Merge branch 'develop' into pycsdr
33
CHANGELOG.md
@ -1,14 +1,39 @@
|
||||
**unreleased**
|
||||
**1.1.x - unreleased**
|
||||
- Reworked most graphical elements as SVGs for faster loadtimes and crispier display on hi-dpi displays
|
||||
- Updated pipelines to match changes in digiham
|
||||
- Changed D-Star and NXDN integrations to use new decoders from digiham
|
||||
- Added D-Star and NXDN metadata display
|
||||
|
||||
**1.0.0**
|
||||
- Introduced `squelch_auto_margin` config option that allows configuring the auto squelch level
|
||||
- Removed `port` configuration option; `rtltcp_compat` takes the port number with the new connectors
|
||||
- Added support for new WSJT-X modes FST4 and FST4W (only available with WSJT-X 2.3)
|
||||
- Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X 2.3) and Q65 (only avilable with
|
||||
WSJT-X 2.4)
|
||||
- Added support for demodulating M17 digital voice signals using m17-cxx-demod
|
||||
- New reporting infrastructure, allowing WSPR and FST4W spots to be sent to wsprnet.org
|
||||
- Add some basic filtering capabilities to the map
|
||||
- New arguments to the `openwebrx` command-line to facilitate the administration of users (try `openwebrx admin`)
|
||||
- Default bandwidth changes:
|
||||
- "WFM" changed to 150kHz
|
||||
- "Packet" (APRS) changed to 12.5kHz
|
||||
- Configuration rework:
|
||||
- New: fully web-based configuration interface
|
||||
- System configuration parameters have been moved to a new, separate `openwebrx.conf` file
|
||||
- Remaining parameters are now editable in the web configuration
|
||||
- Existing `config_webrx.py` files will still be read, but changes made in the web configuration will be written to
|
||||
a new storage system
|
||||
- Added upload of avatar and panorama image via web configuration
|
||||
- New devices supported:
|
||||
- HPSDR devices (Hermes Lite 2)
|
||||
- HPSDR devices (Hermes Lite 2) thanks to @jancona
|
||||
- BBRF103 / RX666 / RX888 devices supported by libsddc
|
||||
- Devices using the EB200 protocol
|
||||
- R&S devices using the EB200 or Ammos protocols
|
||||
|
||||
**0.20.3**
|
||||
- Fix a compatibility issue with python versions <= 3.6
|
||||
|
||||
**0.20.2**
|
||||
- Fix a security problem that allowed arbitrary commands to be executed on the receiver
|
||||
([See github issue #215](https://github.com/jketterl/openwebrx/issues/215))
|
||||
|
||||
**0.20.1**
|
||||
- Remove broken OSM map fallback
|
||||
|
@ -13,8 +13,7 @@ It has the following features:
|
||||
- it works in Google Chrome, Chromium and Mozilla Firefox
|
||||
- supports a wide range of [SDR hardware](https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices)
|
||||
- Multiple SDR devices can be used simultaneously
|
||||
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag)
|
||||
- [dsd](https://github.com/f4exb/dsdcc) based demodulators (D-Star, NXDN)
|
||||
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag, D-Star, NXDN)
|
||||
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
|
||||
FST4W)
|
||||
- [direwolf](https://github.com/wb2osz/direwolf) based demodulation of APRS packets
|
||||
|
150
bands.json
@ -6,7 +6,8 @@
|
||||
"frequencies": {
|
||||
"fst4": 136000,
|
||||
"fst4w": 136000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "630m",
|
||||
@ -15,7 +16,8 @@
|
||||
"frequencies": {
|
||||
"fst4": 474200,
|
||||
"fst4w": 474200
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "160m",
|
||||
@ -30,7 +32,8 @@
|
||||
"js8": 1842000,
|
||||
"fst4": 1839000,
|
||||
"fst4w": 1836800
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "80m",
|
||||
@ -44,7 +47,8 @@
|
||||
"jt9": 3572000,
|
||||
"ft4": [3568000, 3575000],
|
||||
"js8": 3578000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "60m",
|
||||
@ -53,7 +57,8 @@
|
||||
"frequencies": {
|
||||
"ft8": 5357000,
|
||||
"wspr": 5364700
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "40m",
|
||||
@ -67,7 +72,8 @@
|
||||
"jt9": 7078000,
|
||||
"ft4": 7047500,
|
||||
"js8": 7078000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "30m",
|
||||
@ -81,7 +87,8 @@
|
||||
"jt9": 10140000,
|
||||
"ft4": 10140000,
|
||||
"js8": 10130000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "20m",
|
||||
@ -95,7 +102,8 @@
|
||||
"jt9": 14078000,
|
||||
"ft4": 14080000,
|
||||
"js8": 14078000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "17m",
|
||||
@ -109,7 +117,8 @@
|
||||
"jt9": 18104000,
|
||||
"ft4": 18104000,
|
||||
"js8": 18104000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "15m",
|
||||
@ -123,7 +132,8 @@
|
||||
"jt9": 21078000,
|
||||
"ft4": 21140000,
|
||||
"js8": 21078000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "12m",
|
||||
@ -137,7 +147,8 @@
|
||||
"jt9": 24919000,
|
||||
"ft4": 24919000,
|
||||
"js8": 24922000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "10m",
|
||||
@ -151,7 +162,8 @@
|
||||
"jt9": 28078000,
|
||||
"ft4": 28180000,
|
||||
"js8": 28078000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "6m",
|
||||
@ -164,8 +176,10 @@
|
||||
"jt65": 50310000,
|
||||
"jt9": 50312000,
|
||||
"ft4": 50318000,
|
||||
"js8": 50318000
|
||||
}
|
||||
"js8": 50318000,
|
||||
"q65": [50211000, 50275000]
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "4m",
|
||||
@ -173,7 +187,8 @@
|
||||
"upper_bound": 70200000,
|
||||
"frequencies": {
|
||||
"wspr": 70091000
|
||||
}
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "2m",
|
||||
@ -184,110 +199,169 @@
|
||||
"ft8": 144174000,
|
||||
"ft4": 144170000,
|
||||
"jt65": 144120000,
|
||||
"packet": 144800000
|
||||
}
|
||||
"packet": 144800000,
|
||||
"q65": 144116000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "70cm",
|
||||
"lower_bound": 430000000,
|
||||
"upper_bound": 440000000,
|
||||
"frequencies": {
|
||||
"pocsag": 439987500
|
||||
}
|
||||
"pocsag": 439987500,
|
||||
"q65": 432065000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "23cm",
|
||||
"lower_bound": 1240000000,
|
||||
"upper_bound": 1300000000
|
||||
"upper_bound": 1300000000,
|
||||
"frequencies": {
|
||||
"q65": 1296065000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "13cm",
|
||||
"lower_bound": 2320000000,
|
||||
"upper_bound": 2450000000
|
||||
"upper_bound": 2450000000,
|
||||
"frequencies": {
|
||||
"q65": [2301065000, 2304065000, 2320065000]
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "9cm",
|
||||
"lower_bound": 3400000000,
|
||||
"upper_bound": 3475000000
|
||||
"upper_bound": 3475000000,
|
||||
"frequencies": {
|
||||
"q65": 3400065000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "6cm",
|
||||
"lower_bound": 5650000000,
|
||||
"upper_bound": 5850000000
|
||||
"upper_bound": 5850000000,
|
||||
"frequencies": {
|
||||
"q65": 5760200000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "3cm",
|
||||
"lower_bound": 10000000000,
|
||||
"upper_bound": 10500000000
|
||||
"upper_bound": 10500000000,
|
||||
"frequencies": {
|
||||
"q65": 10368200000
|
||||
},
|
||||
"tags": ["hamradio"]
|
||||
},
|
||||
{
|
||||
"name": "120m Broadcast",
|
||||
"lower_bound": 2300000,
|
||||
"upper_bound": 2495000
|
||||
"upper_bound": 2495000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "90m Broadcast",
|
||||
"lower_bound": 3200000,
|
||||
"upper_bound": 3400000
|
||||
"upper_bound": 3400000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "75m Broadcast",
|
||||
"lower_bound": 3900000,
|
||||
"upper_bound": 4000000
|
||||
"upper_bound": 4000000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "60m Broadcast",
|
||||
"lower_bound": 4750000,
|
||||
"upper_bound": 4995000
|
||||
"upper_bound": 4995000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "49m Broadcast",
|
||||
"lower_bound": 5900000,
|
||||
"upper_bound": 6200000
|
||||
"upper_bound": 6200000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "41m Broadcast",
|
||||
"lower_bound": 7200000,
|
||||
"upper_bound": 7450000
|
||||
"upper_bound": 7450000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "31m Broadcast",
|
||||
"lower_bound": 9400000,
|
||||
"upper_bound": 9900000
|
||||
"upper_bound": 9900000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "25m Broadcast",
|
||||
"lower_bound": 11600000,
|
||||
"upper_bound": 12100000
|
||||
"upper_bound": 12100000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "22m Broadcast",
|
||||
"lower_bound": 13570000,
|
||||
"upper_bound": 13870000
|
||||
"upper_bound": 13870000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "19m Broadcast",
|
||||
"lower_bound": 15100000,
|
||||
"upper_bound": 15830000
|
||||
"upper_bound": 15830000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "16m Broadcast",
|
||||
"lower_bound": 17480000,
|
||||
"upper_bound": 17900000
|
||||
"upper_bound": 17900000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "15m Broadcast",
|
||||
"lower_bound": 18900000,
|
||||
"upper_bound": 19020000
|
||||
"upper_bound": 19020000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "13m Broadcast",
|
||||
"lower_bound": 21450000,
|
||||
"upper_bound": 21850000
|
||||
"upper_bound": 21850000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "11m Broadcast",
|
||||
"lower_bound": 25670000,
|
||||
"upper_bound": 26100000
|
||||
"upper_bound": 26100000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "FM Broadcast",
|
||||
"lower_bound": 87500000,
|
||||
"upper_bound": 108000000,
|
||||
"tags": ["broadcast"]
|
||||
},
|
||||
{
|
||||
"name": "11m CB",
|
||||
"lower_bound": 26965000,
|
||||
"upper_bound": 27405000,
|
||||
"frequencies": {
|
||||
"js8": 27245000
|
||||
},
|
||||
"tags": ["public"]
|
||||
},
|
||||
{
|
||||
"name": "PMR446",
|
||||
"lower_bound": 446000000,
|
||||
"upper_bound": 446200000,
|
||||
"tags": ["public"]
|
||||
}
|
||||
]
|
217
bookmarks.json
@ -1,217 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "DB0ZU",
|
||||
"frequency": 145725000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0ZM",
|
||||
"frequency": 145750000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DM0ULR",
|
||||
"frequency": 145787500,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0EL",
|
||||
"frequency": 439275000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0NJ",
|
||||
"frequency": 438775000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0NJ",
|
||||
"frequency": 439437500,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0UFO",
|
||||
"frequency": 438312500,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0PV",
|
||||
"frequency": 438525000,
|
||||
"modulation": "ysf"
|
||||
},
|
||||
{
|
||||
"name": "DB0BZA",
|
||||
"frequency": 438412500,
|
||||
"modulation": "ysf"
|
||||
},
|
||||
{
|
||||
"name": "DB0OSH",
|
||||
"frequency": 438250000,
|
||||
"modulation": "ysf"
|
||||
},
|
||||
{
|
||||
"name": "DB0ULR",
|
||||
"frequency": 439325000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0ZU",
|
||||
"frequency": 438850000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0ISW",
|
||||
"frequency": 438650000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "Radio DARC",
|
||||
"frequency": 6070000,
|
||||
"modulation": "am"
|
||||
},
|
||||
{
|
||||
"name": "DB0TVM",
|
||||
"frequency": 439575000,
|
||||
"modulation": "dstar"
|
||||
},
|
||||
{
|
||||
"name": "DB0TVM",
|
||||
"frequency": 439800000,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0TR",
|
||||
"frequency": 438700000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0PME",
|
||||
"frequency": 439825000,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0HKN",
|
||||
"frequency": 438300000,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "OE2XHM",
|
||||
"frequency": 438825000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DM0WW",
|
||||
"frequency": 438962500,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "OE7XXR",
|
||||
"frequency": 438200000,
|
||||
"modulation": "dstar"
|
||||
},
|
||||
{
|
||||
"name": "OE2XZR",
|
||||
"frequency": 439000000,
|
||||
"modulation": "dstar"
|
||||
},
|
||||
{
|
||||
"name": "DB0OAL",
|
||||
"frequency": 439912500,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0AAT",
|
||||
"frequency": 439550000,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0FSG",
|
||||
"frequency": 439937500,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0ULR",
|
||||
"frequency": 145575000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0RDH",
|
||||
"frequency": 145737500,
|
||||
"modulation": "dstar"
|
||||
},
|
||||
{
|
||||
"name": "DM0GAP",
|
||||
"frequency": 145612500,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0XF",
|
||||
"frequency": 145600000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0TOL",
|
||||
"frequency": 145712500,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0TTB",
|
||||
"frequency": 439587500,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0TRS",
|
||||
"frequency": 439125000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0OAL",
|
||||
"frequency": 438937500,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DM0ULR",
|
||||
"frequency": 439337500,
|
||||
"modulation": "nxdn"
|
||||
},
|
||||
{
|
||||
"name": "DB0MIR",
|
||||
"frequency": 439300000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0PM",
|
||||
"frequency": 439075000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0CP",
|
||||
"frequency": 439025000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "OE7XGR",
|
||||
"frequency": 438925000,
|
||||
"modulation": "dmr"
|
||||
},
|
||||
{
|
||||
"name": "DB0TOL",
|
||||
"frequency": 438725000,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0OAL",
|
||||
"frequency": 438325000,
|
||||
"modulation": "dstar"
|
||||
},
|
||||
{
|
||||
"name": "DB0ROL",
|
||||
"frequency": 439237500,
|
||||
"modulation": "nfm"
|
||||
},
|
||||
{
|
||||
"name": "DB0ABX",
|
||||
"frequency": 439137500,
|
||||
"modulation": "nfm"
|
||||
}
|
||||
]
|
417
config_webrx.py
@ -32,32 +32,45 @@ config_webrx: configuration options for OpenWebRX
|
||||
and use them for running your web service with OpenWebRX.)
|
||||
"""
|
||||
|
||||
"""
|
||||
DEPRECATION notice
|
||||
|
||||
As of OpenWebRX 0.21, the configuration system has been completely overhauled.
|
||||
The configuration of OpenWebRX should now be done in the new web-based
|
||||
configuration interface exclusively.
|
||||
|
||||
Existing configurations can still be used, but their values will be migrated
|
||||
to the new storage infrastructure as soon as the web configuration is used to
|
||||
edit them.
|
||||
|
||||
The new configuration storage is not intended to be edited manually.
|
||||
"""
|
||||
|
||||
# configuration version. please only modify if you're able to perform the associated migration steps.
|
||||
version = 3
|
||||
version = 7
|
||||
|
||||
# NOTE: you can find additional information about configuring OpenWebRX in the Wiki:
|
||||
# https://github.com/jketterl/openwebrx/wiki/Configuration-guide
|
||||
|
||||
# ==== Server settings ====
|
||||
web_port = 8073
|
||||
max_clients = 20
|
||||
#max_clients = 20
|
||||
|
||||
# ==== Web GUI configuration ====
|
||||
receiver_name = "[Callsign]"
|
||||
receiver_location = "Budapest, Hungary"
|
||||
receiver_asl = 200
|
||||
receiver_admin = "example@example.com"
|
||||
receiver_gps = {"lat": 47.000000, "lon": 19.000000}
|
||||
photo_title = "Panorama of Budapest from Schönherz Zoltán Dormitory"
|
||||
#receiver_name = "[Callsign]"
|
||||
#receiver_location = "Budapest, Hungary"
|
||||
#receiver_asl = 200
|
||||
#receiver_admin = "example@example.com"
|
||||
#receiver_gps = {"lat": 47.000000, "lon": 19.000000}
|
||||
#photo_title = "Panorama of Budapest from Schönherz Zoltán Dormitory"
|
||||
# photo_desc allows you to put pretty much any HTML you like into the receiver description.
|
||||
# The lines below should give you some examples of what's possible.
|
||||
photo_desc = """
|
||||
You can add your own background photo and receiver information.<br />
|
||||
Receiver is operated by: <a href="mailto:openwebrx@localhost" target="_blank">Receiver Operator</a><br/>
|
||||
Device: Receiver Device<br />
|
||||
Antenna: Receiver Antenna<br />
|
||||
Website: <a href="http://localhost" target="_blank">http://localhost</a>
|
||||
"""
|
||||
#photo_desc = """
|
||||
#You can add your own background photo and receiver information.<br />
|
||||
#Receiver is operated by: <a href="mailto:openwebrx@localhost" target="_blank">Receiver Operator</a><br/>
|
||||
#Device: Receiver Device<br />
|
||||
#Antenna: Receiver Antenna<br />
|
||||
#Website: <a href="http://localhost" target="_blank">http://localhost</a>
|
||||
#"""
|
||||
|
||||
# ==== Public receiver listings ====
|
||||
# You can publish your receiver on online receiver directories, like https://www.receiverbook.de
|
||||
@ -65,7 +78,7 @@ Website: <a href="http://localhost" target="_blank">http://localhost</a>
|
||||
# Please note that you not share your receiver keys publicly since anyone that obtains your receiver key can take over
|
||||
# your public listing.
|
||||
# Your receiver keys should be placed into this array:
|
||||
receiver_keys = []
|
||||
#receiver_keys = []
|
||||
# If you list your receiver on multiple sites, you can place all your keys into the array above, or you can append
|
||||
# keys to the arraylike this:
|
||||
# receiver_keys += ["my-receiver-key"]
|
||||
@ -73,30 +86,29 @@ receiver_keys = []
|
||||
# If you're not sure, simply copy & paste the code you received from your listing site below this line:
|
||||
|
||||
# ==== DSP/RX settings ====
|
||||
fft_fps = 9
|
||||
fft_size = 4096 # Should be power of 2
|
||||
fft_voverlap_factor = (
|
||||
0.3 # If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram.
|
||||
)
|
||||
#fft_fps = 9
|
||||
#fft_size = 4096 # Should be power of 2
|
||||
#fft_voverlap_factor = (
|
||||
# 0.3 # If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram.
|
||||
#)
|
||||
|
||||
audio_compression = "adpcm" # valid values: "adpcm", "none"
|
||||
fft_compression = "adpcm" # valid values: "adpcm", "none"
|
||||
#audio_compression = "adpcm" # valid values: "adpcm", "none"
|
||||
#fft_compression = "adpcm" # valid values: "adpcm", "none"
|
||||
|
||||
# Tau setting for WFM (broadcast FM) deemphasis\
|
||||
# Quote from wikipedia https://en.wikipedia.org/wiki/FM_broadcasting#Pre-emphasis_and_de-emphasis
|
||||
# "In most of the world a 50 µs time constant is used. In the Americas and South Korea, 75 µs is used"
|
||||
# Enable one of the following lines, depending on your location:
|
||||
# wfm_deemphasis_tau = 75e-6 # for US and South Korea
|
||||
wfm_deemphasis_tau = 50e-6 # for the rest of the world
|
||||
#wfm_deemphasis_tau = 50e-6 # for the rest of the world
|
||||
|
||||
digimodes_enable = True # Decoding digimodes come with higher CPU usage.
|
||||
digimodes_fft_size = 2048
|
||||
#digimodes_fft_size = 2048
|
||||
|
||||
# determines the quality, and thus the cpu usage, for the ambe codec used by digital voice modes
|
||||
# if you're running on a Raspi (up to 3B+) you'll want to leave this on 1
|
||||
digital_voice_unvoiced_quality = 1
|
||||
#digital_voice_unvoiced_quality = 1
|
||||
# enables lookup of DMR ids using the radioid api
|
||||
digital_voice_dmr_id_lookup = True
|
||||
#digital_voice_dmr_id_lookup = True
|
||||
|
||||
"""
|
||||
Note: if you experience audio underruns while CPU usage is 100%, you can:
|
||||
@ -116,232 +128,230 @@ Note: if you experience audio underruns while CPU usage is 100%, you can:
|
||||
|
||||
# Currently supported types of sdr receivers:
|
||||
# "rtl_sdr", "rtl_sdr_soapy", "sdrplay", "hackrf", "airspy", "airspyhf", "fifi_sdr",
|
||||
# "perseussdr", "lime_sdr", "pluto_sdr", "soapy_remote", "hpsdr", "red_pitaya", "uhd",
|
||||
# "radioberry", "fcdpp", "rtl_tcp", "sddc", "eb200"
|
||||
# "perseussdr", "lime_sdr", "pluto_sdr", "soapy_remote", "hpsdr", "uhd",
|
||||
# "radioberry", "fcdpp", "rtl_tcp", "sddc", "runds"
|
||||
|
||||
# For more details on specific types, please checkout the wiki:
|
||||
# https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices
|
||||
|
||||
sdrs = {
|
||||
"rtlsdr": {
|
||||
"name": "RTL-SDR USB Stick",
|
||||
"type": "rtl_sdr",
|
||||
"ppm": 0,
|
||||
# you can change this if you use an upconverter. formula is:
|
||||
# center_freq + lfo_offset = actual frequency on the sdr
|
||||
# "lfo_offset": 0,
|
||||
"profiles": {
|
||||
"70cm": {
|
||||
"name": "70cm Relais",
|
||||
"center_freq": 438800000,
|
||||
"rf_gain": 29,
|
||||
"samp_rate": 2400000,
|
||||
"start_freq": 439275000,
|
||||
"start_mod": "nfm",
|
||||
},
|
||||
"2m": {
|
||||
"name": "2m komplett",
|
||||
"center_freq": 145000000,
|
||||
"rf_gain": 29,
|
||||
"samp_rate": 2048000,
|
||||
"start_freq": 145725000,
|
||||
"start_mod": "nfm",
|
||||
},
|
||||
},
|
||||
},
|
||||
"airspy": {
|
||||
"name": "Airspy HF+",
|
||||
"type": "airspyhf",
|
||||
"ppm": 0,
|
||||
"rf_gain": "auto",
|
||||
"profiles": {
|
||||
"20m": {
|
||||
"name": "20m",
|
||||
"center_freq": 14150000,
|
||||
"samp_rate": 384000,
|
||||
"start_freq": 14070000,
|
||||
"start_mod": "usb",
|
||||
},
|
||||
"30m": {
|
||||
"name": "30m",
|
||||
"center_freq": 10125000,
|
||||
"samp_rate": 192000,
|
||||
"start_freq": 10142000,
|
||||
"start_mod": "usb",
|
||||
},
|
||||
"40m": {
|
||||
"name": "40m",
|
||||
"center_freq": 7100000,
|
||||
"samp_rate": 256000,
|
||||
"start_freq": 7070000,
|
||||
"start_mod": "lsb",
|
||||
},
|
||||
"80m": {
|
||||
"name": "80m",
|
||||
"center_freq": 3650000,
|
||||
"samp_rate": 384000,
|
||||
"start_freq": 3570000,
|
||||
"start_mod": "lsb",
|
||||
},
|
||||
"49m": {
|
||||
"name": "49m Broadcast",
|
||||
"center_freq": 6050000,
|
||||
"samp_rate": 384000,
|
||||
"start_freq": 6070000,
|
||||
"start_mod": "am",
|
||||
},
|
||||
},
|
||||
},
|
||||
"sdrplay": {
|
||||
"name": "SDRPlay RSP2",
|
||||
"type": "sdrplay",
|
||||
"ppm": 0,
|
||||
"antenna": "Antenna A",
|
||||
"profiles": {
|
||||
"20m": {
|
||||
"name": "20m",
|
||||
"center_freq": 14150000,
|
||||
"rf_gain": 0,
|
||||
"samp_rate": 500000,
|
||||
"start_freq": 14070000,
|
||||
"start_mod": "usb",
|
||||
},
|
||||
"30m": {
|
||||
"name": "30m",
|
||||
"center_freq": 10125000,
|
||||
"rf_gain": 0,
|
||||
"samp_rate": 250000,
|
||||
"start_freq": 10142000,
|
||||
"start_mod": "usb",
|
||||
},
|
||||
"40m": {
|
||||
"name": "40m",
|
||||
"center_freq": 7100000,
|
||||
"rf_gain": 0,
|
||||
"samp_rate": 500000,
|
||||
"start_freq": 7070000,
|
||||
"start_mod": "lsb",
|
||||
},
|
||||
"80m": {
|
||||
"name": "80m",
|
||||
"center_freq": 3650000,
|
||||
"rf_gain": 0,
|
||||
"samp_rate": 500000,
|
||||
"start_freq": 3570000,
|
||||
"start_mod": "lsb",
|
||||
},
|
||||
"49m": {
|
||||
"name": "49m Broadcast",
|
||||
"center_freq": 6000000,
|
||||
"rf_gain": 0,
|
||||
"samp_rate": 500000,
|
||||
"start_freq": 6070000,
|
||||
"start_mod": "am",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
#sdrs = {
|
||||
# "rtlsdr": {
|
||||
# "name": "RTL-SDR USB Stick",
|
||||
# "type": "rtl_sdr",
|
||||
# "ppm": 0,
|
||||
# # you can change this if you use an upconverter. formula is:
|
||||
# # center_freq + lfo_offset = actual frequency on the sdr
|
||||
# # "lfo_offset": 0,
|
||||
# "profiles": {
|
||||
# "70cm": {
|
||||
# "name": "70cm Relais",
|
||||
# "center_freq": 438800000,
|
||||
# "rf_gain": 29,
|
||||
# "samp_rate": 2400000,
|
||||
# "start_freq": 439275000,
|
||||
# "start_mod": "nfm",
|
||||
# },
|
||||
# "2m": {
|
||||
# "name": "2m komplett",
|
||||
# "center_freq": 145000000,
|
||||
# "rf_gain": 29,
|
||||
# "samp_rate": 2048000,
|
||||
# "start_freq": 145725000,
|
||||
# "start_mod": "nfm",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
# "airspy": {
|
||||
# "name": "Airspy HF+",
|
||||
# "type": "airspyhf",
|
||||
# "ppm": 0,
|
||||
# "rf_gain": "auto",
|
||||
# "profiles": {
|
||||
# "20m": {
|
||||
# "name": "20m",
|
||||
# "center_freq": 14150000,
|
||||
# "samp_rate": 384000,
|
||||
# "start_freq": 14070000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "30m": {
|
||||
# "name": "30m",
|
||||
# "center_freq": 10125000,
|
||||
# "samp_rate": 192000,
|
||||
# "start_freq": 10142000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "40m": {
|
||||
# "name": "40m",
|
||||
# "center_freq": 7100000,
|
||||
# "samp_rate": 256000,
|
||||
# "start_freq": 7070000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "80m": {
|
||||
# "name": "80m",
|
||||
# "center_freq": 3650000,
|
||||
# "samp_rate": 384000,
|
||||
# "start_freq": 3570000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "49m": {
|
||||
# "name": "49m Broadcast",
|
||||
# "center_freq": 6050000,
|
||||
# "samp_rate": 384000,
|
||||
# "start_freq": 6070000,
|
||||
# "start_mod": "am",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
# "sdrplay": {
|
||||
# "name": "SDRPlay RSP2",
|
||||
# "type": "sdrplay",
|
||||
# "ppm": 0,
|
||||
# "antenna": "Antenna A",
|
||||
# "profiles": {
|
||||
# "20m": {
|
||||
# "name": "20m",
|
||||
# "center_freq": 14150000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 14070000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "30m": {
|
||||
# "name": "30m",
|
||||
# "center_freq": 10125000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 250000,
|
||||
# "start_freq": 10142000,
|
||||
# "start_mod": "usb",
|
||||
# },
|
||||
# "40m": {
|
||||
# "name": "40m",
|
||||
# "center_freq": 7100000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 7070000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "80m": {
|
||||
# "name": "80m",
|
||||
# "center_freq": 3650000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 3570000,
|
||||
# "start_mod": "lsb",
|
||||
# },
|
||||
# "49m": {
|
||||
# "name": "49m Broadcast",
|
||||
# "center_freq": 6000000,
|
||||
# "rf_gain": 0,
|
||||
# "samp_rate": 500000,
|
||||
# "start_freq": 6070000,
|
||||
# "start_mod": "am",
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
#}
|
||||
|
||||
# ==== Color themes ====
|
||||
|
||||
### google turbo colormap (see: https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html)
|
||||
waterfall_colors = [0x30123b, 0x311542, 0x33184a, 0x341b51, 0x351e58, 0x36215f, 0x372466, 0x38266c, 0x392973, 0x3a2c79, 0x3b2f80, 0x3c3286, 0x3d358b, 0x3e3891, 0x3e3a97, 0x3f3d9c, 0x4040a2, 0x4043a7, 0x4146ac, 0x4248b1, 0x424bb6, 0x434eba, 0x4351bf, 0x4453c3, 0x4456c7, 0x4559cb, 0x455bcf, 0x455ed3, 0x4561d7, 0x4663da, 0x4666dd, 0x4669e1, 0x466be4, 0x466ee7, 0x4671e9, 0x4673ec, 0x4676ee, 0x4678f1, 0x467bf3, 0x467df5, 0x4680f7, 0x4682f9, 0x4685fa, 0x4587fc, 0x458afd, 0x448cfe, 0x448ffe, 0x4391ff, 0x4294ff, 0x4196ff, 0x3f99ff, 0x3e9bff, 0x3d9efe, 0x3ba1fd, 0x3aa3fd, 0x38a6fb, 0x36a8fa, 0x35abf9, 0x33adf7, 0x31b0f6, 0x2fb2f4, 0x2db5f2, 0x2cb7f0, 0x2ab9ee, 0x28bcec, 0x26beea, 0x25c0e7, 0x23c3e5, 0x21c5e2, 0x20c7e0, 0x1fc9dd, 0x1dccdb, 0x1cced8, 0x1bd0d5, 0x1ad2d3, 0x19d4d0, 0x18d6cd, 0x18d8cb, 0x18dac8, 0x17dbc5, 0x17ddc3, 0x17dfc0, 0x18e0be, 0x18e2bb, 0x19e3b9, 0x1ae5b7, 0x1be6b4, 0x1de8b2, 0x1ee9af, 0x20eaad, 0x22ecaa, 0x24eda7, 0x27eea4, 0x29efa1, 0x2cf09e, 0x2ff19b, 0x32f298, 0x35f394, 0x38f491, 0x3cf58e, 0x3ff68b, 0x43f787, 0x46f884, 0x4af980, 0x4efa7d, 0x51fa79, 0x55fb76, 0x59fc73, 0x5dfc6f, 0x61fd6c, 0x65fd69, 0x69fe65, 0x6dfe62, 0x71fe5f, 0x75ff5c, 0x79ff59, 0x7dff56, 0x80ff53, 0x84ff50, 0x88ff4e, 0x8bff4b, 0x8fff49, 0x92ff46, 0x96ff44, 0x99ff42, 0x9cfe40, 0x9ffe3e, 0xa2fd3d, 0xa4fd3b, 0xa7fc3a, 0xaafc39, 0xacfb38, 0xaffa37, 0xb1f936, 0xb4f835, 0xb7f835, 0xb9f634, 0xbcf534, 0xbff434, 0xc1f334, 0xc4f233, 0xc6f033, 0xc9ef34, 0xcbee34, 0xceec34, 0xd0eb34, 0xd2e934, 0xd5e835, 0xd7e635, 0xd9e435, 0xdbe236, 0xdde136, 0xe0df37, 0xe2dd37, 0xe4db38, 0xe6d938, 0xe7d738, 0xe9d539, 0xebd339, 0xedd139, 0xeecf3a, 0xf0cd3a, 0xf1cb3a, 0xf3c93a, 0xf4c73a, 0xf5c53a, 0xf7c33a, 0xf8c13a, 0xf9bf39, 0xfabd39, 0xfaba38, 0xfbb838, 0xfcb637, 0xfcb436, 0xfdb135, 0xfdaf35, 0xfeac34, 0xfea933, 0xfea732, 0xfea431, 0xffa12f, 0xff9e2e, 0xff9c2d, 0xff992c, 0xfe962b, 0xfe932a, 0xfe9028, 0xfe8d27, 0xfd8a26, 0xfd8724, 0xfc8423, 0xfc8122, 0xfb7e20, 0xfb7b1f, 0xfa781e, 0xf9751c, 0xf8721b, 0xf86f1a, 0xf76c19, 0xf66917, 0xf56616, 0xf46315, 0xf36014, 0xf25d13, 0xf05b11, 0xef5810, 0xee550f, 0xed530e, 0xeb500e, 0xea4e0d, 0xe94b0c, 0xe7490b, 0xe6470a, 0xe4450a, 0xe34209, 0xe14009, 0xdf3e08, 0xde3c07, 0xdc3a07, 0xda3806, 0xd83606, 0xd63405, 0xd43205, 0xd23105, 0xd02f04, 0xce2d04, 0xcc2b03, 0xca2903, 0xc82803, 0xc62602, 0xc32402, 0xc12302, 0xbf2102, 0xbc1f01, 0xba1e01, 0xb71c01, 0xb41b01, 0xb21901, 0xaf1801, 0xac1601, 0xaa1501, 0xa71401, 0xa41201, 0xa11101, 0x9e1001, 0x9b0f01, 0x980d01, 0x950c01, 0x920b01, 0x8e0a01, 0x8b0901, 0x880801, 0x850701, 0x810602, 0x7e0502, 0x7a0402]
|
||||
#waterfall_scheme = "GoogleTurboWaterfall"
|
||||
|
||||
### original theme by teejez:
|
||||
#waterfall_colors = [0x000000, 0x0000FF, 0x00FFFF, 0x00FF00, 0xFFFF00, 0xFF0000, 0xFF00FF, 0xFFFFFF]
|
||||
#waterfall_scheme = "TeejeezWaterfall"
|
||||
|
||||
### old theme by HA7ILM:
|
||||
#waterfall_colors = [0x000000, 0x2e6893, 0x69a5d0, 0x214b69, 0x9dc4e0, 0xfff775, 0xff8a8a, 0xb20000]
|
||||
# waterfall_min_level = -115 #in dB
|
||||
# waterfall_max_level = 0
|
||||
# waterfall_auto_level_margin = {"min": 20, "max": 30}
|
||||
#waterfall_scheme = "Ha7ilmWaterfall"
|
||||
##For the old colors, you might also want to set [fft_voverlap_factor] to 0.
|
||||
|
||||
waterfall_min_level = -88 # in dB
|
||||
waterfall_max_level = -20
|
||||
waterfall_auto_level_margin = {"min": 3, "max": 10, "min_range": 50}
|
||||
### custom waterfall schemes can be configured like this:
|
||||
#waterfall_scheme = "CustomWaterfall"
|
||||
#waterfall_colors = [0x0000FF, 0x00FF00, 0xFF0000]
|
||||
|
||||
### Waterfall calibration
|
||||
#waterfall_levels = {"min": -88, "max": -20} # in dB
|
||||
|
||||
#waterfall_auto_levels = {"min": 3, "max": 10}
|
||||
#waterfall_auto_min_range = 50
|
||||
|
||||
# Note: When the auto waterfall level button is clicked, the following happens:
|
||||
# [waterfall_min_level] = [current_min_power_level] - [waterfall_auto_level_margin["min"]]
|
||||
# [waterfall_max_level] = [current_max_power_level] + [waterfall_auto_level_margin["max"]]
|
||||
# [waterfall_levels.min] = [current_min_power_level] - [waterfall_auto_levels["min"]]
|
||||
# [waterfall_levels.max] = [current_max_power_level] + [waterfall_auto_levels["max"]]
|
||||
#
|
||||
# ___|________________________________________|____________________________________|________________________________________|___> signal power
|
||||
# \_waterfall_auto_level_margin["min"]_/ |__ current_min_power_level | \_waterfall_auto_level_margin["max"]_/
|
||||
# current_max_power_level __|
|
||||
# ___|__________________________________|____________________________________|__________________________________|___> signal power
|
||||
# \_waterfall_auto_levels["min"]_/ |__ current_min_power_level | \_waterfall_auto_levels["max"]_/
|
||||
# current_max_power_level __|
|
||||
|
||||
# This setting allows you to modify the precision of the frequency displays in OpenWebRX.
|
||||
# Set this to the number of digits you would like to see:
|
||||
frequency_display_precision = 4
|
||||
# Set this to exponent of 10 to select the most precise digit in Hz you'd like to see
|
||||
# examples:
|
||||
# a value of 2 selects 10^2 = 100Hz tuning precision (default):
|
||||
#tuning_precision = 2
|
||||
# a value of 1 selects 10^1 = 10Hz tuning precision:
|
||||
#tuning_precision = 1
|
||||
|
||||
# This setting tells the auto-squelch the offset to add to the current signal level to use as the new squelch level.
|
||||
# Lowering this setting will give you a more sensitive squelch, but it may also cause unwanted squelch openings when
|
||||
# using the auto squelch.
|
||||
squelch_auto_margin = 10 # in dB
|
||||
#squelch_auto_margin = 10 # in dB
|
||||
|
||||
# === Experimental settings ===
|
||||
# Warning! The settings below are very experimental.
|
||||
csdr_dynamic_bufsize = False # This allows you to change the buffering mode of csdr.
|
||||
csdr_print_bufsizes = False # This prints the buffer sizes used for csdr processes.
|
||||
csdr_through = False # Setting this True will print out how much data is going into the DSP chains.
|
||||
|
||||
nmux_memory = 50 # in megabytes. This sets the approximate size of the circular buffer used by nmux.
|
||||
|
||||
google_maps_api_key = ""
|
||||
#google_maps_api_key = ""
|
||||
|
||||
# how long should positions be visible on the map?
|
||||
# they will start fading out after half of that
|
||||
# in seconds; default: 2 hours
|
||||
map_position_retention_time = 2 * 60 * 60
|
||||
#map_position_retention_time = 2 * 60 * 60
|
||||
|
||||
# decoder queue configuration
|
||||
# due to the nature of some operating modes (ft8, ft8, jt9, jt65, wspr and js8), the data is recorded for a given amount
|
||||
# of time (6 seconds up to 2 minutes) and decoded at the end. this can lead to very high peak loads.
|
||||
# to mitigate this, the recordings will be queued and processed in sequence.
|
||||
# the number of workers will limit the total amount of work (one worker will losely occupy one cpu / thread)
|
||||
decoding_queue_workers = 2
|
||||
#decoding_queue_workers = 2
|
||||
# the maximum queue length will cause decodes to be dumped if the workers cannot keep up
|
||||
# if you are running background services, make sure this number is high enough to accept the task influx during peaks
|
||||
# i.e. this should be higher than the number of decoding services running at the same time
|
||||
decoding_queue_length = 10
|
||||
#decoding_queue_length = 10
|
||||
|
||||
# wsjt decoding depth will allow more results, but will also consume more cpu
|
||||
wsjt_decoding_depth = 3
|
||||
#wsjt_decoding_depth = 3
|
||||
# can also be set for each mode separately
|
||||
# jt65 seems to be somewhat prone to erroneous decodes, this setting handles that to some extent
|
||||
wsjt_decoding_depths = {"jt65": 1}
|
||||
#wsjt_decoding_depths = {"jt65": 1}
|
||||
|
||||
# FST4 can be transmitted in different intervals. This setting determines which intervals will be decoded.
|
||||
# available values (in seconds): 15, 30, 60, 120, 300, 900, 1800
|
||||
fst4_enabled_intervals = [15, 30]
|
||||
#fst4_enabled_intervals = [15, 30]
|
||||
|
||||
# FST4W can be transmitted in different intervals. This setting determines which intervals will be decoded.
|
||||
# available values (in seconds): 120, 300, 900, 1800
|
||||
fst4w_enabled_intervals = [120, 300]
|
||||
#fst4w_enabled_intervals = [120, 300]
|
||||
|
||||
# Q65 allows many combinations of intervals and submodes. This setting determines which combinations will be decoded.
|
||||
# Please use the mode letter followed by the decode interval in seconds to specify the combinations. For example:
|
||||
#q65_enabled_combinations = ["A30", "E120", "C60"]
|
||||
|
||||
# JS8 comes in different speeds: normal, slow, fast, turbo. This setting controls which ones are enabled.
|
||||
js8_enabled_profiles = ["normal", "slow"]
|
||||
#js8_enabled_profiles = ["normal", "slow"]
|
||||
# JS8 decoding depth; higher value will get more results, but will also consume more cpu
|
||||
js8_decoding_depth = 3
|
||||
|
||||
temporary_directory = "/tmp"
|
||||
#js8_decoding_depth = 3
|
||||
|
||||
# Enable background service for decoding digital data. You can find more information at:
|
||||
# https://github.com/jketterl/openwebrx/wiki/Background-decoding
|
||||
services_enabled = False
|
||||
services_decoders = ["ft8", "ft4", "wspr", "packet"]
|
||||
#services_enabled = False
|
||||
#services_decoders = ["ft8", "ft4", "wspr", "packet"]
|
||||
|
||||
# === aprs igate settings ===
|
||||
# If you want to share your APRS decodes with the aprs network, configure these settings accordingly.
|
||||
# Make sure that you have set services_enabled to true and customize services_decoders to your needs.
|
||||
aprs_callsign = "N0CALL"
|
||||
aprs_igate_enabled = False
|
||||
aprs_igate_server = "euro.aprs2.net"
|
||||
aprs_igate_password = ""
|
||||
#aprs_callsign = "N0CALL"
|
||||
#aprs_igate_enabled = False
|
||||
#aprs_igate_server = "euro.aprs2.net"
|
||||
#aprs_igate_password = ""
|
||||
# beacon uses the receiver_gps setting, so if you enable this, make sure the location is correct there
|
||||
aprs_igate_beacon = False
|
||||
|
||||
# path to the aprs symbols repository (get it here: https://github.com/hessu/aprs-symbols)
|
||||
aprs_symbols_path = "/usr/share/aprs-symbols/png"
|
||||
#aprs_igate_beacon = False
|
||||
|
||||
# Uncomment the following to customize gateway beacon details reported to the aprs network
|
||||
# Plese see Dire Wolf's documentation on PBEACON configuration for complete details:
|
||||
@ -367,18 +377,13 @@ aprs_symbols_path = "/usr/share/aprs-symbols/png"
|
||||
# === PSK Reporter settings ===
|
||||
# enable this if you want to upload all ft8, ft4 etc spots to pskreporter.info
|
||||
# this also uses the receiver_gps setting from above, so make sure it contains a correct locator
|
||||
pskreporter_enabled = False
|
||||
pskreporter_callsign = "N0CALL"
|
||||
#pskreporter_enabled = False
|
||||
#pskreporter_callsign = "N0CALL"
|
||||
# optional antenna information, uncomment to enable
|
||||
#pskreporter_antenna_information = "Dipole"
|
||||
|
||||
# === WSPRNet reporting settings
|
||||
# enable this if you want to upload WSPR spots to wsprnet.ort
|
||||
# in addition to these settings also make sure that receiver_gps contains your correct location
|
||||
wsprnet_enabled = False
|
||||
wsprnet_callsign = "N0CALL"
|
||||
|
||||
# === Web admin settings ===
|
||||
# this feature is experimental at the moment. it should not be enabled on shared receivers since it allows remote
|
||||
# changes to the receiver settings. enable for testing in controlled environment only.
|
||||
# webadmin_enabled = False
|
||||
#wsprnet_enabled = False
|
||||
#wsprnet_callsign = "N0CALL"
|
||||
|
@ -28,10 +28,10 @@ import threading
|
||||
import math
|
||||
from functools import partial
|
||||
|
||||
from owrx.kiss import KissClient, DirewolfConfig
|
||||
from owrx.wsjt import Ft8Profile, WsprProfile, Jt9Profile, Jt65Profile, Ft4Profile, Fst4Profile, Fst4wProfile
|
||||
from owrx.js8 import Js8Profiles
|
||||
from owrx.audio import AudioChopper
|
||||
from csdr.output import Output
|
||||
|
||||
from owrx.kiss import KissClient, DirewolfConfig, DirewolfConfigSubscriber
|
||||
from owrx.audio.chopper import AudioChopper
|
||||
|
||||
from csdr.pipe import Pipe
|
||||
|
||||
@ -40,40 +40,8 @@ import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class output(object):
|
||||
def send_output(self, t, read_fn):
|
||||
if not self.supports_type(t):
|
||||
# TODO rewrite the output mechanism in a way that avoids producing unnecessary data
|
||||
logger.warning("dumping output of type %s since it is not supported.", t)
|
||||
threading.Thread(target=self.pump(read_fn, lambda x: None), name="csdr_pump_thread").start()
|
||||
return
|
||||
self.receive_output(t, read_fn)
|
||||
|
||||
def receive_output(self, t, read_fn):
|
||||
pass
|
||||
|
||||
def pump(self, read, write):
|
||||
def copy():
|
||||
run = True
|
||||
while run:
|
||||
data = None
|
||||
try:
|
||||
data = read()
|
||||
except ValueError:
|
||||
pass
|
||||
if data is None or (isinstance(data, bytes) and len(data) == 0):
|
||||
run = False
|
||||
else:
|
||||
write(data)
|
||||
|
||||
return copy
|
||||
|
||||
def supports_type(self, t):
|
||||
return True
|
||||
|
||||
|
||||
class dsp(object):
|
||||
def __init__(self, output):
|
||||
class Dsp(DirewolfConfigSubscriber):
|
||||
def __init__(self, output: Output):
|
||||
self.pycsdr_enabled = True
|
||||
self.pycsdr_chain = None
|
||||
self.buffer = None
|
||||
@ -98,9 +66,6 @@ class dsp(object):
|
||||
self.decimation = None
|
||||
self.last_decimation = None
|
||||
self.nc_port = None
|
||||
self.csdr_dynamic_bufsize = False
|
||||
self.csdr_print_bufsizes = False
|
||||
self.csdr_through = False
|
||||
self.squelch_level = -150
|
||||
self.fft_averages = 50
|
||||
self.wfm_deemphasis_tau = 50e-6
|
||||
@ -124,6 +89,7 @@ class dsp(object):
|
||||
self.secondary_pipe_names = {"secondary_shift_pipe": Pipe.WRITE}
|
||||
self.secondary_offset_freq = 1000
|
||||
self.unvoiced_quality = 1
|
||||
self.codecserver = None
|
||||
self.modification_lock = threading.Lock()
|
||||
self.output = output
|
||||
|
||||
@ -133,7 +99,7 @@ class dsp(object):
|
||||
|
||||
self.is_service = False
|
||||
self.direwolf_config = None
|
||||
self.direwolf_port = None
|
||||
self.direwolf_config_path = None
|
||||
self.process = None
|
||||
|
||||
def setBuffer(self, buffer):
|
||||
@ -150,10 +116,6 @@ class dsp(object):
|
||||
|
||||
def chain(self, which):
|
||||
chain = ["nc -v 127.0.0.1 {nc_port}"]
|
||||
if self.csdr_dynamic_bufsize:
|
||||
chain += ["csdr setbuf {start_bufsize}"]
|
||||
if self.csdr_through:
|
||||
chain += ["csdr through"]
|
||||
chain += ["csdr shift_addfast_cc --fifo {shift_pipe}"]
|
||||
if self.decimation > 1:
|
||||
chain += ["csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING"]
|
||||
@ -199,43 +161,43 @@ class dsp(object):
|
||||
elif self.isDigitalVoice(which):
|
||||
chain += ["csdr fmdemod_quadri_cf"]
|
||||
chain += last_decimation_block
|
||||
# dsd modes
|
||||
if which in ["dstar", "nxdn"]:
|
||||
chain += ["dc_block", "csdr limit_ff", "csdr convert_f_s16"]
|
||||
if which == "dstar":
|
||||
chain += ["dsd -fd -i - -o - -u {unvoiced_quality} -g -1 "]
|
||||
elif which == "nxdn":
|
||||
chain += ["dsd -fi -i - -o - -u {unvoiced_quality} -g -1 "]
|
||||
chain += [
|
||||
"digitalvoice_filter",
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
chain += ["dc_block"]
|
||||
# m17
|
||||
elif which == "m17":
|
||||
if which == "m17":
|
||||
chain += [
|
||||
"csdr limit_ff",
|
||||
"csdr convert_f_s16",
|
||||
"m17-demod",
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
# digiham modes
|
||||
else:
|
||||
chain += ["dc_block", "rrc_filter", "gfsk_demodulator"]
|
||||
if which == "dmr":
|
||||
# digiham modes
|
||||
if which == "dstar":
|
||||
chain += [
|
||||
"dmr_decoder --fifo {meta_pipe} --control-fifo {dmr_control_pipe}",
|
||||
"mbe_synthesizer -f -u {unvoiced_quality}",
|
||||
"fsk_demodulator -s 10",
|
||||
"dstar_decoder --fifo {meta_pipe}",
|
||||
"mbe_synthesizer -d {codecserver_arg}",
|
||||
]
|
||||
elif which == "ysf":
|
||||
chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y -f -u {unvoiced_quality}"]
|
||||
max_gain = 0.005
|
||||
chain += [
|
||||
"digitalvoice_filter -f",
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_ff --max 0.005 --initial 0.0005",
|
||||
"sox -t raw -r 8000 -e floating-point -b 32 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif which == "nxdn":
|
||||
chain += [
|
||||
"rrc_filter --narrow",
|
||||
"gfsk_demodulator --samples 20",
|
||||
"nxdn_decoder --fifo {meta_pipe}",
|
||||
"mbe_synthesizer {codecserver_arg}",
|
||||
]
|
||||
else:
|
||||
chain += ["rrc_filter", "gfsk_demodulator"]
|
||||
if which == "dmr":
|
||||
chain += [
|
||||
"dmr_decoder --fifo {meta_pipe} --control-fifo {dmr_control_pipe}",
|
||||
"mbe_synthesizer {codecserver_arg}",
|
||||
]
|
||||
elif which == "ysf":
|
||||
chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y {codecserver_arg}"]
|
||||
chain += ["digitalvoice_filter"]
|
||||
chain += [
|
||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
||||
"sox -t raw -r 8000 -e signed-integer -b 16 -c 1 --buffer 32 - -t raw -r {output_rate} -e signed-integer -b 16 -c 1 - ",
|
||||
]
|
||||
elif which == "am":
|
||||
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
|
||||
chain += last_decimation_block
|
||||
@ -377,14 +339,10 @@ class dsp(object):
|
||||
if_samp_rate=self.if_samp_rate(),
|
||||
last_decimation=self.last_decimation,
|
||||
audio_rate=self.get_audio_rate(),
|
||||
direwolf_config=self.direwolf_config,
|
||||
direwolf_config=self.direwolf_config_path,
|
||||
)
|
||||
|
||||
logger.debug("secondary command (demod) = %s", secondary_command_demod)
|
||||
my_env = os.environ.copy()
|
||||
# if self.csdr_dynamic_bufsize: my_env["CSDR_DYNAMIC_BUFSIZE_ON"]="1";
|
||||
if self.csdr_print_bufsizes:
|
||||
my_env["CSDR_PRINT_BUFSIZES"] = "1"
|
||||
if self.output.supports_type("secondary_fft"):
|
||||
secondary_command_fft = " | ".join(self.secondary_chain("fft"))
|
||||
secondary_command_fft = secondary_command_fft.format(
|
||||
@ -397,7 +355,7 @@ class dsp(object):
|
||||
logger.debug("secondary command (fft) = %s", secondary_command_fft)
|
||||
|
||||
self.secondary_process_fft = subprocess.Popen(
|
||||
secondary_command_fft, stdout=subprocess.PIPE, shell=True, start_new_session=True, env=my_env
|
||||
secondary_command_fft, stdout=subprocess.PIPE, shell=True, start_new_session=True
|
||||
)
|
||||
self.output.send_output(
|
||||
"secondary_fft",
|
||||
@ -409,38 +367,18 @@ class dsp(object):
|
||||
# it would block if not read. by piping it to devnull, we avoid a potential pitfall here.
|
||||
secondary_output = subprocess.DEVNULL if self.isPacket() else subprocess.PIPE
|
||||
self.secondary_process_demod = subprocess.Popen(
|
||||
secondary_command_demod, stdout=secondary_output, shell=True, start_new_session=True, env=my_env
|
||||
secondary_command_demod, stdout=secondary_output, shell=True, start_new_session=True
|
||||
)
|
||||
self.secondary_processes_running = True
|
||||
|
||||
if self.isWsjtMode():
|
||||
smd = self.get_secondary_demodulator()
|
||||
chopper_profiles = None
|
||||
if smd == "ft8":
|
||||
chopper_profiles = [Ft8Profile()]
|
||||
elif smd == "wspr":
|
||||
chopper_profiles = [WsprProfile()]
|
||||
elif smd == "jt65":
|
||||
chopper_profiles = [Jt65Profile()]
|
||||
elif smd == "jt9":
|
||||
chopper_profiles = [Jt9Profile()]
|
||||
elif smd == "ft4":
|
||||
chopper_profiles = [Ft4Profile()]
|
||||
elif smd == "fst4":
|
||||
chopper_profiles = Fst4Profile.getEnabledProfiles()
|
||||
elif smd == "fst4w":
|
||||
chopper_profiles = Fst4wProfile.getEnabledProfiles()
|
||||
if chopper_profiles is not None and len(chopper_profiles):
|
||||
chopper = AudioChopper(self, self.secondary_process_demod.stdout, *chopper_profiles)
|
||||
chopper.start()
|
||||
self.output.send_output("wsjt_demod", chopper.read)
|
||||
elif self.isJs8():
|
||||
chopper = AudioChopper(self, self.secondary_process_demod.stdout, *Js8Profiles.getEnabledProfiles())
|
||||
chopper.start()
|
||||
self.output.send_output("js8_demod", chopper.read)
|
||||
if self.isWsjtMode() or self.isJs8():
|
||||
chopper = AudioChopper(self, self.get_secondary_demodulator())
|
||||
chopper.send_output("audio", self.secondary_process_demod.stdout.read)
|
||||
output_type = "js8_demod" if self.isJs8() else "wsjt_demod"
|
||||
self.output.send_output(output_type, chopper.read)
|
||||
elif self.isPacket():
|
||||
# we best get the ax25 packets from the kiss socket
|
||||
kiss = KissClient(self.direwolf_port)
|
||||
kiss = KissClient(self.direwolf_config.getPort())
|
||||
self.output.send_output("packet_demod", kiss.read)
|
||||
elif self.isPocsag():
|
||||
self.output.send_output("pocsag_demod", self.secondary_process_demod.stdout.readline)
|
||||
@ -487,11 +425,16 @@ class dsp(object):
|
||||
return self.secondary_demodulator
|
||||
|
||||
def set_secondary_fft_size(self, secondary_fft_size):
|
||||
# to change this, restart is required
|
||||
if self.secondary_fft_size == secondary_fft_size:
|
||||
return
|
||||
self.secondary_fft_size = secondary_fft_size
|
||||
self.restart()
|
||||
|
||||
def set_audio_compression(self, what):
|
||||
if self.audio_compression == what:
|
||||
return
|
||||
self.audio_compression = what
|
||||
self.restart()
|
||||
|
||||
def get_audio_bytes_to_read(self):
|
||||
# desired latency: 5ms
|
||||
@ -506,6 +449,7 @@ class dsp(object):
|
||||
if self.fft_compression == what:
|
||||
return
|
||||
self.fft_compression = what
|
||||
self.restart()
|
||||
|
||||
def get_secondary_fft_bytes_to_read(self):
|
||||
if self.fft_compression == "none":
|
||||
@ -528,6 +472,8 @@ class dsp(object):
|
||||
(self.decimation, self.last_decimation) = self.get_decimation(self.samp_rate, self.get_audio_rate())
|
||||
|
||||
def get_decimation(self, input_rate, output_rate):
|
||||
if output_rate <= 0:
|
||||
raise ValueError("invalid output rate: {rate}".format(rate=output_rate))
|
||||
decimation = 1
|
||||
target_rate = output_rate
|
||||
# wideband fm has a much higher frequency deviation (75kHz).
|
||||
@ -571,7 +517,7 @@ class dsp(object):
|
||||
def isWsjtMode(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
demodulator = self.get_secondary_demodulator()
|
||||
return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w"]
|
||||
return demodulator in ["ft8", "wspr", "jt65", "jt9", "ft4", "fst4", "fst4w", "q65"]
|
||||
|
||||
def isJs8(self, demodulator=None):
|
||||
if demodulator is None:
|
||||
@ -665,7 +611,7 @@ class dsp(object):
|
||||
# no squelch required on digital voice modes
|
||||
actual_squelch = (
|
||||
-150
|
||||
if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV()
|
||||
if self.isDigitalVoice() or self.isPacket() or self.isPocsag() or self.isFreeDV() or self.isDrm()
|
||||
else self.squelch_level
|
||||
)
|
||||
if self.running:
|
||||
@ -678,6 +624,15 @@ class dsp(object):
|
||||
def get_unvoiced_quality(self):
|
||||
return self.unvoiced_quality
|
||||
|
||||
def set_codecserver(self, s):
|
||||
if self.codecserver == s:
|
||||
return
|
||||
self.codecserver = s
|
||||
self.restart()
|
||||
|
||||
def get_codecserver_arg(self):
|
||||
return "-s {}".format(self.codecserver) if self.codecserver else ""
|
||||
|
||||
def set_dmr_filter(self, filter):
|
||||
if self.has_pipe("dmr_control_pipe"):
|
||||
self.pipes["dmr_control_pipe"].write("{0}\n".format(filter))
|
||||
@ -718,27 +673,34 @@ class dsp(object):
|
||||
|
||||
def try_create_configs(self, command):
|
||||
if "{direwolf_config}" in command:
|
||||
self.direwolf_config = "{tmp_dir}/openwebrx_direwolf_{myid}.conf".format(
|
||||
self.direwolf_config_path = "{tmp_dir}/openwebrx_direwolf_{myid}.conf".format(
|
||||
tmp_dir=self.temporary_directory, myid=id(self)
|
||||
)
|
||||
self.direwolf_port = KissClient.getFreePort()
|
||||
file = open(self.direwolf_config, "w")
|
||||
file.write(DirewolfConfig().getConfig(self.direwolf_port, self.is_service))
|
||||
self.direwolf_config = DirewolfConfig()
|
||||
self.direwolf_config.wire(self)
|
||||
file = open(self.direwolf_config_path, "w")
|
||||
file.write(self.direwolf_config.getConfig(self.is_service))
|
||||
file.close()
|
||||
else:
|
||||
self.direwolf_config = None
|
||||
self.direwolf_port = None
|
||||
self.direwolf_config_path = None
|
||||
|
||||
def try_delete_configs(self):
|
||||
if self.direwolf_config:
|
||||
if self.direwolf_config is not None:
|
||||
self.direwolf_config.unwire(self)
|
||||
self.direwolf_config = None
|
||||
if self.direwolf_config_path is not None:
|
||||
try:
|
||||
os.unlink(self.direwolf_config)
|
||||
os.unlink(self.direwolf_config_path)
|
||||
except FileNotFoundError:
|
||||
# result suits our expectations. fine :)
|
||||
pass
|
||||
except Exception:
|
||||
logger.exception("try_delete_configs()")
|
||||
self.direwolf_config = None
|
||||
self.direwolf_config_path = None
|
||||
|
||||
def onConfigChanged(self):
|
||||
self.restart()
|
||||
|
||||
def start(self):
|
||||
with self.modification_lock:
|
||||
@ -781,19 +743,15 @@ class dsp(object):
|
||||
output_rate=self.get_output_rate(),
|
||||
smeter_report_every=int(self.if_samp_rate() / 6000),
|
||||
unvoiced_quality=self.get_unvoiced_quality(),
|
||||
codecserver_arg=self.get_codecserver_arg(),
|
||||
audio_rate=self.get_audio_rate(),
|
||||
wfm_deemphasis_tau=self.wfm_deemphasis_tau,
|
||||
)
|
||||
|
||||
logger.debug("Command = %s", command)
|
||||
my_env = os.environ.copy()
|
||||
if self.csdr_dynamic_bufsize:
|
||||
my_env["CSDR_DYNAMIC_BUFSIZE_ON"] = "1"
|
||||
if self.csdr_print_bufsizes:
|
||||
my_env["CSDR_PRINT_BUFSIZES"] = "1"
|
||||
|
||||
out = subprocess.PIPE if self.output.supports_type("audio") else subprocess.DEVNULL
|
||||
self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True, env=my_env)
|
||||
self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True)
|
||||
|
||||
def watch_thread():
|
||||
rc = self.process.wait()
|
||||
@ -837,10 +795,6 @@ class dsp(object):
|
||||
|
||||
self.output.send_output("meta", read_meta)
|
||||
|
||||
if self.csdr_dynamic_bufsize:
|
||||
self.process.stdout.read(8) # dummy read to skip bufsize & preamble
|
||||
logger.debug("Note: CSDR_DYNAMIC_BUFSIZE_ON = 1")
|
||||
|
||||
def stop(self):
|
||||
with self.modification_lock:
|
||||
self.running = False
|
||||
@ -859,6 +813,7 @@ class dsp(object):
|
||||
self.stop_secondary_demodulator()
|
||||
|
||||
self.try_delete_pipes(self.pipe_names)
|
||||
self.try_delete_configs()
|
||||
|
||||
def restart(self):
|
||||
if not self.running:
|
36
csdr/output.py
Normal file
@ -0,0 +1,36 @@
|
||||
import threading
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Output(object):
|
||||
def send_output(self, t, read_fn):
|
||||
if not self.supports_type(t):
|
||||
# TODO rewrite the output mechanism in a way that avoids producing unnecessary data
|
||||
logger.warning("dumping output of type %s since it is not supported.", t)
|
||||
threading.Thread(target=self.pump(read_fn, lambda x: None), name="csdr_pump_thread").start()
|
||||
return
|
||||
self.receive_output(t, read_fn)
|
||||
|
||||
def receive_output(self, t, read_fn):
|
||||
pass
|
||||
|
||||
def pump(self, read, write):
|
||||
def copy():
|
||||
run = True
|
||||
while run:
|
||||
data = None
|
||||
try:
|
||||
data = read()
|
||||
except ValueError:
|
||||
pass
|
||||
if data is None or (isinstance(data, bytes) and len(data) == 0):
|
||||
run = False
|
||||
else:
|
||||
write(data)
|
||||
|
||||
return copy
|
||||
|
||||
def supports_type(self, t):
|
||||
return True
|
53
debian/changelog
vendored
@ -1,21 +1,60 @@
|
||||
openwebrx (0.21.0) UNRELEASED; urgency=low
|
||||
openwebrx (1.1.0) UNRELEASED; urgency=low
|
||||
|
||||
* Reworked most graphical elements as SVGs for faster loadtimes and crispier
|
||||
display on hi-dpi displays
|
||||
* Updated pipelines to match changes in digiham
|
||||
* Changed D-Star and NXDN integrations to use new decoder from digiham
|
||||
* Added D-Star and NXDN metadata display
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Sun, 09 May 2021 14:05:00 +0000
|
||||
|
||||
openwebrx (1.0.0) buster hirsute; urgency=low
|
||||
* Introduced `squelch_auto_margin` config option that allows configuring the
|
||||
auto squelch level
|
||||
* Removed `port` configuration option; `rtltcp_compat` takes the port number
|
||||
with the new connectors
|
||||
* Added support for new WSJT-X modes FST4 and FST4W (only available with
|
||||
WSJT-X 2.3)
|
||||
* Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X
|
||||
2.3) and Q65 (only available with WSJT-X 2.4)
|
||||
* Added support for demodulating M17 digital voice signals using
|
||||
m17-cxx-demod
|
||||
* New reporting infrastructure, allowing WSPR and FST4W spots to be sent to
|
||||
wsprnet.org
|
||||
* Add some basic filtering capabilities to the map
|
||||
* New arguments to the `openwebrx` command-line to facilitate the
|
||||
administration of users (try `openwebrx admin`)
|
||||
* New command-line tool `openwebrx-admin` that facilitates the
|
||||
administration of users
|
||||
* Default bandwidth changes:
|
||||
- "WFM" changed to 150kHz
|
||||
- "Packet" (APRS) changed to 12.5kHz
|
||||
* Configuration rework:
|
||||
- New: fully web-based configuration interface
|
||||
- System configuration parameters have been moved to a new, separate
|
||||
`openwebrx.conf` file
|
||||
- Remaining parameters are now editable in the web configuration
|
||||
- Existing `config_webrx.py` files will still be read, but changes made in
|
||||
the web configuration will be written to a new storage system
|
||||
- Added upload of avatar and panorama image via web configuration
|
||||
* New devices supported:
|
||||
- HPSDR devices (Hermes Lite 2) (`"type": "hpsdr"`)
|
||||
- BBRF103 / RX666 / RX888 devices supported by libsddc (`"type": "sddc"`)
|
||||
- Devices using the EB200 protocol (`"type": "eb200"`)
|
||||
- HPSDR devices (Hermes Lite 2) thanks to @jancona
|
||||
- BBRF103 / RX666 / RX888 devices supported by libsddc
|
||||
- R&S devices using the EB200 or Ammos protocols
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Sun, 11 Oct 2020 21:12:00 +0000
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Thu, 06 May 2021 17:22:00 +0000
|
||||
|
||||
openwebrx (0.20.3) buster focal; urgency=low
|
||||
|
||||
* Fix a compatibility issue with python versions <= 3.6
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Tue, 26 Jan 2021 15:28:00 +0000
|
||||
|
||||
openwebrx (0.20.2) buster focal; urgency=high
|
||||
|
||||
* Fix a security problem that allowed arbitrary commands to be executed on
|
||||
the receiver (See github issue #215:
|
||||
https://github.com/jketterl/openwebrx/issues/215)
|
||||
|
||||
-- Jakob Ketterl <jakob.ketterl@gmx.de> Sun, 24 Jan 2021 22:50:00 +0000
|
||||
|
||||
openwebrx (0.20.1) buster focal; urgency=low
|
||||
|
||||
|
6
debian/control
vendored
@ -10,7 +10,7 @@ Vcs-Git: https://github.com/jketterl/openwebrx.git
|
||||
|
||||
Package: openwebrx
|
||||
Architecture: all
|
||||
Depends: adduser, python3 (>= 3.5), python3-pkg-resources, csdr (>= 0.17), netcat, owrx-connector (>= 0.4), soapysdr-tools, python3-js8py (>= 0.1), ${python3:Depends}, ${misc:Depends}
|
||||
Recommends: digiham (>= 0.3), dsd (>= 1.7), sox, direwolf (>= 1.4), wsjtx, eb200-connector, hpsdrconnector, aprs-symbols, m17-demod
|
||||
Depends: adduser, python3 (>= 3.5), python3-pkg-resources, csdr (>= 0.17), netcat, owrx-connector (>= 0.5), soapysdr-tools, python3-js8py (>= 0.1), ${python3:Depends}, ${misc:Depends}
|
||||
Recommends: digiham (>= 0.5), sox, direwolf (>= 1.4), wsjtx, runds-connector (>= 0.2), hpsdrconnector, aprs-symbols, m17-demod, js8call
|
||||
Description: multi-user web sdr
|
||||
Open source, multi-user SDR receiver with a web interface
|
||||
Open source, multi-user SDR receiver with a web interface
|
||||
|
8
debian/openwebrx.config
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh -e
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
db_get openwebrx/admin_user_configured
|
||||
if [ "${1:-}" = "reconfigure" ] || [ "${RET}" != true ]; then
|
||||
db_input high openwebrx/admin_user_password || true
|
||||
db_go
|
||||
fi
|
1
debian/openwebrx.dirs
vendored
Normal file
@ -0,0 +1 @@
|
||||
/etc/openwebrx/openwebrx.conf.d
|
4
debian/openwebrx.install
vendored
@ -1,5 +1,3 @@
|
||||
config_webrx.py etc/openwebrx/
|
||||
bands.json etc/openwebrx/
|
||||
bookmarks.json etc/openwebrx/
|
||||
users.json etc/openwebrx/
|
||||
openwebrx.conf etc/openwebrx/
|
||||
systemd/openwebrx.service lib/systemd/system/
|
59
debian/openwebrx.postinst
vendored
Executable file
@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
OWRX_USER="openwebrx"
|
||||
OWRX_DATADIR="/var/lib/openwebrx"
|
||||
OWRX_USERS_FILE="${OWRX_DATADIR}/users.json"
|
||||
OWRX_SETTINGS_FILE="${OWRX_DATADIR}/settings.json"
|
||||
OWRX_BOOKMARKS_FILE="${OWRX_DATADIR}/bookmarks.json"
|
||||
|
||||
case "$1" in
|
||||
configure|reconfigure)
|
||||
adduser --system --group --no-create-home --home /nonexistent --quiet "${OWRX_USER}"
|
||||
usermod -aG plugdev "${OWRX_USER}"
|
||||
|
||||
# create OpenWebRX data directory and set the correct permissions
|
||||
if [ ! -d "${OWRX_DATADIR}" ] && [ ! -L "${OWRX_DATADIR}" ]; then mkdir "${OWRX_DATADIR}"; fi
|
||||
chown "${OWRX_USER}". ${OWRX_DATADIR}
|
||||
|
||||
# create empty config files now to avoid permission problems later
|
||||
if [ ! -e "${OWRX_USERS_FILE}" ]; then
|
||||
echo "[]" > "${OWRX_USERS_FILE}"
|
||||
chown "${OWRX_USER}". "${OWRX_USERS_FILE}"
|
||||
chmod 0600 "${OWRX_USERS_FILE}"
|
||||
fi
|
||||
|
||||
if [ ! -e "${OWRX_SETTINGS_FILE}" ]; then
|
||||
echo "{}" > "${OWRX_SETTINGS_FILE}"
|
||||
chown "${OWRX_USER}". "${OWRX_SETTINGS_FILE}"
|
||||
fi
|
||||
|
||||
if [ ! -e "${OWRX_BOOKMARKS_FILE}" ]; then
|
||||
touch "${OWRX_BOOKMARKS_FILE}"
|
||||
chown "${OWRX_USER}". "${OWRX_BOOKMARKS_FILE}"
|
||||
fi
|
||||
|
||||
db_get openwebrx/admin_user_password
|
||||
if [ ! -z "${RET}" ]; then
|
||||
if ! openwebrx admin --silent hasuser admin; then
|
||||
# create initial openwebrx user
|
||||
OWRX_PASSWORD="${RET}" openwebrx admin --noninteractive adduser admin
|
||||
else
|
||||
# change existing user's password
|
||||
OWRX_PASSWORD="${RET}" openwebrx admin --noninteractive resetpassword admin
|
||||
fi
|
||||
fi
|
||||
# remove password from debconf database
|
||||
db_unregister openwebrx/admin_user_password
|
||||
# set a marker that admin is configured to avoid future questions
|
||||
db_set openwebrx/admin_user_configured true
|
||||
;;
|
||||
*)
|
||||
echo "postinst called with unknown argument '$1'" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
8
debian/openwebrx.postrm
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
|
||||
. /usr/share/debconf/confmodule
|
||||
db_purge
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
23
debian/openwebrx.templates
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
Template: openwebrx/admin_user_password
|
||||
Type: password
|
||||
Description: OpenWebRX "admin" user password:
|
||||
The system can create a user for the OpenWebRX web configuration interface for
|
||||
you. Using this user, you will be able to log into the "settings" area of
|
||||
OpenWebRX to configure your receiver conveniently through your browser.
|
||||
.
|
||||
The name of the created user will be "admin".
|
||||
.
|
||||
If you do not wish to create a web admin user right now, you can leave this
|
||||
empty for now. You can return to this prompt at a later time by running the
|
||||
command "sudo dpkg-reconfigure openwebrx".
|
||||
.
|
||||
You can also use the "openwebrx admin" command to create, delete or manage
|
||||
existing users. More information is available in by running the command
|
||||
"openwebrx admin --help".
|
||||
|
||||
Template: openwebrx/admin_user_configured
|
||||
Type: boolean
|
||||
Default: false
|
||||
Description: OpenWebRX "admin" user previously configured?
|
||||
Marker used internally by the config scripts to remember if an admin user has
|
||||
been created.
|
7
debian/postinst
vendored
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
adduser --system --group --no-create-home --home /nonexistent --quiet openwebrx
|
||||
usermod -aG plugdev openwebrx
|
||||
|
||||
#DEBHELPER#
|
14
docker.sh
@ -2,10 +2,10 @@
|
||||
set -euo pipefail
|
||||
|
||||
ARCH=$(uname -m)
|
||||
IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-redpitaya openwebrx-rtltcp openwebrx-eb200 openwebrx-hpsdr openwebrx-full openwebrx"
|
||||
IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-rtltcp openwebrx-runds openwebrx-hpsdr openwebrx-full openwebrx"
|
||||
ALL_ARCHS="x86_64 armv7l aarch64"
|
||||
TAG=${TAG:-"latest"}
|
||||
ARCHTAG="$TAG-$ARCH"
|
||||
ARCHTAG="${TAG}-${ARCH}"
|
||||
|
||||
usage () {
|
||||
echo "Usage: ${0} [command]"
|
||||
@ -36,7 +36,7 @@ build () {
|
||||
|
||||
push () {
|
||||
for image in ${IMAGES}; do
|
||||
docker push jketterl/$image:$ARCHTAG
|
||||
docker push jketterl/${image}:${ARCHTAG}
|
||||
done
|
||||
}
|
||||
|
||||
@ -45,11 +45,11 @@ manifest () {
|
||||
# there's no docker manifest rm command, and the create --amend does not work, so we have to clean up manually
|
||||
rm -rf "${HOME}/.docker/manifests/docker.io_jketterl_${image}-${TAG}"
|
||||
IMAGE_LIST=""
|
||||
for a in $ALL_ARCHS; do
|
||||
IMAGE_LIST="$IMAGE_LIST jketterl/$image:$TAG-$a"
|
||||
for a in ${ALL_ARCHS}; do
|
||||
IMAGE_LIST="${IMAGE_LIST} jketterl/${image}:${TAG}-${a}"
|
||||
done
|
||||
docker manifest create jketterl/$image:$TAG $IMAGE_LIST
|
||||
docker manifest push --purge jketterl/$image:$TAG
|
||||
docker manifest create jketterl/${image}:${TAG} ${IMAGE_LIST}
|
||||
docker manifest push --purge jketterl/${image}:${TAG}
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,16 @@ COPY docker/scripts/install-owrx-tools.sh /
|
||||
RUN /install-owrx-tools.sh && \
|
||||
rm /install-owrx-tools.sh
|
||||
|
||||
COPY docker/files/services/codecserver /etc/services.d/codecserver
|
||||
|
||||
ENTRYPOINT ["/init"]
|
||||
|
||||
WORKDIR /opt/openwebrx
|
||||
|
||||
VOLUME /etc/openwebrx
|
||||
VOLUME /var/lib/openwebrx
|
||||
|
||||
CMD [ "/opt/openwebrx/docker/scripts/run.sh" ]
|
||||
ENV S6_CMD_ARG0="/opt/openwebrx/docker/scripts/run.sh"
|
||||
CMD []
|
||||
|
||||
EXPOSE 8073
|
||||
|
@ -18,10 +18,9 @@ RUN /install-dependencies-rtlsdr.sh &&\
|
||||
/install-dependencies-fcdpp.sh &&\
|
||||
/install-dependencies-radioberry.sh &&\
|
||||
/install-dependencies-uhd.sh &&\
|
||||
/install-dependencies-redpitaya.sh &&\
|
||||
/install-dependencies-hpsdr.sh &&\
|
||||
/install-connectors.sh &&\
|
||||
/install-dependencies-eb200.sh &&\
|
||||
/install-dependencies-runds.sh &&\
|
||||
rm /install-dependencies-*.sh &&\
|
||||
rm /install-lib.*.patch && \
|
||||
rm /install-connectors.sh
|
||||
|
@ -1,8 +0,0 @@
|
||||
ARG ARCHTAG
|
||||
FROM openwebrx-soapysdr-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-dependencies-redpitaya.sh /
|
||||
RUN /install-dependencies-redpitaya.sh &&\
|
||||
rm /install-dependencies-redpitaya.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -2,11 +2,11 @@ ARG ARCHTAG
|
||||
FROM openwebrx-base:$ARCHTAG
|
||||
|
||||
COPY docker/scripts/install-connectors.sh \
|
||||
docker/scripts/install-dependencies-eb200.sh /
|
||||
docker/scripts/install-dependencies-runds.sh /
|
||||
|
||||
RUN /install-connectors.sh &&\
|
||||
rm /install-connectors.sh && \
|
||||
/install-dependencies-eb200.sh && \
|
||||
rm /install-dependencies-eb200.sh
|
||||
/install-dependencies-runds.sh && \
|
||||
rm /install-dependencies-runds.sh
|
||||
|
||||
COPY . /opt/openwebrx
|
@ -1,5 +0,0 @@
|
||||
ARCH=$(uname -m)
|
||||
IMAGES="openwebrx-rtlsdr openwebrx-sdrplay openwebrx-hackrf openwebrx-airspy openwebrx-rtlsdr-soapy openwebrx-plutosdr openwebrx-limesdr openwebrx-soapyremote openwebrx-perseus openwebrx-fcdpp openwebrx-radioberry openwebrx-uhd openwebrx-redpitaya openwebrx-rtltcp openwebrx-full openwebrx"
|
||||
ALL_ARCHS="x86_64 armv7l aarch64"
|
||||
TAG=${TAG:-"latest"}
|
||||
ARCHTAG="$TAG-$ARCH"
|
2
docker/files/services/codecserver/run
Executable file
@ -0,0 +1,2 @@
|
||||
#!/usr/bin/execlineb -P
|
||||
/usr/local/bin/codecserver
|
@ -1,18 +1,17 @@
|
||||
--- CMakeLists.txt.orig 2020-07-21 20:59:55.982026645 +0200
|
||||
+++ CMakeLists.txt 2020-07-21 21:01:25.444836112 +0200
|
||||
@@ -80,24 +80,6 @@
|
||||
--- CMakeLists.txt.orig 2021-03-30 15:28:36.956587995 +0200
|
||||
+++ CMakeLists.txt 2021-03-30 15:29:45.719326832 +0200
|
||||
@@ -106,24 +106,6 @@
|
||||
|
||||
include (ExternalProject)
|
||||
|
||||
-
|
||||
-#
|
||||
#
|
||||
-# build and install hamlib locally so it can be referenced by the
|
||||
-# WSJT-X build
|
||||
-#
|
||||
-ExternalProject_Add (hamlib
|
||||
- GIT_REPOSITORY ${hamlib_repo}
|
||||
- GIT_TAG ${hamlib_TAG}
|
||||
- URL ${CMAKE_CURRENT_SOURCE_DIR}/src/${__hamlib_upstream}
|
||||
- GIT_SHALLOW False
|
||||
- URL ${CMAKE_CURRENT_SOURCE_DIR}/src/${__hamlib_upstream}.tar.gz
|
||||
- URL_HASH MD5=${hamlib_md5sum}
|
||||
- #UPDATE_COMMAND ${CMAKE_COMMAND} -E env "[ -f ./bootstrap ] && ./bootstrap"
|
||||
- PATCH_COMMAND ${PATCH_EXECUTABLE} -p1 -N < ${CMAKE_CURRENT_SOURCE_DIR}/hamlib.patch
|
||||
@ -22,10 +21,11 @@
|
||||
- STEP_TARGETS update install
|
||||
- )
|
||||
-
|
||||
#
|
||||
-#
|
||||
# custom target to make a hamlib source tarball
|
||||
#
|
||||
@@ -136,7 +118,6 @@
|
||||
add_custom_target (hamlib_sources
|
||||
@@ -161,7 +143,6 @@
|
||||
# build and optionally install WSJT-X using the hamlib package built
|
||||
# above
|
||||
#
|
||||
@ -33,11 +33,18 @@
|
||||
ExternalProject_Add (wsjtx
|
||||
GIT_REPOSITORY ${wsjtx_repo}
|
||||
GIT_TAG ${WSJTX_TAG}
|
||||
@@ -160,7 +141,6 @@
|
||||
@@ -186,14 +167,8 @@
|
||||
DEPENDEES build
|
||||
)
|
||||
|
||||
-set_target_properties (hamlib PROPERTIES EXCLUDE_FROM_ALL 1)
|
||||
set_target_properties (wsjtx PROPERTIES EXCLUDE_FROM_ALL 1)
|
||||
|
||||
add_dependencies (wsjtx-configure hamlib-install)
|
||||
-add_dependencies (wsjtx-configure hamlib-install)
|
||||
-add_dependencies (wsjtx-build hamlib-install)
|
||||
-add_dependencies (wsjtx-install hamlib-install)
|
||||
-add_dependencies (wsjtx-package hamlib-install)
|
||||
-
|
||||
# export traditional targets
|
||||
add_custom_target (build ALL DEPENDS wsjtx-build)
|
||||
add_custom_target (install DEPENDS wsjtx-install)
|
||||
|
@ -1,6 +1,6 @@
|
||||
diff -ur wsjtx-orig/CMake/Modules/Findhamlib.cmake wsjtx/CMake/Modules/Findhamlib.cmake
|
||||
--- wsjtx-orig/CMake/Modules/Findhamlib.cmake 2020-07-21 21:10:43.124810140 +0200
|
||||
+++ wsjtx/CMake/Modules/Findhamlib.cmake 2020-07-21 21:11:03.368019114 +0200
|
||||
--- wsjtx-orig/CMake/Modules/Findhamlib.cmake 2021-05-31 18:56:20.657682124 +0200
|
||||
+++ wsjtx/CMake/Modules/Findhamlib.cmake 2021-05-31 18:57:03.963994898 +0200
|
||||
@@ -85,4 +85,4 @@
|
||||
# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to
|
||||
# TRUE if all listed variables are TRUE
|
||||
@ -8,9 +8,93 @@ diff -ur wsjtx-orig/CMake/Modules/Findhamlib.cmake wsjtx/CMake/Modules/Findhamli
|
||||
-find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES hamlib_LIBRARY_DIRS)
|
||||
+find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES)
|
||||
diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
--- wsjtx-orig/CMakeLists.txt 2020-07-21 21:10:43.124810140 +0200
|
||||
+++ wsjtx/CMakeLists.txt 2020-07-21 22:14:04.454639589 +0200
|
||||
@@ -871,7 +871,7 @@
|
||||
--- wsjtx-orig/CMakeLists.txt 2021-05-31 18:56:20.657682124 +0200
|
||||
+++ wsjtx/CMakeLists.txt 2021-05-31 19:08:02.768474060 +0200
|
||||
@@ -122,7 +122,7 @@
|
||||
option (WSJT_QDEBUG_TO_FILE "Redirect Qt debuging messages to a trace file.")
|
||||
option (WSJT_SOFT_KEYING "Apply a ramp to CW keying envelope to reduce transients." ON)
|
||||
option (WSJT_SKIP_MANPAGES "Skip *nix manpage generation.")
|
||||
-option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
|
||||
+option (WSJT_GENERATE_DOCS "Generate documentation files.")
|
||||
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
|
||||
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
|
||||
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
|
||||
@@ -169,74 +169,7 @@
|
||||
)
|
||||
|
||||
set (wsjt_qt_CXXSRCS
|
||||
- qt_helpers.cpp
|
||||
- widgets/MessageBox.cpp
|
||||
- MetaDataRegistry.cpp
|
||||
- Network/NetworkServerLookup.cpp
|
||||
revision_utils.cpp
|
||||
- L10nLoader.cpp
|
||||
- WFPalette.cpp
|
||||
- Radio.cpp
|
||||
- RadioMetaType.cpp
|
||||
- NonInheritingProcess.cpp
|
||||
- models/IARURegions.cpp
|
||||
- models/Bands.cpp
|
||||
- models/Modes.cpp
|
||||
- models/FrequencyList.cpp
|
||||
- models/StationList.cpp
|
||||
- widgets/FrequencyLineEdit.cpp
|
||||
- widgets/FrequencyDeltaLineEdit.cpp
|
||||
- item_delegates/CandidateKeyFilter.cpp
|
||||
- item_delegates/ForeignKeyDelegate.cpp
|
||||
- validators/LiveFrequencyValidator.cpp
|
||||
- GetUserId.cpp
|
||||
- Audio/AudioDevice.cpp
|
||||
- Transceiver/Transceiver.cpp
|
||||
- Transceiver/TransceiverBase.cpp
|
||||
- Transceiver/EmulateSplitTransceiver.cpp
|
||||
- Transceiver/TransceiverFactory.cpp
|
||||
- Transceiver/PollingTransceiver.cpp
|
||||
- Transceiver/HamlibTransceiver.cpp
|
||||
- Transceiver/HRDTransceiver.cpp
|
||||
- Transceiver/DXLabSuiteCommanderTransceiver.cpp
|
||||
- Network/NetworkMessage.cpp
|
||||
- Network/MessageClient.cpp
|
||||
- widgets/LettersSpinBox.cpp
|
||||
- widgets/HintedSpinBox.cpp
|
||||
- widgets/RestrictedSpinBox.cpp
|
||||
- widgets/HelpTextWindow.cpp
|
||||
- SampleDownloader.cpp
|
||||
- SampleDownloader/DirectoryDelegate.cpp
|
||||
- SampleDownloader/Directory.cpp
|
||||
- SampleDownloader/FileNode.cpp
|
||||
- SampleDownloader/RemoteFile.cpp
|
||||
- DisplayManual.cpp
|
||||
- MultiSettings.cpp
|
||||
- validators/MaidenheadLocatorValidator.cpp
|
||||
- validators/CallsignValidator.cpp
|
||||
- widgets/SplashScreen.cpp
|
||||
- EqualizationToolsDialog.cpp
|
||||
- widgets/DoubleClickablePushButton.cpp
|
||||
- widgets/DoubleClickableRadioButton.cpp
|
||||
- Network/LotWUsers.cpp
|
||||
- models/DecodeHighlightingModel.cpp
|
||||
- widgets/DecodeHighlightingListView.cpp
|
||||
- models/FoxLog.cpp
|
||||
- widgets/AbstractLogWindow.cpp
|
||||
- widgets/FoxLogWindow.cpp
|
||||
- widgets/CabrilloLogWindow.cpp
|
||||
- item_delegates/CallsignDelegate.cpp
|
||||
- item_delegates/MaidenheadLocatorDelegate.cpp
|
||||
- item_delegates/FrequencyDelegate.cpp
|
||||
- item_delegates/FrequencyDeltaDelegate.cpp
|
||||
- item_delegates/SQLiteDateTimeDelegate.cpp
|
||||
- models/CabrilloLog.cpp
|
||||
- logbook/AD1CCty.cpp
|
||||
- logbook/WorkedBefore.cpp
|
||||
- logbook/Multiplier.cpp
|
||||
- Network/NetworkAccessManager.cpp
|
||||
- widgets/LazyFillComboBox.cpp
|
||||
- widgets/CheckableItemComboBox.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
@@ -857,7 +790,7 @@
|
||||
#
|
||||
# libhamlib setup
|
||||
#
|
||||
@ -19,31 +103,47 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
find_package (hamlib 3 REQUIRED)
|
||||
find_program (RIGCTL_EXE rigctl)
|
||||
find_program (RIGCTLD_EXE rigctld)
|
||||
@@ -1348,53 +1348,10 @@
|
||||
@@ -895,9 +828,6 @@
|
||||
if (WSJT_GENERATE_DOCS)
|
||||
add_subdirectory (doc)
|
||||
endif (WSJT_GENERATE_DOCS)
|
||||
-if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests)
|
||||
- add_subdirectory (tests)
|
||||
-endif ()
|
||||
|
||||
endif(WSJT_BUILD_UTILS)
|
||||
#
|
||||
# Library building setup
|
||||
@@ -1380,60 +1310,6 @@
|
||||
target_link_libraries (jt9 wsjt_fort wsjt_cxx fort_qt)
|
||||
endif (${OPENMP_FOUND} OR APPLE)
|
||||
|
||||
-# build the main application
|
||||
-generate_version_info (wsjtx_VERSION_RESOURCES
|
||||
- NAME wsjtx
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- )
|
||||
-
|
||||
-add_executable (wsjtx MACOSX_BUNDLE
|
||||
- ${wsjtx_CXXSRCS}
|
||||
- ${wsjtx_GENUISRCS}
|
||||
- wsjtx.rc
|
||||
- ${WSJTX_ICON_FILE}
|
||||
- ${wsjtx_RESOURCES_RCC}
|
||||
- ${wsjtx_VERSION_RESOURCES}
|
||||
- )
|
||||
-
|
||||
if (WSJT_CREATE_WINMAIN)
|
||||
set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
||||
endif (WSJT_CREATE_WINMAIN)
|
||||
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-set_target_properties (wsjtx PROPERTIES
|
||||
- MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
|
||||
- MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}"
|
||||
- MACOSX_BUNDLE_INFO_STRING "${PROJECT_DESCRIPTION}"
|
||||
- MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||
- MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION}
|
||||
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}"
|
||||
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}"
|
||||
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}"
|
||||
- MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
|
||||
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
|
||||
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${SCS_VERSION_STR}"
|
||||
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_BUNDLE_NAME}"
|
||||
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
||||
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
||||
- MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
||||
@ -51,9 +151,9 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
-
|
||||
-target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||
-if (APPLE)
|
||||
- target_link_libraries (wsjtx Qt5::SerialPort wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
- target_link_libraries (wsjtx wsjt_fort)
|
||||
-else ()
|
||||
- target_link_libraries (wsjtx Qt5::SerialPort wsjt_fort_omp wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
- target_link_libraries (wsjtx wsjt_fort_omp)
|
||||
- if (OpenMP_C_FLAGS)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
@ -65,18 +165,42 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
- )
|
||||
- if (WIN32)
|
||||
- set_target_properties (wsjtx PROPERTIES
|
||||
- LINK_FLAGS -Wl,--stack,16777216
|
||||
- LINK_FLAGS -Wl,--stack,0x1000000,--heap,0x20000000
|
||||
- )
|
||||
- endif ()
|
||||
-endif ()
|
||||
-target_link_libraries (wsjtx Qt5::SerialPort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES} ${LIBM_LIBRARIES})
|
||||
-
|
||||
# make a library for WSJT-X UDP servers
|
||||
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
||||
add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
|
||||
@@ -1437,24 +1394,9 @@
|
||||
set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
|
||||
endif (WSJT_CREATE_WINMAIN)
|
||||
@@ -1473,47 +1349,9 @@
|
||||
add_executable (wsjtx_app_version AppVersion/AppVersion.cpp ${wsjtx_app_version_VERSION_RESOURCES})
|
||||
target_link_libraries (wsjtx_app_version wsjt_qt)
|
||||
|
||||
-generate_version_info (message_aggregator_VERSION_RESOURCES
|
||||
- NAME message_aggregator
|
||||
- BUNDLE ${PROJECT_BUNDLE_NAME}
|
||||
- ICON ${WSJTX_ICON_FILE}
|
||||
- FILE_DESCRIPTION "Example WSJT-X UDP Message Protocol application"
|
||||
- )
|
||||
-add_resources (message_aggregator_RESOURCES /qss ${message_aggregator_STYLESHEETS})
|
||||
-configure_file (UDPExamples/message_aggregator.qrc.in message_aggregator.qrc @ONLY)
|
||||
-qt5_add_resources (message_aggregator_RESOURCES_RCC
|
||||
- ${CMAKE_CURRENT_BINARY_DIR}/message_aggregator.qrc
|
||||
- contrib/QDarkStyleSheet/qdarkstyle/style.qrc
|
||||
- )
|
||||
-add_executable (message_aggregator
|
||||
- ${message_aggregator_CXXSRCS}
|
||||
- ${message_aggregator_RESOURCES_RCC}
|
||||
- ${message_aggregator_VERSION_RESOURCES}
|
||||
- )
|
||||
-target_link_libraries (message_aggregator wsjt_qt Qt5::Widgets wsjtx_udp-static)
|
||||
-
|
||||
-if (WSJT_CREATE_WINMAIN)
|
||||
- set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
|
||||
-endif (WSJT_CREATE_WINMAIN)
|
||||
-
|
||||
-if (UNIX)
|
||||
- if (NOT WSJT_SKIP_MANPAGES)
|
||||
- add_subdirectory (manpages)
|
||||
@ -98,21 +222,21 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
|
||||
# install (TARGETS wsjtx_udp EXPORT udp
|
||||
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
@@ -1473,12 +1415,7 @@
|
||||
@@ -1532,12 +1370,7 @@
|
||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
|
||||
# )
|
||||
|
||||
-install (TARGETS udp_daemon message_aggregator
|
||||
-install (TARGETS udp_daemon message_aggregator wsjtx_app_version
|
||||
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
-install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
||||
+install (TARGETS jt9 wsprd
|
||||
+install (TARGETS wsjtx_app_version jt9 wsprd
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
@@ -1491,39 +1428,6 @@
|
||||
@@ -1549,38 +1382,6 @@
|
||||
)
|
||||
endif(WSJT_BUILD_UTILS)
|
||||
|
||||
@ -143,13 +267,50 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||
- AUTHORS
|
||||
- THANKS
|
||||
- NEWS
|
||||
- INSTALL
|
||||
- BUGS
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
install (FILES
|
||||
contrib/Ephemeris/JPLEPH
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
|
||||
Only in wsjtx: .idea
|
||||
cty.dat
|
||||
cty.dat_copyright.txt
|
||||
@@ -1589,13 +1390,6 @@
|
||||
#COMPONENT runtime
|
||||
)
|
||||
|
||||
-install (DIRECTORY
|
||||
- example_log_configurations
|
||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
- FILES_MATCHING REGEX "^.*[^~]$"
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-
|
||||
#
|
||||
# Mac installer files
|
||||
#
|
||||
@@ -1648,22 +1442,6 @@
|
||||
)
|
||||
|
||||
|
||||
-if (NOT WIN32 AND NOT APPLE)
|
||||
- # install a desktop file so wsjtx appears in the application start
|
||||
- # menu with an icon
|
||||
- install (
|
||||
- FILES wsjtx.desktop message_aggregator.desktop
|
||||
- DESTINATION share/applications
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
- install (
|
||||
- FILES icons/Unix/wsjtx_icon.png
|
||||
- DESTINATION share/pixmaps
|
||||
- #COMPONENT runtime
|
||||
- )
|
||||
-endif (NOT WIN32 AND NOT APPLE)
|
||||
-
|
||||
-
|
||||
#
|
||||
# bundle fixup only done in non-Debug configurations
|
||||
#
|
||||
Only in wsjtx/: CMakeLists.txt.orig
|
||||
Only in wsjtx/: .idea
|
||||
|
@ -24,8 +24,8 @@ apt-get update
|
||||
apt-get -y install --no-install-recommends $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/jketterl/owrx_connector.git
|
||||
# latest develop as of 2020-11-28 (int32 samples; debhelper)
|
||||
cmakebuild owrx_connector 87a2fcc54e221aad71ec0700737ca7f385c388de
|
||||
# latest develop as of 2021-05-18 (individual connector versions)
|
||||
cmakebuild owrx_connector 167324219813f61b2be8164eb4acb1237ba2c304
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
|
@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
export MAKEFLAGS="-j4"
|
||||
|
||||
function cmakebuild() {
|
||||
cd $1
|
||||
if [[ ! -z "${2:-}" ]]; then
|
||||
git checkout $2
|
||||
fi
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
make install
|
||||
cd ../..
|
||||
rm -rf $1
|
||||
}
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES=""
|
||||
BUILD_PACKAGES="git cmake make gcc g++"
|
||||
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/pothosware/SoapyRedPitaya.git
|
||||
cmakebuild SoapyRedPitaya soapy-redpitaya-0.1.1
|
||||
|
||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -24,9 +24,9 @@ BUILD_PACKAGES="git cmake make gcc g++ pkg-config"
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
git clone https://github.com/jketterl/eb200_connector.git
|
||||
# latest from develop as of 2020-12-01
|
||||
cmakebuild eb200_connector 9c8313770c1072df72d2fdb85307ca206c29c60a
|
||||
git clone https://github.com/jketterl/runds_connector.git
|
||||
# latest develop as of 2021-05-18 (individual connector versions)
|
||||
cmakebuild runds_connector adfa04bee4ee36852feb07e7b845be2c3d3f97c7
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
@ -48,9 +48,9 @@ cd ..
|
||||
rm -rf sdrplay
|
||||
rm $BINARY
|
||||
|
||||
git clone https://github.com/SDRplay/SoapySDRPlay.git
|
||||
# latest from master as of 2020-09-04
|
||||
cmakebuild SoapySDRPlay 105f8a6b3d449982d7ef860790c201aa066b8fa9
|
||||
git clone https://github.com/pothosware/SoapySDRPlay3.git
|
||||
# latest from master as of 2021-06-19 (reliability fixes)
|
||||
cmakebuild SoapySDRPlay3 a869f25364a1f0d5b16169ff908aa21a2ace475d
|
||||
|
||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
|
@ -18,8 +18,8 @@ function cmakebuild() {
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="sox libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline7 libgfortran4 libgomp1 libasound2 libudev1 ca-certificates libqt5gui5 libqt5sql5 libqt5printsupport5 libpulse0 libfaad2 libopus0 libboost-program-options1.67.0"
|
||||
BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-default libfaad-dev libopus-dev libgtest-dev libboost-dev libboost-program-options-dev"
|
||||
STATIC_PACKAGES="sox libfftw3-bin python3 python3-setuptools netcat-openbsd libsndfile1 liblapack3 libusb-1.0-0 libqt5core5a libreadline7 libgfortran4 libgomp1 libasound2 libudev1 ca-certificates libqt5gui5 libqt5sql5 libqt5printsupport5 libpulse0 libfaad2 libopus0 libboost-program-options1.67.0 libboost-log1.67.0"
|
||||
BUILD_PACKAGES="wget git libsndfile1-dev libfftw3-dev cmake make gcc g++ liblapack-dev texinfo gfortran libusb-1.0-0-dev qtbase5-dev qtmultimedia5-dev qttools5-dev libqt5serialport5-dev qttools5-dev-tools asciidoctor asciidoc libasound2-dev libudev-dev libhamlib-dev patch xsltproc qt5-default libfaad-dev libopus-dev libgtest-dev libboost-dev libboost-program-options-dev libboost-log-dev libboost-regex-dev"
|
||||
apt-get update
|
||||
apt-get -y install auto-apt-proxy
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
@ -40,15 +40,6 @@ wget https://github.com/just-containers/s6-overlay/releases/download/v1.21.8.0/s
|
||||
tar xzf s6-overlay-${PLATFORM}.tar.gz -C /
|
||||
rm s6-overlay-${PLATFORM}.tar.gz
|
||||
|
||||
git clone https://git.code.sf.net/p/itpp/git itpp
|
||||
cmakebuild itpp bb5c7e95f40e8fdb5c3f3d01a84bcbaf76f3676d
|
||||
|
||||
git clone https://github.com/szechyjs/mbelib.git
|
||||
cmakebuild mbelib 9a04ed5c78176a9965f3d43f7aa1b1f5330e771f
|
||||
|
||||
git clone https://github.com/f4exb/dsd.git
|
||||
cmakebuild dsd f6939f9edbbc6f66261833616391a4e59cb2b3d7
|
||||
|
||||
JS8CALL_VERSION=2.2.0
|
||||
JS8CALL_DIR=js8call
|
||||
JS8CALL_TGZ=js8call-${JS8CALL_VERSION}.tgz
|
||||
@ -60,7 +51,7 @@ rm /js8call-hamlib.patch
|
||||
CMAKE_ARGS="-D CMAKE_CXX_FLAGS=-DJS8_USE_HAMLIB_THREE" cmakebuild ${JS8CALL_DIR}
|
||||
rm ${JS8CALL_TGZ}
|
||||
|
||||
WSJT_DIR=wsjtx-2.2.2
|
||||
WSJT_DIR=wsjtx-2.4.0
|
||||
WSJT_TGZ=${WSJT_DIR}.tgz
|
||||
wget http://physics.princeton.edu/pulsar/k1jt/${WSJT_TGZ}
|
||||
tar xfz ${WSJT_TGZ}
|
||||
@ -111,12 +102,14 @@ rm -rf dream
|
||||
rm dream-2.1.1-svn808.tar.gz
|
||||
|
||||
git clone https://github.com/mobilinkd/m17-cxx-demod.git
|
||||
# latest master as of 2020-12-27 (new sync words)
|
||||
cmakebuild m17-cxx-demod 2b84657676efb3b07b33de3ab3d0a6218e9d88b5
|
||||
# latest master as of 2021-04-20
|
||||
cmakebuild m17-cxx-demod c1d954fd5e5c53d28a2524e99484f832f9dcb826
|
||||
|
||||
git clone https://github.com/hessu/aprs-symbols /usr/share/aprs-symbols
|
||||
pushd /usr/share/aprs-symbols
|
||||
git checkout 5c2abe2658ee4d2563f3c73b90c6f59124839802
|
||||
# remove unused files (including git meta information)
|
||||
rm -rf .git aprs-symbols.ai aprs-sym-export.js
|
||||
popd
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
|
@ -18,8 +18,8 @@ function cmakebuild() {
|
||||
|
||||
cd /tmp
|
||||
|
||||
STATIC_PACKAGES="libfftw3-bin"
|
||||
BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++"
|
||||
STATIC_PACKAGES="libfftw3-bin libprotobuf17"
|
||||
BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++ libprotobuf-dev protobuf-compiler"
|
||||
apt-get update
|
||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||
|
||||
@ -40,8 +40,15 @@ make install
|
||||
cd ..
|
||||
rm -rf csdr
|
||||
|
||||
git clone https://github.com/jketterl/codecserver.git
|
||||
mkdir -p /usr/local/etc/codecserver
|
||||
cp codecserver/conf/codecserver.conf /usr/local/etc/codecserver
|
||||
#latest develop as of 2021-07-04 (optional checksum fix)
|
||||
cmakebuild codecserver d73c9a56a773355679bc2d4a10f199b62223d7a0
|
||||
|
||||
git clone https://github.com/jketterl/digiham.git
|
||||
cmakebuild digiham 0.3.0
|
||||
#latest develop as of 2021-06-15 (DMR LCSS overflow fix; D-Star alternate terminator)
|
||||
cmakebuild digiham 418145d74b528596a39198a537ab56207d932595
|
||||
|
||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||
apt-get clean
|
||||
|
@ -1,19 +1,25 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p /etc/openwebrx/
|
||||
mkdir -p /etc/openwebrx/openwebrx.conf.d
|
||||
mkdir -p /var/lib/openwebrx
|
||||
mkdir -p /tmp/openwebrx/
|
||||
if [[ ! -f /etc/openwebrx/config_webrx.py ]] ; then
|
||||
sed 's/temporary_directory = "\/tmp"/temporary_directory = "\/tmp\/openwebrx"/' < "/opt/openwebrx/config_webrx.py" > "/etc/openwebrx/config_webrx.py"
|
||||
if [[ ! -f /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf ]] ; then
|
||||
cat << EOF > /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf
|
||||
[core]
|
||||
temporary_directory = /tmp/openwebrx
|
||||
EOF
|
||||
fi
|
||||
if [[ ! -f /etc/openwebrx/bands.json ]] ; then
|
||||
cp bands.json /etc/openwebrx/
|
||||
fi
|
||||
if [[ ! -f /etc/openwebrx/bookmarks.json ]] ; then
|
||||
cp bookmarks.json /etc/openwebrx/
|
||||
if [[ ! -f /etc/openwebrx/openwebrx.conf ]] ; then
|
||||
cp openwebrx.conf /etc/openwebrx/
|
||||
fi
|
||||
if [[ ! -f /etc/openwebrx/users.json ]] ; then
|
||||
cp users.json /etc/openwebrx/
|
||||
if [[ ! -z "${OPENWEBRX_ADMIN_USER:-}" ]] && [[ ! -z "${OPENWEBRX_ADMIN_PASSWORD:-}" ]] ; then
|
||||
if ! python3 openwebrx.py admin --silent hasuser "${OPENWEBRX_ADMIN_USER}" ; then
|
||||
OWRX_PASSWORD="${OPENWEBRX_ADMIN_PASSWORD}" python3 openwebrx.py admin --noninteractive adduser "${OPENWEBRX_ADMIN_USER}"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
BIN
htdocs/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 17 KiB |
@ -1,14 +1,162 @@
|
||||
@import url("openwebrx-header.css");
|
||||
@import url("openwebrx-globals.css");
|
||||
|
||||
html, body {
|
||||
height: unset;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #222;
|
||||
z-index: 2;
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
border-top: 1px solid #444;
|
||||
}
|
||||
|
||||
.row .map-input {
|
||||
margin: 15px 15px 0;
|
||||
}
|
||||
|
||||
.device {
|
||||
margin-top: 20px;
|
||||
.settings-section h3 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 1em 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.matrix {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.q65-matrix {
|
||||
grid-template-columns: repeat(5, auto);
|
||||
}
|
||||
|
||||
.imageupload .image-container {
|
||||
max-width: 100%;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.imageupload img.webrx-top-photo {
|
||||
max-height: 350px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.settings-grid > div {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.settings-grid .btn {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
padding: 20px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.tab-body {
|
||||
overflow: auto;
|
||||
border: 1px solid #444;
|
||||
border-top: none;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.tab-body .form-group {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.bookmarks table .frequency, .bookmark-list table .frequency {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.bookmarks table input, .bookmarks table select {
|
||||
width: initial;
|
||||
text-align: inherit;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.bookmark-list table .form-check-input {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.actions .btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wsjt-decoding-depths-table {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wsjt-decoding-depths-table td:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.sdr-device-list .list-group-item,
|
||||
.sdr-profile-list .list-group-item {
|
||||
background: initial;
|
||||
}
|
||||
|
||||
.sdr-device-list .sdr-profile-list {
|
||||
max-height: 20rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.removable-group.removable, .add-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.removable-group.removable .removable-item, .add-group .add-group-select {
|
||||
flex: 1 0 auto;
|
||||
margin-right: .25rem;
|
||||
}
|
||||
|
||||
.removable-group.removable .option-remove-button, .add-group .option-add-button {
|
||||
flex: 0 0 70px;
|
||||
}
|
||||
|
||||
.option-add-button, .option-remove-button {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.scheduler-static-time-inputs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.scheduler-static-time-inputs > * {
|
||||
flex: 0 0 auto;
|
||||
width: unset;
|
||||
}
|
||||
|
||||
.scheduler-static-time-inputs > select {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
.imageupload.is-invalid ~ .invalid-feedback {
|
||||
display: block;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
@import url("openwebrx-header.css");
|
||||
@import url("openwebrx-globals.css");
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 50px 0;
|
||||
}
|
@ -1,6 +1,16 @@
|
||||
@import url("openwebrx-header.css");
|
||||
@import url("openwebrx-globals.css");
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
|
@ -6,10 +6,6 @@ body {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#webrx-top-container {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.openwebrx-map {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
@ -5,21 +5,3 @@ html, body
|
||||
height: 100%;
|
||||
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
||||
}
|
||||
|
||||
.sprite {
|
||||
background-image: url(../gfx/openwebrx-sprites.png);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.openwebrx-button.highlighted .sprite {
|
||||
background-image: linear-gradient(rgba(255,127,0,0.5), rgba(255,127,0,0.5)), url(../gfx/openwebrx-sprites.png);
|
||||
background-blend-mode: overlay;
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||
only screen and (min-device-pixel-ratio: 2) {
|
||||
.sprite {
|
||||
background-image: url(../gfx/openwebrx-sprites-2x.png);
|
||||
background-size: 198px 77px;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#webrx-top-container {
|
||||
.webrx-top-container {
|
||||
position: relative;
|
||||
z-index:1000;
|
||||
background-color: #575757;
|
||||
@ -12,7 +12,7 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#openwebrx-description-container {
|
||||
.openwebrx-description-container {
|
||||
transition-property: height, opacity;
|
||||
transition-duration: 1s;
|
||||
transition-timing-function: ease-out;
|
||||
@ -23,12 +23,12 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#openwebrx-description-container.expanded {
|
||||
.openwebrx-description-container.expanded {
|
||||
opacity: 1;
|
||||
height: 283px;
|
||||
}
|
||||
|
||||
.webrx-top-bar-parts {
|
||||
.webrx-top-bar {
|
||||
height:67px;
|
||||
|
||||
background: rgba(128, 128, 128, 0.15);
|
||||
@ -46,26 +46,27 @@
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.webrx-top-bar-parts > * {
|
||||
.webrx-top-bar > * {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
#webrx-top-container, #webrx-top-container * {
|
||||
.webrx-top-container, .webrx-top-container * {
|
||||
line-height: initial;
|
||||
box-sizing: initial;
|
||||
}
|
||||
|
||||
#webrx-top-logo {
|
||||
.webrx-top-logo {
|
||||
width: 261px;
|
||||
padding: 12px;
|
||||
filter: drop-shadow(0 0 2.5px rgba(0, 0, 0, .9));
|
||||
/* overwritten by media queries */
|
||||
display: none;
|
||||
}
|
||||
|
||||
#webrx-rx-avatar {
|
||||
.webrx-rx-avatar {
|
||||
background-color: rgba(154, 154, 154, .5);
|
||||
margin: 7px;
|
||||
|
||||
cursor:pointer;
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
padding: 4px;
|
||||
@ -73,82 +74,66 @@
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
#webrx-rx-texts {
|
||||
.webrx-rx-texts {
|
||||
/* minimum layout width */
|
||||
width: 0;
|
||||
/* will be getting wider with flex */
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
#webrx-rx-texts div {
|
||||
.webrx-rx-texts div, .webrx-rx-texts h1 {
|
||||
margin: 0 10px;
|
||||
padding: 3px;
|
||||
white-space:nowrap;
|
||||
overflow: hidden;
|
||||
cursor:pointer;
|
||||
color: #909090;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#webrx-rx-texts div:first-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#webrx-rx-title {
|
||||
.webrx-rx-title {
|
||||
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
||||
font-size: 11pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#webrx-rx-desc {
|
||||
.webrx-rx-desc {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#openwebrx-rx-details-arrow {
|
||||
cursor:pointer;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
#openwebrx-rx-details-arrow a {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#openwebrx-main-buttons .button {
|
||||
.openwebrx-main-buttons .button {
|
||||
display: block;
|
||||
width: 55px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#openwebrx-main-buttons .button[data-toggle-panel] {
|
||||
.openwebrx-main-buttons .button[data-toggle-panel] {
|
||||
/* will be enabled by javascript if the panel is present in the DOM */
|
||||
display: none;
|
||||
}
|
||||
|
||||
#openwebrx-main-buttons .button img {
|
||||
.openwebrx-main-buttons .button img,
|
||||
.openwebrx-main-buttons .button svg {
|
||||
height: 38px;
|
||||
filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
#openwebrx-main-buttons a {
|
||||
.openwebrx-main-buttons a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
#openwebrx-main-buttons .button:hover {
|
||||
.openwebrx-main-buttons .button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
#openwebrx-main-buttons .button:active {
|
||||
.openwebrx-main-buttons .button:active {
|
||||
background-color: rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
|
||||
#openwebrx-main-buttons {
|
||||
.openwebrx-main-buttons {
|
||||
padding: 5px 15px;
|
||||
display: flex;
|
||||
list-style: none;
|
||||
@ -160,7 +145,7 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#webrx-rx-photo-title {
|
||||
.webrx-rx-photo-title {
|
||||
margin: 10px 15px;
|
||||
color: white;
|
||||
font-size: 16pt;
|
||||
@ -168,7 +153,7 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#webrx-rx-photo-desc {
|
||||
.webrx-rx-photo-desc {
|
||||
margin: 10px 15px;
|
||||
color: white;
|
||||
font-size: 10pt;
|
||||
@ -178,17 +163,21 @@
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
#webrx-rx-photo-desc a {
|
||||
.webrx-rx-photo-desc a {
|
||||
color: #5ca8ff;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.openwebrx-photo-trigger {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Responsive stuff
|
||||
*/
|
||||
|
||||
@media (min-width: 576px) {
|
||||
#webrx-rx-texts {
|
||||
.webrx-rx-texts {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
@ -197,7 +186,7 @@
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
#webrx-top-logo {
|
||||
.webrx-top-logo {
|
||||
display: initial;
|
||||
}
|
||||
}
|
||||
@ -206,47 +195,33 @@
|
||||
}
|
||||
|
||||
/*
|
||||
* Sprites (images)
|
||||
* RX details arrow up/down switching
|
||||
*/
|
||||
|
||||
.sprite-panel-status {
|
||||
background-position: 0 0;
|
||||
width: 44px;
|
||||
height: 38px;
|
||||
.openwebrx-rx-details-arrow {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sprite-panel-log {
|
||||
background-position: -44px 0;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-panel-receiver {
|
||||
background-position: -82px 0;
|
||||
width: 40px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-panel-map {
|
||||
background-position: -122px 0;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-panel-settings {
|
||||
background-position: -160px 0;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.sprite-rx-details-arrow-down {
|
||||
background-position: 0 -65px;
|
||||
width: 43px;
|
||||
.openwebrx-rx-details-arrow svg {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.sprite-rx-details-arrow-up {
|
||||
background-position: -43px -65px;
|
||||
width: 43px;
|
||||
height: 12px;
|
||||
.openwebrx-rx-details-arrow .up {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.openwebrx-rx-details-arrow--up .down {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.openwebrx-rx-details-arrow--up .up {
|
||||
display: initial;
|
||||
}
|
@ -36,15 +36,14 @@ input
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
input[type=range]
|
||||
{
|
||||
input[type=range] {
|
||||
-webkit-appearance: none;
|
||||
margin: 0 0;
|
||||
background: transparent;
|
||||
background: transparent !important;
|
||||
--track-background: #B6B6B6;
|
||||
}
|
||||
input[type=range]:focus
|
||||
{
|
||||
|
||||
input[type=range]:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@ -297,11 +296,13 @@ input[type=range]:disabled {
|
||||
#webrx-canvas-container canvas
|
||||
{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
border-style: none;
|
||||
image-rendering: crisp-edges;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
#openwebrx-log-scroll
|
||||
@ -336,12 +337,58 @@ input[type=range]:disabled {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.webrx-actual-freq > * {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.webrx-actual-freq .input-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.webrx-actual-freq .input-group > * {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.webrx-actual-freq .input-group input {
|
||||
flex: 1 0 auto;
|
||||
margin-right: 0;
|
||||
border-right: 1px solid #373737;
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.webrx-actual-freq .input-group input::-webkit-outer-spin-button,
|
||||
.webrx-actual-freq .input-group input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input-group > :not(:last-child) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.input-group > :not(:first-child) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.input-group :first-child {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.input-group :last-child {
|
||||
padding-right: 5px
|
||||
}
|
||||
|
||||
.webrx-actual-freq .input-group input, .webrx-actual-freq .input-group select {
|
||||
outline: none;
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
.webrx-actual-freq input {
|
||||
font-family: 'roboto-mono';
|
||||
width: 0;
|
||||
@ -355,7 +402,10 @@ input[type=range]:disabled {
|
||||
.webrx-actual-freq, .webrx-actual-freq input {
|
||||
font-size: 16pt;
|
||||
font-family: 'roboto-mono';
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.webrx-actual-freq .digit {
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
.webrx-actual-freq .digit:hover {
|
||||
@ -552,6 +602,7 @@ img.openwebrx-mirror-img
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
overflow: hidden;
|
||||
z-index: 1
|
||||
}
|
||||
|
||||
.openwebrx-progressbar-bar {
|
||||
@ -564,6 +615,7 @@ img.openwebrx-mirror-img
|
||||
transition-timing-function: ease-in-out;
|
||||
transform: translate(-100%) translateZ(0);
|
||||
will-change: transform, background-color;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.openwebrx-progressbar--over .openwebrx-progressbar-bar {
|
||||
@ -573,11 +625,11 @@ img.openwebrx-mirror-img
|
||||
.openwebrx-progressbar-text
|
||||
{
|
||||
position: absolute;
|
||||
left:50;
|
||||
left:50%;
|
||||
top:50%;
|
||||
transform: translate(-50%, -50%);
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#openwebrx-panel-status
|
||||
@ -602,6 +654,7 @@ img.openwebrx-mirror-img
|
||||
#openwebrx-panel-receiver .frequencies-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
#openwebrx-panel-receiver .frequencies {
|
||||
@ -614,16 +667,6 @@ img.openwebrx-mirror-img
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#openwebrx-mute-on
|
||||
{
|
||||
color: lime;
|
||||
}
|
||||
|
||||
#openwebrx-mute-off
|
||||
{
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openwebrx-panel-slider
|
||||
{
|
||||
position: relative;
|
||||
@ -631,13 +674,6 @@ img.openwebrx-mirror-img
|
||||
width: 95px;
|
||||
}
|
||||
|
||||
.openwebrx-sliderbtn-img
|
||||
{
|
||||
width: 14px;
|
||||
position:relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.openwebrx-panel-line
|
||||
{
|
||||
padding-top: 5px;
|
||||
@ -714,19 +750,19 @@ img.openwebrx-mirror-img
|
||||
}
|
||||
|
||||
.openwebrx-overlay {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
opacity: 0.8;
|
||||
background-color: #777;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1001;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 20pt;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
opacity: 0.8;
|
||||
background-color: #777;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1001;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 20pt;
|
||||
}
|
||||
|
||||
#openwebrx-autoplay-overlay
|
||||
@ -735,8 +771,7 @@ img.openwebrx-mirror-img
|
||||
transition: opacity 0.3s linear;
|
||||
}
|
||||
|
||||
#openwebrx-autoplay-overlay img
|
||||
{
|
||||
#openwebrx-autoplay-overlay svg {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
@ -768,11 +803,14 @@ img.openwebrx-mirror-img
|
||||
#openwebrx-digimode-canvas-container canvas
|
||||
{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
pointer-events: none;
|
||||
transition: width 500ms, left 500ms;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.openwebrx-panel select,
|
||||
.openwebrx-panel input,
|
||||
.openwebrx-dialog select,
|
||||
.openwebrx-dialog input {
|
||||
border-radius: 5px;
|
||||
@ -781,11 +819,26 @@ img.openwebrx-mirror-img
|
||||
font-weight: normal;
|
||||
font-size: 13pt;
|
||||
margin-right: 1px;
|
||||
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.0 , #373737), color-stop(1, #4F4F4F) );
|
||||
background:-moz-linear-gradient( center top, #373737 0%, #4F4F4F 100% );
|
||||
background:linear-gradient(#373737, #4F4F4F);
|
||||
border-color: transparent;
|
||||
border-width: 0px;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
@supports(-moz-appearance: none) {
|
||||
.openwebrx-panel select,
|
||||
.openwebrx-dialog select {
|
||||
-moz-appearance: none;
|
||||
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%20%20xmlns%3Av%3D%22https%3A%2F%2Fvecta.io%2Fnano%22%3E%3Cpath%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8s-1.9-9.2-5.5-12.8z%22%20fill%3D%22%23fff%22%2F%3E%3C%2Fsvg%3E'),
|
||||
linear-gradient(#373737, #4F4F4F);
|
||||
background-repeat: no-repeat, repeat;
|
||||
background-position: right .3em top 50%, 0 0;
|
||||
background-size: .65em auto, 100%;
|
||||
}
|
||||
|
||||
.openwebrx-panel .input-group select,
|
||||
.openwebrx-dialog .input-group select {
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.openwebrx-panel select option,
|
||||
@ -912,6 +965,8 @@ img.openwebrx-mirror-img
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
/* compatibility with iOS 14.2 */
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot {
|
||||
@ -928,26 +983,22 @@ img.openwebrx-mirror-img
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot > * {
|
||||
flex: 0;
|
||||
flex-basis: 1.2em;
|
||||
flex: 1 0 0;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot, .openwebrx-meta-slot.muted:before {
|
||||
.openwebrx-meta-slot, .openwebrx-meta-slot .mute {
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.muted:before {
|
||||
display: block;
|
||||
content: "";
|
||||
background-image: url("../gfx/openwebrx-mute.png");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
.openwebrx-meta-slot .mute {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
|
||||
position: absolute;
|
||||
@ -958,6 +1009,17 @@ img.openwebrx-mirror-img
|
||||
background-color: rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot .mute svg {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.muted .mute {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.active {
|
||||
background-color: #95bbdf;
|
||||
}
|
||||
@ -974,18 +1036,29 @@ img.openwebrx-mirror-img
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot .openwebrx-meta-user-image {
|
||||
flex: 1;
|
||||
flex: 0 1 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
line-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image,
|
||||
#openwebrx-panel-metadata-ysf .openwebrx-meta-slot.active .openwebrx-meta-user-image {
|
||||
background-image: url("../gfx/openwebrx-directcall.png");
|
||||
.openwebrx-meta-slot .openwebrx-meta-user-image img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.active.group .openwebrx-meta-user-image {
|
||||
background-image: url("../gfx/openwebrx-groupcall.png");
|
||||
.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image .directcall,
|
||||
.openwebrx-meta-slot.active.individual .openwebrx-meta-user-image .directcall,
|
||||
#openwebrx-panel-metadata-ysf .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall,
|
||||
#openwebrx-panel-metadata-dstar .openwebrx-meta-slot.active .openwebrx-meta-user-image .directcall {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.active.group .openwebrx-meta-user-image .groupcall,
|
||||
.openwebrx-meta-slot.active.conference .openwebrx-meta-user-image .groupcall {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.group .openwebrx-dmr-target:not(:empty):before {
|
||||
@ -998,6 +1071,7 @@ img.openwebrx-mirror-img
|
||||
|
||||
.openwebrx-dmr-timeslot-panel * {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.openwebrx-ysf-mode:not(:empty):before {
|
||||
@ -1012,14 +1086,30 @@ img.openwebrx-mirror-img
|
||||
content: "Down: ";
|
||||
}
|
||||
|
||||
.openwebrx-maps-pin {
|
||||
background-image: url("../gfx/google_maps_pin.svg");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
.openwebrx-dstar-yourcall:not(:empty):before {
|
||||
content: "UR: ";
|
||||
}
|
||||
|
||||
.openwebrx-dstar-departure:not(:empty):before {
|
||||
content: "RPT1: ";
|
||||
}
|
||||
|
||||
.openwebrx-dstar-destination:not(:empty):before {
|
||||
content: "RPT2: ";
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.individual .openwebrx-nxdn-destination:not(:empty):before {
|
||||
content: "Direct: ";
|
||||
}
|
||||
|
||||
.openwebrx-meta-slot.conference .openwebrx-nxdn-destination:not(:empty):before {
|
||||
content: "Conference: ";
|
||||
}
|
||||
|
||||
.openwebrx-maps-pin svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
background-size: contain;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.openwebrx-message-panel {
|
||||
@ -1192,6 +1282,7 @@ img.openwebrx-mirror-img
|
||||
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-content-container,
|
||||
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-content-container,
|
||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-content-container,
|
||||
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-content-container,
|
||||
#openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-select-channel,
|
||||
@ -1201,7 +1292,8 @@ img.openwebrx-mirror-img
|
||||
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-select-channel
|
||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-select-channel,
|
||||
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-select-channel
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
@ -1215,81 +1307,58 @@ img.openwebrx-mirror-img
|
||||
#openwebrx-panel-digimodes[data-mode="pocsag"] #openwebrx-digimode-canvas-container,
|
||||
#openwebrx-panel-digimodes[data-mode="js8"] #openwebrx-digimode-canvas-container,
|
||||
#openwebrx-panel-digimodes[data-mode="fst4"] #openwebrx-digimode-canvas-container,
|
||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-canvas-container
|
||||
#openwebrx-panel-digimodes[data-mode="fst4w"] #openwebrx-digimode-canvas-container,
|
||||
#openwebrx-panel-digimodes[data-mode="q65"] #openwebrx-digimode-canvas-container
|
||||
{
|
||||
height: 200px;
|
||||
margin: -10px;
|
||||
}
|
||||
|
||||
.sprite-zoom-in {
|
||||
background-position: 0 -38px;
|
||||
width: 27px;
|
||||
.openwebrx-zoom-button svg {
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
.sprite-zoom-out {
|
||||
background-position: -27px -38px;
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
.sprite-zoom-in-total {
|
||||
background-position: -54px -38px;
|
||||
width: 24px;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
.sprite-zoom-out-total {
|
||||
background-position: -78px -38px;
|
||||
width: 25px;
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
.sprite-edit {
|
||||
background-position: -131px -51px;
|
||||
width: 14px;
|
||||
.openwebrx-slider-button svg {
|
||||
position:relative;
|
||||
top: 1px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.sprite-trashcan {
|
||||
background-position: -145px -38px;
|
||||
width: 14px;
|
||||
.openwebrx-mute-button svg.muted {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.openwebrx-mute-button.muted svg.muted {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.openwebrx-mute-button.muted svg.unmuted {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bookmark .bookmark-actions .openwebrx-button svg {
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.sprite-speaker {
|
||||
width: 14px;
|
||||
height: 15px;
|
||||
#openwebrx-waterfall-colors-auto .continuous {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.openwebrx-mute-button .sprite-speaker {
|
||||
background-position: -103px -38px;
|
||||
#openwebrx-waterfall-colors-auto.highlighted .continuous {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.openwebrx-mute-button.muted .sprite-speaker {
|
||||
background-position: -117px -38px;
|
||||
#openwebrx-waterfall-colors-auto.highlighted .auto {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sprite-squelch {
|
||||
background-position: -131px -38px;
|
||||
width: 14px;
|
||||
height: 13px;
|
||||
.openwebrx-waterfall-container {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sprite-waterfall-auto {
|
||||
background-position: -103px -53px;
|
||||
width: 14px;
|
||||
height: 11px;
|
||||
}
|
||||
|
||||
.sprite-waterfall-default {
|
||||
background-position: -117px -53px;
|
||||
width: 14px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.sprite-bookmark {
|
||||
background-position: -159px -38px;
|
||||
width: 21px;
|
||||
height: 27px;
|
||||
.openwebrx-waterfall-container > * {
|
||||
flex: 0 0 auto;
|
||||
}
|
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 5.3 KiB |
@ -3,7 +3,6 @@
|
||||
<link rel="shortcut icon" type="image/x-icon" href="static/favicon.ico" />
|
||||
<link rel="stylesheet" href="static/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="static/css/admin.css" />
|
||||
<link rel="stylesheet" href="static/css/features.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.0/showdown.min.js"></script>
|
||||
<script src="static/lib/jquery-3.2.1.min.js"></script>
|
||||
<script src="static/lib/Header.js"></script>
|
||||
@ -11,6 +10,7 @@
|
||||
</HEAD><BODY>
|
||||
${header}
|
||||
<div class="container">
|
||||
${breadcrumb}
|
||||
<h1>OpenWebRX Feature Report</h1>
|
||||
<table class="features table">
|
||||
<tr>
|
||||
@ -20,5 +20,6 @@
|
||||
<th>Available</th>
|
||||
</tr>
|
||||
</table>
|
||||
${breadcrumb}
|
||||
</div>
|
||||
</BODY></HTML>
|
@ -13,8 +13,7 @@ $(function(){
|
||||
});
|
||||
$table.append(
|
||||
'<tr>' +
|
||||
'<td colspan=2>' + name + '</td>' +
|
||||
'<td>' + converter.makeHtml(details.description) + '</td>' +
|
||||
'<td colspan=3>' + name + '</td>' +
|
||||
'<td>' + (details.available ? 'YES' : 'NO') + '</td>' +
|
||||
'</tr>' +
|
||||
requirements.join("")
|
||||
|
@ -1,20 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenWebRX Settings</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="static/favicon.ico" />
|
||||
<link rel="stylesheet" href="static/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="static/css/admin.css" />
|
||||
<script src="https://unpkg.com/location-picker/dist/location-picker.min.js"></script>
|
||||
<script src="compiled/settings.js"></script>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
${header}
|
||||
<div class="container">
|
||||
<div class="col-12">
|
||||
<h1>General settings</h1>
|
||||
</div>
|
||||
${sections}
|
||||
</div>
|
||||
</body>
|
BIN
htdocs/gfx/favicon128.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
htdocs/gfx/favicon32.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
htdocs/gfx/favicon44.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
htdocs/gfx/favicon64.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
htdocs/gfx/favicon96.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 679 B |
Before Width: | Height: | Size: 970 B |
Before Width: | Height: | Size: 5.3 KiB |
1
htdocs/gfx/openwebrx-directcall.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg"><defs><filter id="a" x="-.25" y="-.25" width="1.5" height="1.5" color-interpolation-filters="sRGB"><feFlood flood-color="#000" flood-opacity=".4" result="flood"/><feComposite in="flood" in2="SourceGraphic" operator="in" result="composite1"/><feGaussianBlur in="composite1" result="blur" stdDeviation="66.6"/><feOffset result="offset"/><feComposite in="SourceGraphic" in2="offset" result="composite2"/></filter></defs><path d="M550.98 541.91c-.99-28.904-4.377-57.939-9.421-86.393-6.111-34.469-13.889-85.002-43.983-107.46-17.404-12.988-39.941-17.249-59.865-25.081-9.697-3.81-18.384-7.594-26.537-11.901-27.518 30.176-63.4 45.962-105.19 45.964-41.774 0-77.652-15.786-105.17-45.964-8.153 4.308-16.84 8.093-26.537 11.901-19.924 7.832-42.461 12.092-59.863 25.081-30.096 22.463-37.873 72.996-43.983 107.46-5.045 28.454-8.433 57.489-9.422 86.393-.766 22.387 10.288 25.525 29.017 32.284 23.453 8.458 47.666 14.737 72.041 19.884 47.077 9.941 95.603 17.582 143.92 17.924 48.318-.343 96.844-7.983 143.92-17.924 24.375-5.145 48.59-11.424 72.041-19.884 18.736-6.757 29.789-9.895 29.023-32.284zM306 325.99c90.56-.01 123.15-90.68 131.68-165.17C448.19 69.06 404.8 0 306 0c-98.78 0-142.19 69.055-131.68 160.82C182.86 235.304 215.434 326 306 325.99z" filter="url(#a)" transform="matrix(.42446 0 0 .42484 70.12 69)" fill="#fff"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 8.1 KiB |
1
htdocs/gfx/openwebrx-groupcall.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg"><defs><filter id="a" x="-.25" y="-.25" width="1.5" height="1.5" color-interpolation-filters="sRGB"><feFlood flood-color="#000" flood-opacity=".4" result="flood"/><feComposite in="flood" in2="SourceGraphic" operator="in" result="composite1"/><feGaussianBlur in="composite1" result="blur" stdDeviation="66.6"/><feOffset result="offset"/><feComposite in="SourceGraphic" in2="offset" result="composite2"/></filter></defs><g fill="#fff"><g transform="matrix(.42446 0 0 .42484 129.12 42)" filter="url(#a)"><path d="M27.982.002c-98.778 0-142.188 69.056-131.678 160.823 8.54 74.484 41.112 165.183 131.678 165.173 90.558-.01 123.148-90.682 131.678-165.173C170.17 69.063 126.781.002 27.982.002zm277.996 0C207.2.002 163.79 69.058 174.3 160.825c8.54 74.484 41.113 165.183 131.678 165.173 90.559-.01 123.148-90.682 131.678-165.173C448.166 69.063 404.777.002 305.978.002zM-77.209 311.093c-8.153 4.308-16.84 8.09-26.537 11.898-19.924 7.833-42.463 12.095-59.863 25.084-30.095 22.463-37.871 72.996-43.98 107.46-5.045 28.454-8.435 57.492-9.424 86.395-.766 22.388 10.288 25.523 29.015 32.284 23.453 8.458 47.665 14.737 72.04 19.884 47.075 9.941 95.6 17.583 143.916 17.925 46.64-.33 93.461-7.487 138.998-16.923 45.538 9.437 92.359 16.593 138.999 16.923 48.317-.343 96.841-7.984 143.917-17.925 24.374-5.145 48.593-11.424 72.043-19.884 18.736-6.757 29.786-9.894 29.02-32.284h.01c-.99-28.903-4.38-57.941-9.424-86.395-6.111-34.47-13.886-85.002-43.98-107.46-17.404-12.989-39.94-17.252-59.863-25.084-9.697-3.81-18.384-7.59-26.537-11.898-27.517 30.177-63.398 45.962-105.186 45.965-41.773 0-77.65-15.787-105.17-45.965-8.153 4.308-16.84 8.09-26.537 11.898-2.394.941-4.828 1.826-7.284 2.685-2.456-.859-4.89-1.744-7.284-2.685-9.697-3.81-18.383-7.59-26.537-11.898-27.517 30.177-63.397 45.962-105.186 45.965-41.773 0-77.65-15.787-105.17-45.965z"/></g><g transform="matrix(.42446 0 0 .42484 70.12 102)" filter="url(#a)"><path d="M550.98 541.91c-.99-28.904-4.377-57.939-9.421-86.393-6.111-34.469-13.889-85.002-43.983-107.46-17.404-12.988-39.941-17.249-59.865-25.081-9.697-3.81-18.384-7.594-26.537-11.901-27.518 30.176-63.4 45.962-105.19 45.964-41.774 0-77.652-15.786-105.17-45.964-8.153 4.308-16.84 8.093-26.537 11.901-19.924 7.832-42.461 12.092-59.863 25.081-30.096 22.463-37.873 72.996-43.983 107.46-5.045 28.454-8.433 57.489-9.422 86.393-.766 22.387 10.288 25.525 29.017 32.284 23.453 8.458 47.666 14.737 72.041 19.884 47.077 9.941 95.603 17.582 143.92 17.924 48.318-.343 96.844-7.983 143.92-17.924 24.375-5.145 48.59-11.424 72.041-19.884 18.736-6.757 29.789-9.895 29.023-32.284zM306 325.99c90.56-.01 123.15-90.68 131.68-165.17C448.19 69.06 404.8 0 306 0c-98.78 0-142.19 69.055-131.68 160.82C182.86 235.304 215.434 326 306 325.99z"/></g></g></svg>
|
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 518 B |
Before Width: | Height: | Size: 505 B |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 699 B |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 797 B |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.5 KiB |
28
htdocs/gfx/svg-defs.svg
Normal file
@ -0,0 +1,28 @@
|
||||
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<g id="top-logo"><g fill="none" stroke="#fff" stroke-linecap="square" stroke-linejoin="round" stroke-width="6"><path d="M517.23 68.215a35.5 33.2 0 0 1-11.936-26.458 35.5 33.2 0 0 1 14.593-25.266M561.62 16.49a35.5 33.2 0 0 1 14.593 25.266 35.5 33.2 0 0 1-11.936 26.458M551.57 29.079a18.4 19 0 0 1 7.564 14.46 18.4 19 0 0 1-6.187 15.142M528.56 58.681a18.4 19 0 0 1-6.187-15.142 18.4 19 0 0 1 7.564-14.46"/></g><g fill="none"><path d="M540.75 40.25v41.5h-322v-.5h322" stroke="#fff" stroke-width="4.5"/><path d="M13 81.5h58zm76 0h128z" stroke="#ccc" stroke-width="5"/></g><g aria-label="OpenWebRX"><path d="M207.85 45.906c0-11.755-5.104-17.787-14.771-17.787-5.877 0-10.363 2.475-13.688 7.579v-6.574h-6.96v42.301h6.96V47.53c0-8.352 4.717-13.379 12.141-13.379 6.264 0 9.357 4.022 9.357 11.987v25.288h6.96zm-53.515.619h-24.747c.696-7.966 5.645-12.528 13.301-12.528 6.805 0 11.368 4.794 11.445 12.528zm6.96 2.01c0-12.683-7.192-20.416-18.483-20.416-12.605 0-20.725 8.662-20.725 22.581 0 13.301 8.352 21.808 21.963 21.808 5.336 0 10.595-1.082 15.621-3.248v-6.573c-4.872 2.63-9.821 3.944-15.235 3.944-9.203 0-14.461-5.104-15.08-14.693h31.939zm-54.907 1.78c0 10.44-4.64 16.394-11.832 16.394-7.192 0-11.832-5.955-11.832-16.395s4.64-16.395 11.832-16.395c7.192 0 11.832 5.955 11.832 16.395zm-23.664 14.77c2.939 5.027 7.347 7.424 13.533 7.424 10.053 0 17.323-8.661 17.323-22.195S106.31 28.12 96.257 28.12c-6.187 0-10.595 2.397-13.533 7.424v-6.419h-6.96v58.387h6.96zm-44.389-51.04c-15.699 0-26.139 11.291-26.139 29.232 0 18.02 10.44 29.232 26.139 29.232s26.061-11.29 26.061-29.232-10.363-29.232-26.061-29.232zm0 6.187c10.827 0 18.019 8.506 18.019 23.045s-7.192 23.045-18.019 23.045-18.096-8.507-18.096-23.045 7.27-23.045 18.096-23.045z" fill="#ccc"/><path d="m480.99 42.658 18.792-27.608h-15.235l-12.296 18.173-12.373-18.173h-15.157l18.792 27.608-19.565 28.768h15.235l13.069-19.256 13.147 19.256h15.157zm-76.405 7.424h4.099c5.026 0 7.269 2.01 9.898 7.347l6.883 13.997h15.467l-7.888-16.008c-2.939-5.955-5.8-9.358-10.13-10.363 7.268-2.243 10.826-7.038 10.826-14.461 0-10.904-6.883-15.544-21.499-15.544h-22.195v56.376h14.54zm6.11-10.053h-6.11V25.568h6.11c5.954 0 8.506 1.933 8.506 7.192s-2.552 7.27-8.507 7.27zm-62.873-4.485V12.653h-6.96v58.773h6.96v-6.342c2.939 5.027 7.347 7.424 13.533 7.424 10.053 0 17.323-8.66 17.323-22.195s-7.269-22.195-17.323-22.195c-6.186 0-10.595 2.398-13.533 7.424zm23.664 14.77c0 10.44-4.64 16.396-11.832 16.396s-11.832-5.955-11.832-16.395 4.64-16.395 11.832-16.395 11.832 5.954 11.832 16.395zm-48.72-3.789H298.02c.696-7.965 5.646-12.528 13.301-12.528 6.806 0 11.368 4.795 11.445 12.528zm6.96 2.011c0-12.683-7.192-20.416-18.483-20.416-12.605 0-20.725 8.661-20.725 22.581 0 13.301 8.352 21.808 21.963 21.808 5.336 0 10.595-1.083 15.621-3.248v-6.573c-4.872 2.63-9.821 3.944-15.235 3.944-9.202 0-14.46-5.104-15.08-14.693h31.94zm-112.75-33.485 14.152 56.376h9.59l11.987-48.952 11.909 48.952h9.589l14.152-56.376h-7.733L268.79 62.688l-11.832-47.637h-8.584l-11.832 47.637-11.832-47.637z" fill="#fff"/></g></g>
|
||||
<g id="panel-log" stroke="#fff"><g fill="none" stroke-linecap="round" stroke-width="3.5"><path d="M21 57h39M21 48.5h39M21 40h34M21 31.5h39M21 23h39"/></g><g fill="#fff" stroke-linejoin="round" stroke-width="2.1"><path d="M13.5 63.5c0 2.5 2.5 5 5 5h45c2.5 0 5-2.5 5-5v-46c0-2.5-2.5-5-5-5H25l-11.5 16z" fill-opacity=".35" style="mix-blend-mode:normal"/><path d="M25 12.5s-1.323 7.847 4 15c-9.294-1.268-15.5 1-15.5 1"/></g></g>
|
||||
<g id="panel-status" fill="#fff" stroke="#fff" stroke-linejoin="round" stroke-width="2.1"><g fill-opacity=".35"><path d="M9.683 26.483c-3.13 0-5.666-2.455-5.666-5.483 0-3.029 2.536-5.484 5.666-5.484h48.634c3.13 0 5.666 2.455 5.666 5.484 0 3.028-2.537 5.483-5.666 5.483zM19.113 44.913c-3.13 0-5.666-2.455-5.666-5.483s2.537-5.484 5.666-5.484h48.634c3.13 0 5.666 2.455 5.666 5.484s-2.537 5.483-5.666 5.483zM9.683 63.483c-3.13 0-5.666-2.455-5.666-5.483s2.536-5.484 5.666-5.484h48.634c3.13 0 5.666 2.455 5.666 5.484s-2.537 5.483-5.666 5.483z"/></g><path d="M10.06 26.456c-3.322 0-6.016-2.443-6.016-5.456 0-3.013 2.694-5.456 6.016-5.456h5.932c3.322 0 6.016 2.443 6.016 5.456 0 3.013-2.694 5.456-6.016 5.456zM19.48 44.886c-3.317 0-6.007-2.443-6.007-5.456 0-3.013 2.69-5.456 6.007-5.456h32.516c3.317 0 6.007 2.443 6.007 5.456 0 3.014-2.69 5.456-6.007 5.456zM10.052 63.456c-3.318 0-6.008-2.443-6.008-5.456 0-3.013 2.69-5.456 6.008-5.456h24.944c3.318 0 6.008 2.443 6.008 5.456 0 3.013-2.69 5.456-6.008 5.456z"/></g>
|
||||
<g id="panel-receiver" stroke="#fff" stroke-width="2.1"><path d="M66 29.05 12 10" fill="none" stroke-linecap="round" stroke-linejoin="round"/><rect x="6.8" y="29.05" width="67.5" height="38.5" rx="5" ry="5" fill="#fff" fill-opacity=".35"/><g fill="#fff" stroke-linecap="round" stroke-linejoin="round" fill-opacity=".35"><rect x="12.3" y="34.05" width="28.5" height="9.5" rx="2" ry="2"/><circle cx="56.55" cy="48.55" r="13.5"/><g transform="translate(0 -.5)"><circle cx="17.05" cy="50.55" r="3"/><circle cx="26.3" cy="50.55" r="3"/><circle cx="35.55" cy="50.55" r="3"/><circle cx="17.05" cy="57.05" r="3"/><circle cx="26.3" cy="57.05" r="3"/><circle cx="35.55" cy="57.05" r="3"/></g></g></g>
|
||||
<g id="panel-map" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.1"><g stroke-opacity=".989"><path d="m30 11-19 8v50l19-5 19 5 20-5V11l-10.844 4.879a11.93 11.93 0 0 1 2.394 7.172c0 2.111-.55 4.09-1.507 5.814h.004L49 47 38.279 29.256h.013a11.922 11.922 0 0 1-1.742-6.205c0-2.905 1.034-5.568 2.752-7.644z" fill="#fff" fill-opacity=".35"/><g fill="none"><path d="M30 11v53M49 47v22M11 59l19-25 19 18 20-6"/></g></g><circle cx="48.55" cy="23.05" r="6.5" fill="none" stroke-opacity=".989"/><path d="M48.551 11.051c-6.627 0-12 5.373-12 12 0 2.274.643 4.393 1.742 6.205h-.013L49 47l10.048-18.135h-.004a11.935 11.935 0 0 0 1.507-5.814c0-6.628-5.372-12-12-12z" fill="#fff" fill-opacity=".2"/></g>
|
||||
<g id="panel-settings" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6"><path d="m39.855 10-1 .021c-1.041.04-2.078.134-3.11.282-.546.078-.853.587-.78 1.135a7.876 7.876 0 0 1-.022 1.841 6.504 6.504 0 0 1-5.428 5.428 7.889 7.889 0 0 1-1.992 0 6.501 6.501 0 0 1-4.156-2.463c-.336-.437-.916-.581-1.358-.25a29.998 29.998 0 0 0-6.017 6.016c-.331.442-.188 1.02.25 1.355a6.505 6.505 0 0 1 2.465 4.158 7.885 7.885 0 0 1 0 1.993 6.504 6.504 0 0 1-5.428 5.427 7.862 7.862 0 0 1-1.992-.002c-.461-.072-.904.256-.983.803a30.012 30.012 0 0 0-.002 8.51c.079.547.588.853 1.135.781a7.876 7.876 0 0 1 1.842.022 6.504 6.504 0 0 1 5.428 5.427 7.889 7.889 0 0 1 0 1.992 6.501 6.501 0 0 1-2.463 4.157c-.438.336-.581.915-.25 1.357a29.998 29.998 0 0 0 6.015 6.018c.442.33 1.02.187 1.356-.25a6.505 6.505 0 0 1 4.158-2.465 7.885 7.885 0 0 1 1.992 0 6.504 6.504 0 0 1 5.428 5.428 7.862 7.862 0 0 1-.002 1.992c-.072.46.256.904.803.982a30.012 30.012 0 0 0 8.51.002c.546-.078.853-.59.78-1.136a7.859 7.859 0 0 1 .022-1.84 6.504 6.504 0 0 1 5.428-5.428 7.889 7.889 0 0 1 1.992 0 6.501 6.501 0 0 1 4.156 2.463c.336.437.916.581 1.358.25a29.998 29.998 0 0 0 6.017-6.016c.331-.442.188-1.02-.25-1.355a6.505 6.505 0 0 1-2.465-4.158 7.885 7.885 0 0 1 0-1.993 6.504 6.504 0 0 1 5.428-5.427 7.862 7.862 0 0 1 1.992.002c.461.072.904-.258.983-.805a29.977 29.977 0 0 0 .002-8.508c-.079-.546-.59-.853-1.137-.781a7.859 7.859 0 0 1-1.84-.022 6.504 6.504 0 0 1-5.427-5.427 7.889 7.889 0 0 1 0-1.992 6.501 6.501 0 0 1 2.462-4.157c.438-.336.582-.915.25-1.357a29.998 29.998 0 0 0-6.015-6.018c-.442-.33-1.02-.187-1.356.25a6.505 6.505 0 0 1-4.158 2.465 7.885 7.885 0 0 1-1.992 0 6.504 6.504 0 0 1-5.428-5.428 7.862 7.862 0 0 1 .002-1.992c.072-.46-.256-.904-.803-.982a30.002 30.002 0 0 0-4.4-.305zM40 26.5A13.5 13.5 0 0 1 53.5 40 13.5 13.5 0 0 1 40 53.5 13.5 13.5 0 0 1 26.5 40 13.5 13.5 0 0 1 40 26.5z" fill="#fff" fill-opacity=".35"/><circle cx="40" cy="40" r="13.5" fill="#fff" fill-opacity=".2"/><circle cx="40" cy="40" r="8" fill="none"/></g>
|
||||
<g id="zoom-in" stroke="#fff"><circle cx="31.75" cy="32" r="27.5" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"/><path d="m57.147 47.242 20.644 20.645a4 4 90 0 1 0 5.657l-3.748 3.748a4 4 180 0 1-5.656 0L47.743 56.647" fill="#fff" stroke-width="2.1"/><path d="M31.75 18.5v27M18.25 32h27" fill="none" stroke-linecap="round" stroke-width="10"/></g>
|
||||
<g id="zoom-out" stroke="#fff"><circle cx="31.75" cy="32" r="27.5" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="8"/><path d="m57.147 47.242 20.644 20.645a4 4 90 0 1 0 5.657l-3.748 3.748a4 4 180 0 1-5.656 0L47.743 56.647" fill="#fff" stroke-width="2.1"/><path d="M18.25 32h27" fill="none" stroke-linecap="round" stroke-width="10"/></g>
|
||||
<g id="zoom-out-total" stroke="#fff"><circle cx="44.001" cy="51.307" r="16.326" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="4.75"/><path d="M59.079 60.356 71.6 72.877a2 2 90 0 1 0 2.829l-2.755 2.754a2 2 180 0 1-2.828 0L53.496 65.94" fill="#fff" stroke-width="1.247"/><path d="m20.893 1.244-16.199 16.9 16.199 16.9V21.698H59.5v13.346l16.199-16.9L59.5 1.244V14.7H20.893z" fill="#fff"/></g>
|
||||
<g id="zoom-in-total" stroke="#fff"><circle cx="44.701" cy="51.307" r="16.326" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="4.75"/><path d="M59.779 60.356 72.3 72.877a2 2 90 0 1 0 2.829l-2.755 2.754a2 2-180 0 1-2.828 0L54.196 65.94" fill="#fff" stroke-width="1.247"/><path d="M4.8 1.244v33.801L17.595 21.7H62.4l12.793 13.346v-33.8L62.296 14.698H17.698z" fill="#fff"/></g>
|
||||
<g id="speaker" stroke="#fff"><path d="M33.5 7.15 16.74 25.201H2.65v31.7h16.041L33.5 72.848z" fill="#fff" stroke-width="2.1"/><g fill="none"><path d="M46.336 16.041A20 30 0 0 1 54.3 40a20 30 0 0 1-7.964 23.959" stroke-width="3"/><path d="M52.716 9.652A30.6 38 0 0 1 64.9 40a30.6 38 0 0 1-12.184 30.348" stroke-width="4.2"/><path d="M59.035 2.065A41.1 47.5 0 0 1 75.4 40a41.1 47.5 0 0 1-16.365 37.935" stroke-width="5.4"/></g></g>
|
||||
<g id="speaker-muted"><path d="M33.5 7.15 16.74 25.201H2.65v31.7h16.041L33.5 72.848z" fill="#fff" stroke="#fff" stroke-width="2.1"/></g>
|
||||
<g id="waterfall-auto"><path d="M33.512 72.05s3.393-64.129 8.24-64.093c4.48.034 4.392 28.286 9.98 28.198 4.775-.074 5.279-13.721 6.33-17.88 1.013-4.004 2.915-5.172 5.321-4.894 2.993.346 8.205 5.925 10.588 13.761 4.16 13.677 5.53 44.907 5.53 44.907z" fill="#ccc" stroke="#ccc"/><path d="M29.3 68.8 18.4 54 7.5 68.8zM7.5 11.2 18.4 26l10.9-14.8zM18.4 26v28" fill="#fff" stroke="#fff" stroke-width="7.5"/></g>
|
||||
<g id="waterfall-default"><path d="M36.356 75.295s3.187-34.502 7.74-34.482c4.207.018 4.125 15.218 9.374 15.171 4.485-.04 4.958-7.382 5.945-9.62.951-2.154 2.738-2.782 4.998-2.632 2.812.186 7.707 3.187 9.945 7.403 3.906 7.358 5.193 24.16 5.193 24.16z" fill="#ccc" stroke="#ccc" stroke-width=".711"/><path d="M18.4 25.424v29.075m-10.9 0L18.4 69.3l10.9-14.801zm10.9-43.875L7.5 25.425h21.801z" fill="#fff" stroke="#fff" stroke-width="7.5"/></g>
|
||||
<g id="squelch" fill="#fff" stroke-width=".767"><path d="M33.333 24.7c-.058-14.132-5.913-21.9-16.58-21.9-10.145 0-16 7.673-16 20.963 0 10.575 3.305 15.722 11.884 18.343l5.913 1.872c5.797 1.778 7.942 4.399 7.942 9.92 0 5.71-3.246 9.172-8.521 9.172-5.913 0-9.218-4.024-9.508-11.324H0C.521 66.345 6.724 74.3 17.506 74.3c10.899 0 17.333-8.142 17.333-22.087 0-10.762-3.362-16.378-11.188-18.81l-6.609-2.06c-6.203-1.965-8-3.93-8-8.89 0-5.148 2.782-8.423 7.304-8.423 5.507 0 8.58 3.743 8.87 10.669zM75.362 62.508C78.202 56.893 80 47.534 80 38.363c0-10.014-2.203-19.653-5.913-26.11C70.435 5.887 65.681 2.8 59.653 2.8S48.87 5.888 45.218 12.252C41.45 18.71 39.305 28.35 39.305 38.55s2.203 19.84 5.913 26.298c3.652 6.364 8.406 9.452 14.435 9.452 4.405 0 7.594-1.404 10.956-4.68l4.986 7.581L80 69.621zM64.638 46.13l-4.406 7.58 4.464 6.833c-1.391 1.123-3.246 1.778-5.101 1.778C52.638 62.321 48 52.869 48 38.549c0-14.412 4.58-23.771 11.652-23.771s11.652 9.358 11.652 23.864c0 5.615-.638 10.67-1.913 14.787z"/></g>
|
||||
<g id="trashcan"><path d="M56.667 13.333V6.666A6.67 6.67 0 0 0 50 0H30a6.67 6.67 0 0 0-6.666 6.666v6.667H6.667V20h6.666v53.333A6.67 6.67 0 0 0 20 79.999h40a6.67 6.67 0 0 0 6.667-6.666V20h6.666v-6.667zM30 6.666h20v6.667H30zm30 66.667H20V20h40zM36.667 26.666H30v40h6.667zm13.333 0h-6.667v40H50z" fill="#fff"/></g>
|
||||
<g id="edit"><path d="m52.5 7.5-45 45v20h20l45-45zm12.93 20-4.697 4.697-12.93-12.93L52.5 14.57zM15.302 51.768l4.06-4.06c1.533 1.125 3.575 2.002 5.81 2.002 2.148 0 4.453-.8 6.595-2.942l10-10c2.52-2.52 4.622-7.728.968-12.43l1.535-1.535 12.93 12.93L28.23 64.698zm22.93-18.535-10 10c-2.062 2.058-4.007 1.595-5.27.875L39.14 27.93c1.465 2.485-.27 4.643-.907 5.303zM12.5 56.035 23.965 67.5H12.5z" fill="#fff"/></g>
|
||||
<g id="bookmark"><path d="M62.5 0h-45A7.5 7.5 0 0 0 10 7.5V80l30-17.5L70 80V7.5A7.5 7.5 0 0 0 62.5 0zm0 66.942L40 53.817 17.5 66.942V8.437a.938.938 0 0 1 .938-.938h43.124c.518 0 .938.42.938.937z" fill="#fff"/></g>
|
||||
<g id="rx-details-arrow-down"><path d="M5 0C2.5 0 0 2.5 0 5v7h43V5c0-2.5-2.5-5-5-5zm8 4h17l-8.5 6.5z" fill="#999" fill-opacity=".196"/><path d="M13 4h17l-8.5 6.5z" fill="#848484" fill-opacity=".592"/></g>
|
||||
<g id="rx-details-arrow-up"><path d="M5 0C2.5 0 0 2.5 0 5v7h43V5c0-2.5-2.5-5-5-5zm16.5 3L30 9.5H13z" fill="#999" fill-opacity=".196"/><path d="M30 9.5H13L21.5 3z" fill="#848484" fill-opacity=".592"/></g>
|
||||
<g id="maps-pin" transform="translate(-965.78 -331.788) scale(1.1856)"><path d="M817.11 282.97c-1.258 1.343-2.046 3.299-2.016 5.139.064 3.845 1.797 5.3 4.569 10.592.998 2.328 2.04 4.792 3.031 8.873.138.602.272 1.16.334 1.21.062.048.197-.513.334-1.115.991-4.081 2.033-6.543 3.032-8.872 2.77-5.291 4.504-6.747 4.568-10.592.03-1.84-.76-3.797-2.018-5.14-1.437-1.534-3.605-2.67-5.916-2.717-2.311-.047-4.48 1.088-5.918 2.622z" fill="#ff4646" stroke="#d73534"/><circle cx="823.03" cy="288.25" r="3.035" fill="#590000"/></g>
|
||||
<g id="play-button"><circle cx="350" cy="350" r="330" fill="none" stroke="#fff" stroke-width="36"/><path d="M195 211v278l366-139z" fill="#fff"/></g>
|
||||
<g id="meta-mute" stroke="#fff" stroke-width="5"><path stroke-linejoin="round" style="paint-order:fill" fill="none" d="m21.989 47.699 17.4 15.051V13.769L22.235 28.606H6v19.093z" transform="matrix(5.3513 0 0 5.3723 -.73 -1.542)"/><path d="m48.652 50.27 20.743-24.299M69.395 50.27 48.652 25.971" stroke-linecap="round" transform="matrix(5.3513 0 0 5.3723 -.73 -1.542)"/></g>
|
||||
<g id="waterfall-continuous"><g stroke="#fff" stroke-width="8"><path d="M5 40A35 35 0 0 1 26.606 7.664a35 35 0 0 1 38.143 7.587" fill="none"/><path d="m68.284 11.716 2.828 9.9-9.899-2.829z" fill="#fff"/></g><path d="m48.008 48.144 2.816 8.624h9.035L45.075 14h-9.739L20.141 56.768h8.976l2.875-8.624zm-2.405-7.333H34.456l5.573-16.72z" fill="#fff" aria-label="A"/><g stroke="#fff" stroke-width="8"><path d="M75 40a35 35 0 0 1-21.606 32.336 35 35 0 0 1-38.143-7.587" fill="none"/><path d="m11.716 68.284-2.828-9.9 9.899 2.829z" fill="#fff"/></g></g>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 15 KiB |
@ -1,25 +1,25 @@
|
||||
<div id="webrx-top-container">
|
||||
<div id="webrx-top-bar" class="webrx-top-bar-parts">
|
||||
<a href="https://www.openwebrx.de/" target="_blank"><img src="static/gfx/openwebrx-top-logo.png" id="webrx-top-logo" alt="OpenWebRX Logo"/></a>
|
||||
<img id="webrx-rx-avatar" class="openwebrx-photo-trigger" src="static/gfx/openwebrx-avatar.png" alt="Receiver avatar"/>
|
||||
<div id="webrx-rx-texts">
|
||||
<div id="webrx-rx-title" class="openwebrx-photo-trigger"></div>
|
||||
<div id="webrx-rx-desc" class="openwebrx-photo-trigger"></div>
|
||||
<div class="webrx-top-container">
|
||||
<div class="webrx-top-bar">
|
||||
<a href="https://www.openwebrx.de/" target="_blank"><svg viewBox="0 0 591 100" class="webrx-top-logo"><title>Visit the OpenWebRX homepage</title><use xlink:href="${document_root}static/gfx/svg-defs.svg#top-logo"></use></svg></a>
|
||||
<img class="webrx-rx-avatar openwebrx-photo-trigger" src="${document_root}static/gfx/openwebrx-avatar.png" alt="Receiver avatar"/>
|
||||
<div class="webrx-rx-texts openwebrx-photo-trigger">
|
||||
<h1 class="webrx-rx-title">${receiver_name}</h1>
|
||||
<div class="webrx-rx-desc">${receiver_location} | Loc: ${locator}, ASL: ${receiver_asl} m</div>
|
||||
</div>
|
||||
<section id="openwebrx-main-buttons">
|
||||
<div class="button" data-toggle-panel="openwebrx-panel-status"><span class="sprite sprite-panel-status"></span><br/>Status</div>
|
||||
<div class="button" data-toggle-panel="openwebrx-panel-log"><span class="sprite sprite-panel-log"></span><br/>Log</div>
|
||||
<div class="button" data-toggle-panel="openwebrx-panel-receiver"><span class="sprite sprite-panel-receiver"></span><br/>Receiver</div>
|
||||
<a class="button" href="map" target="openwebrx-map"><span class="sprite sprite-panel-map"></span><br/>Map</a>
|
||||
${settingslink}
|
||||
<section class="openwebrx-main-buttons">
|
||||
<div class="button" data-toggle-panel="openwebrx-panel-status"><svg viewBox="0 0 80 80"><use xlink:href="${document_root}static/gfx/svg-defs.svg#panel-status"></use></svg><br/>Status</div>
|
||||
<div class="button" data-toggle-panel="openwebrx-panel-log"><svg viewBox="0 0 80 80"><use xlink:href="${document_root}static/gfx/svg-defs.svg#panel-log"></use></svg><br/>Log</div>
|
||||
<div class="button" data-toggle-panel="openwebrx-panel-receiver"><svg viewBox="0 0 80 80"><use xlink:href="${document_root}static/gfx/svg-defs.svg#panel-receiver"></use></svg><br/>Receiver</div>
|
||||
<a class="button" href="${document_root}map" target="openwebrx-map"><svg viewBox="0 0 80 80"><use xlink:href="${document_root}static/gfx/svg-defs.svg#panel-map"></use></svg><br/>Map</a>
|
||||
<a class="button" href="${document_root}settings" target="openwebrx-settings"><svg viewBox="0 0 80 80"><use xlink:href="${document_root}static/gfx/svg-defs.svg#panel-settings"></use></svg><br/>Settings</a>
|
||||
</section>
|
||||
</div>
|
||||
<div id="openwebrx-description-container">
|
||||
<div id="webrx-rx-photo-title"></div>
|
||||
<div id="webrx-rx-photo-desc"></div>
|
||||
</div>
|
||||
<div id="openwebrx-rx-details-arrow">
|
||||
<a id="openwebrx-rx-details-arrow-up" class="openwebrx-photo-trigger" style="display: none;"><span class="sprite sprite-rx-details-arrow-up"></span></a>
|
||||
<a id="openwebrx-rx-details-arrow-down" class="openwebrx-photo-trigger"><span class="sprite sprite-rx-details-arrow-down"></span></a>
|
||||
<div class="openwebrx-description-container">
|
||||
<div class="webrx-rx-photo-title">${photo_title}</div>
|
||||
<div class="webrx-rx-photo-desc">${photo_desc}</div>
|
||||
</div>
|
||||
<a class="openwebrx-rx-details-arrow openwebrx-rx-details-arrow--down openwebrx-photo-trigger">
|
||||
<svg class="down" viewBox="0 0 43 12"><use xlink:href="static/gfx/svg-defs.svg#rx-details-arrow-down"></use></svg>
|
||||
<svg class="up" viewBox="0 0 43 12"><use xlink:href="static/gfx/svg-defs.svg#rx-details-arrow-up"></use></svg>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -23,7 +23,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenWebRX | Open Source SDR Web App for Everyone!</title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="static/favicon.ico" />
|
||||
<link rel="shortcut icon" type="image/x-icon" href="static/favicon.ico" sizes="16x16 32x32" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="static/gfx/favicon32.png" />
|
||||
<link rel="icon" type="image/png" sizes="44x44" href="static/gfx/favicon44.png" />
|
||||
<link rel="icon" type="image/png" sizes="64x64" href="static/gfx/favicon64.png" />
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="static/gfx/favicon96.png" />
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="static/gfx/favicon128.png" />
|
||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||
<meta name="msapplication-TileImage" content="mstile-144x144.png">
|
||||
<script src="compiled/receiver.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="static/lib/nanoscroller.css" />
|
||||
<link rel="stylesheet" type="text/css" href="static/css/openwebrx.css" />
|
||||
@ -34,142 +41,191 @@
|
||||
<body onload="openwebrx_init();">
|
||||
<div id="webrx-page-container">
|
||||
${header}
|
||||
<div id="openwebrx-frequency-container">
|
||||
<div id="openwebrx-bookmarks-container"></div>
|
||||
<div id="openwebrx-scale-container">
|
||||
<canvas id="openwebrx-scale-canvas" width="0" height="0"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div id="webrx-canvas-background">
|
||||
<div id="webrx-canvas-container">
|
||||
<!-- add canvas here by javascript -->
|
||||
</div>
|
||||
</div>
|
||||
<div id="openwebrx-panels-container">
|
||||
<div id="openwebrx-panels-container-left">
|
||||
<div class="openwebrx-panel" data-panel-name="client-under-devel" style="width: 245px; background-color: Red;">
|
||||
<span style="font-size: 15pt; font-weight: bold;">Under construction</span>
|
||||
<br />We're working on the code right now, so the application might fail.
|
||||
<div class="openwebrx-waterfall-container">
|
||||
<div id="openwebrx-frequency-container">
|
||||
<div id="openwebrx-bookmarks-container"></div>
|
||||
<div id="openwebrx-scale-container">
|
||||
<canvas id="openwebrx-scale-canvas" width="0" height="0"></canvas>
|
||||
</div>
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-digimodes" style="display: none; width: 619px;" data-panel-name="digimodes">
|
||||
<div id="openwebrx-digimode-canvas-container">
|
||||
<div id="openwebrx-digimode-select-channel"></div>
|
||||
</div>
|
||||
<div id="webrx-canvas-background">
|
||||
<div id="webrx-canvas-container">
|
||||
<!-- add canvas here by javascript -->
|
||||
</div>
|
||||
</div>
|
||||
<div id="openwebrx-panels-container">
|
||||
<div id="openwebrx-panels-container-left">
|
||||
<div class="openwebrx-panel" data-panel-name="client-under-devel" style="width: 245px; background-color: Red;">
|
||||
<span style="font-size: 15pt; font-weight: bold;">Under construction</span>
|
||||
<br />We're working on the code right now, so the application might fail.
|
||||
</div>
|
||||
<div id="openwebrx-digimode-content-container">
|
||||
<div class="gradient"></div>
|
||||
<div id="openwebrx-digimode-content">
|
||||
<span id="openwebrx-cursor-blink"></span>
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-digimodes" style="display: none; width: 619px;" data-panel-name="digimodes">
|
||||
<div id="openwebrx-digimode-canvas-container">
|
||||
<div id="openwebrx-digimode-select-channel"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-wsjt-message" style="display: none; width: 619px;" data-panel-name="wsjt-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-js8-message" style="display:none; width: 619px;" data-panel-name="js8-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-packet-message" style="display: none; width: 619px;" data-panel-name="aprs-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-pocsag-message" style="display: none; width: 619px;" data-panel-name="pocsag-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-ysf" style="display: none;" data-panel-name="metadata-ysf">
|
||||
<div class="openwebrx-meta-slot">
|
||||
<div class="openwebrx-ysf-mode"></div>
|
||||
<div class="openwebrx-meta-user-image"></div>
|
||||
<div class="openwebrx-ysf-source"><span class="location"></span><span class="callsign"></span></div>
|
||||
<div class="openwebrx-ysf-up"></div>
|
||||
<div class="openwebrx-ysf-down"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-dmr" style="display: none;" data-panel-name="metadata-dmr">
|
||||
<div class="openwebrx-meta-slot openwebrx-dmr-timeslot-panel">
|
||||
<div class="openwebrx-dmr-slot">Timeslot 1</div>
|
||||
<div class="openwebrx-meta-user-image"></div>
|
||||
<div class="openwebrx-dmr-id"></div>
|
||||
<div class="openwebrx-dmr-name"></div>
|
||||
<div class="openwebrx-dmr-target"></div>
|
||||
</div>
|
||||
<div class="openwebrx-meta-slot openwebrx-dmr-timeslot-panel">
|
||||
<div class="openwebrx-dmr-slot">Timeslot 2</div>
|
||||
<div class="openwebrx-meta-user-image"></div>
|
||||
<div class="openwebrx-dmr-id"></div>
|
||||
<div class="openwebrx-dmr-name"></div>
|
||||
<div class="openwebrx-dmr-target"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-log" data-panel-name="debug" style="width: 619px;">
|
||||
<div class="openwebrx-panel-inner nano" id="openwebrx-log-scroll">
|
||||
<div class="nano-content">
|
||||
<div id="openwebrx-client-log-title">OpenWebRX client log</div>
|
||||
<div>
|
||||
Author contact: <a href="http://www.justjakob.de/" target="_blank">Jakob Ketterl, DD5JFK</a> |
|
||||
<a href="https://www.openwebrx.de" target="_blank">OpenWebRX homepage</a>
|
||||
<div id="openwebrx-digimode-content-container">
|
||||
<div class="gradient"></div>
|
||||
<div id="openwebrx-digimode-content">
|
||||
<span id="openwebrx-cursor-blink"></span>
|
||||
</div>
|
||||
<div>Support and information: <a href="https://groups.io/g/openwebrx" target="_blank">Groups.io Mailinglist</a></div>
|
||||
<div id="openwebrx-debugdiv"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-wsjt-message" style="display: none; width: 619px;" data-panel-name="wsjt-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-js8-message" style="display:none; width: 619px;" data-panel-name="js8-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-packet-message" style="display: none; width: 619px;" data-panel-name="aprs-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-message-panel" id="openwebrx-panel-pocsag-message" style="display: none; width: 619px;" data-panel-name="pocsag-message"></div>
|
||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-ysf" style="display: none;" data-panel-name="metadata-ysf">
|
||||
<div class="openwebrx-meta-slot">
|
||||
<div class="openwebrx-ysf-mode"></div>
|
||||
<div class="openwebrx-meta-user-image">
|
||||
<img class="directcall" src="static/gfx/openwebrx-directcall.svg">
|
||||
</div>
|
||||
<div class="openwebrx-ysf-source"><span class="location"></span><span class="callsign"></span></div>
|
||||
<div class="openwebrx-ysf-up"></div>
|
||||
<div class="openwebrx-ysf-down"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-dstar" style="display: none;" data-panel-name="metadata-dstar">
|
||||
<div class="openwebrx-meta-slot">
|
||||
<div class="openwebrx-meta-user-image">
|
||||
<img class="directcall" src="static/gfx/openwebrx-directcall.svg">
|
||||
</div>
|
||||
<div class="openwebrx-dstar-ourcall"><span class="location"></span><span class="callsign"></span></div>
|
||||
<div class="openwebrx-dstar-message"></div>
|
||||
<div class="openwebrx-dstar-yourcall"></div>
|
||||
<div class="openwebrx-dstar-departure"></div>
|
||||
<div class="openwebrx-dstar-destination"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-nxdn" style="display: none;" data-panel-name="metadata-nxdn">
|
||||
<div class="openwebrx-meta-slot">
|
||||
<div class="openwebrx-meta-user-image">
|
||||
<img class="directcall" src="static/gfx/openwebrx-directcall.svg">
|
||||
<img class="groupcall" src="static/gfx/openwebrx-groupcall.svg">
|
||||
</div>
|
||||
<div class="openwebrx-nxdn-source"></div>
|
||||
<div class="openwebrx-nxdn-name"></div>
|
||||
<div class="openwebrx-nxdn-destination"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-dmr" style="display: none;" data-panel-name="metadata-dmr">
|
||||
<div class="openwebrx-meta-slot openwebrx-dmr-timeslot-panel">
|
||||
<div class="openwebrx-dmr-slot">Timeslot 1</div>
|
||||
<div class="openwebrx-meta-user-image">
|
||||
<img class="directcall" src="static/gfx/openwebrx-directcall.svg">
|
||||
<img class="groupcall" src="static/gfx/openwebrx-groupcall.svg">
|
||||
</div>
|
||||
<div class="openwebrx-dmr-id"></div>
|
||||
<div class="openwebrx-dmr-name"></div>
|
||||
<div class="openwebrx-dmr-target"></div>
|
||||
<div class="mute">
|
||||
<svg viewBox="0 0 400 400"><use xlink:href="static/gfx/svg-defs.svg#meta-mute"></use></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-meta-slot openwebrx-dmr-timeslot-panel">
|
||||
<div class="openwebrx-dmr-slot">Timeslot 2</div>
|
||||
<div class="openwebrx-meta-user-image">
|
||||
<img class="directcall" src="static/gfx/openwebrx-directcall.svg">
|
||||
<img class="groupcall" src="static/gfx/openwebrx-groupcall.svg">
|
||||
</div>
|
||||
<div class="openwebrx-dmr-id"></div>
|
||||
<div class="openwebrx-dmr-name"></div>
|
||||
<div class="openwebrx-dmr-target"></div>
|
||||
<div class="mute">
|
||||
<svg viewBox="0 0 400 400"><use xlink:href="static/gfx/svg-defs.svg#meta-mute"></use></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-log" data-panel-name="debug" style="width: 619px;">
|
||||
<div class="openwebrx-panel-inner nano" id="openwebrx-log-scroll">
|
||||
<div class="nano-content">
|
||||
<div id="openwebrx-client-log-title">OpenWebRX client log</div>
|
||||
<div>
|
||||
Author contact: <a href="http://www.justjakob.de/" target="_blank">Jakob Ketterl, DD5JFK</a> |
|
||||
<a href="https://www.openwebrx.de" target="_blank">OpenWebRX homepage</a>
|
||||
</div>
|
||||
<div>Support and information: <a href="https://groups.io/g/openwebrx" target="_blank">Groups.io Mailinglist</a></div>
|
||||
<div id="openwebrx-debugdiv"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-status" data-panel-name="status" style="width: 615px;" data-panel-transparent="true">
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-audio-buffer" data-type="audiobuffer"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-audio-output" data-type="audiooutput"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-audio-speed" data-type="audiospeed"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-network-speed" data-type="networkspeed"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-server-cpu" data-type="cpu"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-clients" data-type="clients"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-status" data-panel-name="status" style="width: 615px;" data-panel-transparent="true">
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-audio-buffer" data-type="audiobuffer"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-audio-output" data-type="audiooutput"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-audio-speed" data-type="audiospeed"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-network-speed" data-type="networkspeed"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-server-cpu" data-type="cpu"></div>
|
||||
<div class="openwebrx-progressbar" id="openwebrx-bar-clients" data-type="clients"></div>
|
||||
<div id="openwebrx-panels-container-right">
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-receiver" data-panel-name="client-params" style="width: 259px;">
|
||||
<div class="openwebrx-panel-line frequencies-container">
|
||||
<div class="frequencies">
|
||||
<div class="webrx-actual-freq"></div>
|
||||
<div class="webrx-mouse-freq"></div>
|
||||
</div>
|
||||
<div class="openwebrx-button openwebrx-square-button openwebrx-bookmark-button" style="display:none;" title="Add bookmark...">
|
||||
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#bookmark"></use></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<select id="openwebrx-sdr-profiles-listbox" onchange="sdr_profile_changed();">
|
||||
</select>
|
||||
</div>
|
||||
<div class="openwebrx-modes openwebrx-panel-line"></div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div title="Mute on/off" class="openwebrx-button openwebrx-slider-button openwebrx-mute-button" onclick="toggleMute();">
|
||||
<svg class="unmuted" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#speaker"></use></svg>
|
||||
<svg class="muted" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#speaker-muted"></use></svg>
|
||||
</div>
|
||||
<input title="Volume" id="openwebrx-panel-volume" class="openwebrx-panel-slider" type="range" min="0" max="150" value="50" step="1" onchange="updateVolume()" oninput="updateVolume()">
|
||||
<div title="Auto-adjust waterfall colors (right-click for continuous)" id="openwebrx-waterfall-colors-auto" class="openwebrx-button openwebrx-slider-button">
|
||||
<svg class="auto" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-auto"></use></svg>
|
||||
<svg class="continuous" viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-continuous"></use></svg>
|
||||
</div>
|
||||
<input title="Waterfall minimum level" id="openwebrx-waterfall-color-min" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(0);" oninput="updateVolume()">
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div title="Auto-set squelch level" class="openwebrx-squelch-auto openwebrx-button openwebrx-slider-button">
|
||||
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#squelch"></use></svg>
|
||||
</div>
|
||||
<input title="Squelch" class="openwebrx-squelch-slider openwebrx-panel-slider" type="range" min="-150" max="0" value="-150" step="1">
|
||||
<div title="Set waterfall colors to default" id="openwebrx-waterfall-colors-default" class="openwebrx-button openwebrx-slider-button" onclick="waterfallColorsDefault()">
|
||||
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#waterfall-default"></use></svg>
|
||||
</div>
|
||||
<input title="Waterfall maximum level" id="openwebrx-waterfall-color-max" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(1);" oninput="updateVolume()">
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div class="openwebrx-button openwebrx-square-button openwebrx-zoom-button" onclick="zoomInOneStep();" title="Zoom in one step"><svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#zoom-in"></use></svg></div>
|
||||
<div class="openwebrx-button openwebrx-square-button openwebrx-zoom-button" onclick="zoomOutOneStep();" title="Zoom out one step"><svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#zoom-out"></use></svg></div>
|
||||
<div class="openwebrx-button openwebrx-square-button openwebrx-zoom-button" onclick="zoomInTotal();" title="Zoom in totally"><svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#zoom-in-total"></use></svg></div>
|
||||
<div class="openwebrx-button openwebrx-square-button openwebrx-zoom-button" onclick="zoomOutTotal();" title="Zoom out totally"><svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#zoom-out-total"></use></svg></div>
|
||||
<div id="openwebrx-smeter-db">0 dB</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div id="openwebrx-smeter">
|
||||
<div class="openwebrx-smeter-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="openwebrx-panels-container-right">
|
||||
<div class="openwebrx-panel" id="openwebrx-panel-receiver" data-panel-name="client-params" style="width: 259px;">
|
||||
<div class="openwebrx-panel-line frequencies-container">
|
||||
<div class="frequencies">
|
||||
<div class="webrx-actual-freq"></div>
|
||||
<div class="webrx-mouse-freq"></div>
|
||||
</div>
|
||||
<div class="openwebrx-button openwebrx-square-button openwebrx-bookmark-button" style="display:none;" title="Add bookmark...">
|
||||
<span class="sprite sprite-bookmark"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<select id="openwebrx-sdr-profiles-listbox" onchange="sdr_profile_changed();">
|
||||
</select>
|
||||
</div>
|
||||
<div class="openwebrx-modes openwebrx-panel-line"></div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div title="Mute on/off" class="openwebrx-button openwebrx-mute-button" onclick="toggleMute();"><span class="sprite sprite-speaker openwebrx-sliderbtn-img"></span></div>
|
||||
<input title="Volume" id="openwebrx-panel-volume" class="openwebrx-panel-slider" type="range" min="0" max="150" value="50" step="1" onchange="updateVolume()" oninput="updateVolume()">
|
||||
<div title="Auto-adjust waterfall colors (right-click for continuous)" id="openwebrx-waterfall-colors-auto" class="openwebrx-button"><span class="sprite sprite-waterfall-auto openwebrx-sliderbtn-img"></span></div>
|
||||
<input title="Waterfall minimum level" id="openwebrx-waterfall-color-min" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(0);" oninput="updateVolume()">
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div title="Auto-set squelch level" class="openwebrx-squelch-auto openwebrx-button"><span class="sprite sprite-squelch openwebrx-sliderbtn-img"></span></div>
|
||||
<input title="Squelch" class="openwebrx-squelch-slider openwebrx-panel-slider" type="range" min="-150" max="0" value="-150" step="1">
|
||||
<div title="Set waterfall colors to default" id="openwebrx-waterfall-colors-default" class="openwebrx-button" onclick="waterfallColorsDefault()"><span class="sprite sprite-waterfall-default openwebrx-sliderbtn-img"></span></div>
|
||||
<input title="Waterfall maximum level" id="openwebrx-waterfall-color-max" class="openwebrx-panel-slider" type="range" min="-200" max="100" value="50" step="1" onchange="updateWaterfallColors(1);" oninput="updateVolume()">
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div class="openwebrx-button openwebrx-square-button" onclick="zoomInOneStep();" title="Zoom in one step"><span class="sprite sprite-zoom-in"></span></div>
|
||||
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutOneStep();" title="Zoom out one step"><span class="sprite sprite-zoom-out"></span></div>
|
||||
<div class="openwebrx-button openwebrx-square-button" onclick="zoomInTotal();" title="Zoom in totally"><span class="sprite sprite-zoom-in-total"></span></div>
|
||||
<div class="openwebrx-button openwebrx-square-button" onclick="zoomOutTotal();" title="Zoom out totally"><span class="sprite sprite-zoom-out-total"></span></div>
|
||||
<div id="openwebrx-smeter-db">0 dB</div>
|
||||
</div>
|
||||
<div class="openwebrx-panel-line">
|
||||
<div id="openwebrx-smeter">
|
||||
<div class="openwebrx-smeter-bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="openwebrx-error-overlay" class="openwebrx-overlay" style="display:none;">
|
||||
<div class="overlay-content">
|
||||
<div>This receiver is currently unavailable due to technical issues.</div>
|
||||
<div>Error Message:</div>
|
||||
<div class="errormessage"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="openwebrx-autoplay-overlay" class="openwebrx-overlay" style="display:none;">
|
||||
<div class="overlay-content">
|
||||
<img id="openwebrx-play-button" src="static/gfx/openwebrx-play-button.png" />
|
||||
<svg viewBox="0 0 700 700"><use xlink:href="static/gfx/svg-defs.svg#play-button"></use></svg>
|
||||
<div>Start OpenWebRX</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="openwebrx-error-overlay" class="openwebrx-overlay" style="display:none;">
|
||||
<div class="overlay-content">
|
||||
<div>This receiver is currently unavailable due to technical issues.</div>
|
||||
<div>Error Message:</div>
|
||||
<div class="errormessage"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="openwebrx-dialog-bookmark" class="openwebrx-dialog" style="display:none;">
|
||||
<form>
|
||||
<div class="form-field">
|
||||
|
@ -6,27 +6,15 @@ function AudioEngine(maxBufferLength, audioReporter) {
|
||||
this.audioReporter = audioReporter;
|
||||
this.initStats();
|
||||
this.resetStats();
|
||||
var ctx = window.AudioContext || window.webkitAudioContext;
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onStartCallbacks = [];
|
||||
|
||||
this.started = false;
|
||||
// try common working sample rates
|
||||
if (![48000, 44100].some(function(sr) {
|
||||
try {
|
||||
this.audioContext = new ctx({sampleRate: sr});
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}, this)) {
|
||||
// fallback: let the browser decide
|
||||
// this may cause playback problems down the line
|
||||
this.audioContext = new ctx();
|
||||
this.audioContext = this.buildAudioContext();
|
||||
if (!this.audioContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
var me = this;
|
||||
this.audioContext.onstatechange = function() {
|
||||
if (me.audioContext.state !== 'running') return;
|
||||
@ -43,6 +31,38 @@ function AudioEngine(maxBufferLength, audioReporter) {
|
||||
this.maxBufferSize = maxBufferLength * this.getSampleRate();
|
||||
}
|
||||
|
||||
AudioEngine.prototype.buildAudioContext = function() {
|
||||
var ctxClass = window.AudioContext || window.webkitAudioContext;
|
||||
if (!ctxClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
// known good sample rates
|
||||
var goodRates = [48000, 44100, 96000]
|
||||
|
||||
// let the browser chose the sample rate, if it is good, use it
|
||||
var ctx = new ctxClass({latencyHint: 'playback'});
|
||||
if (goodRates.indexOf(ctx.sampleRate) >= 0) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// if that didn't work, try if any of the good rates work
|
||||
if (goodRates.some(function(sr) {
|
||||
try {
|
||||
ctx = new ctxClass({sampleRate: sr, latencyHint: 'playback'});
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}, this)) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// fallback: let the browser decide
|
||||
// this may cause playback problems down the line
|
||||
return new ctxClass({latencyHint: 'playback'});
|
||||
}
|
||||
|
||||
AudioEngine.prototype.resume = function(){
|
||||
this.audioContext.resume();
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ BookmarkBar.prototype.render = function(){
|
||||
var $bookmark = $(
|
||||
'<div class="bookmark" data-source="' + b.source + '"' + (b.editable?' editable="editable"':'') + '>' +
|
||||
'<div class="bookmark-actions">' +
|
||||
'<div class="openwebrx-button action" data-action="edit"><span class="sprite sprite-edit"></span></div>' +
|
||||
'<div class="openwebrx-button action" data-action="delete"><span class="sprite sprite-trashcan"><span></div>' +
|
||||
'<div class="openwebrx-button action" data-action="edit"><svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#edit"></use></svg></div>' +
|
||||
'<div class="openwebrx-button action" data-action="delete"><svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#trashcan"></use></svg></div>' +
|
||||
'</div>' +
|
||||
'<div class="bookmark-content">' + b.name + '</div>' +
|
||||
'</div>'
|
||||
@ -145,21 +145,3 @@ BookmarkBar.prototype.getDemodulatorPanel = function() {
|
||||
BookmarkBar.prototype.getDemodulator = function() {
|
||||
return this.getDemodulatorPanel().getDemodulator();
|
||||
};
|
||||
|
||||
BookmarkLocalStorage = function(){
|
||||
};
|
||||
|
||||
BookmarkLocalStorage.prototype.getBookmarks = function(){
|
||||
return JSON.parse(window.localStorage.getItem("bookmarks")) || [];
|
||||
};
|
||||
|
||||
BookmarkLocalStorage.prototype.setBookmarks = function(bookmarks){
|
||||
window.localStorage.setItem("bookmarks", JSON.stringify(bookmarks));
|
||||
};
|
||||
|
||||
BookmarkLocalStorage.prototype.deleteBookmark = function(data) {
|
||||
if (data.id) data = data.id;
|
||||
var bookmarks = this.getBookmarks();
|
||||
bookmarks = bookmarks.filter(function(b) { return b.id !== data; });
|
||||
this.setBookmarks(bookmarks);
|
||||
};
|
||||
|
17
htdocs/lib/BookmarkLocalStorage.js
Normal file
@ -0,0 +1,17 @@
|
||||
BookmarkLocalStorage = function(){
|
||||
};
|
||||
|
||||
BookmarkLocalStorage.prototype.getBookmarks = function(){
|
||||
return JSON.parse(window.localStorage.getItem("bookmarks")) || [];
|
||||
};
|
||||
|
||||
BookmarkLocalStorage.prototype.setBookmarks = function(bookmarks){
|
||||
window.localStorage.setItem("bookmarks", JSON.stringify(bookmarks));
|
||||
};
|
||||
|
||||
BookmarkLocalStorage.prototype.deleteBookmark = function(data) {
|
||||
if (data.id) data = data.id;
|
||||
var bookmarks = this.getBookmarks();
|
||||
bookmarks = bookmarks.filter(function(b) { return b.id !== data; });
|
||||
this.setBookmarks(bookmarks);
|
||||
};
|
@ -5,14 +5,14 @@ function Filter(demodulator) {
|
||||
|
||||
Filter.prototype.getLimits = function() {
|
||||
var max_bw;
|
||||
if (this.demodulator.get_secondary_demod() === 'pocsag') {
|
||||
if (['pocsag', 'packet'].indexOf(this.demodulator.get_secondary_demod()) >= 0) {
|
||||
max_bw = 12500;
|
||||
} else if (['dmr', 'dstar', 'nxdn', 'ysf', 'm17'].indexOf(this.demodulator.get_modulation()) >= 0) {
|
||||
max_bw = 6250;
|
||||
} else if (this.demodulator.get_modulation() === 'wfm') {
|
||||
max_bw = 100000;
|
||||
} else if (this.demodulator.get_modulation() === 'drm') {
|
||||
max_bw = 100000;
|
||||
} else if (this.demodulator.get_secondary_demod() === 'packet') {
|
||||
max_bw = 12500;
|
||||
max_bw = 50000;
|
||||
} else {
|
||||
max_bw = (audioEngine.getOutputRate() / 2) - 1;
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ DemodulatorPanel.prototype.updatePanels = function() {
|
||||
var modulation = this.getDemodulator().get_secondary_demod();
|
||||
$('#openwebrx-panel-digimodes').attr('data-mode', modulation);
|
||||
toggle_panel("openwebrx-panel-digimodes", !!modulation);
|
||||
toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4', 'fst4', 'fst4w'].indexOf(modulation) >= 0);
|
||||
toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9', 'ft4', 'fst4', 'fst4w', "q65"].indexOf(modulation) >= 0);
|
||||
toggle_panel("openwebrx-panel-js8-message", modulation == "js8");
|
||||
toggle_panel("openwebrx-panel-packet-message", modulation === "packet");
|
||||
toggle_panel("openwebrx-panel-pocsag-message", modulation === "pocsag");
|
||||
@ -213,6 +213,10 @@ DemodulatorPanel.prototype.setInitialParams = function(params) {
|
||||
$.extend(this.initialParams, params);
|
||||
};
|
||||
|
||||
DemodulatorPanel.prototype.resetInitialParams = function() {
|
||||
this.initialParams = {};
|
||||
};
|
||||
|
||||
DemodulatorPanel.prototype.onHashChange = function() {
|
||||
this._apply(this.transformHashParams(this.parseHash()));
|
||||
};
|
||||
@ -341,7 +345,7 @@ DemodulatorPanel.prototype.updateSquelch = function() {
|
||||
};
|
||||
|
||||
DemodulatorPanel.prototype.setSquelchMargin = function(margin) {
|
||||
if (!margin || this.squelchMargin == margin) return;
|
||||
if (typeof(margin) === 'undefined' || this.squelchMargin == margin) return;
|
||||
this.squelchMargin = margin;
|
||||
};
|
||||
|
||||
@ -353,9 +357,9 @@ DemodulatorPanel.prototype.setMouseFrequency = function(freq) {
|
||||
this.mouseFrequencyDisplay.setFrequency(freq);
|
||||
};
|
||||
|
||||
DemodulatorPanel.prototype.setFrequencyPrecision = function(precision) {
|
||||
this.tuneableFrequencyDisplay.setFrequencyPrecision(precision);
|
||||
this.mouseFrequencyDisplay.setFrequencyPrecision(precision);
|
||||
DemodulatorPanel.prototype.setTuningPrecision = function(precision) {
|
||||
this.tuneableFrequencyDisplay.setTuningPrecision(precision);
|
||||
this.mouseFrequencyDisplay.setTuningPrecision(precision);
|
||||
};
|
||||
|
||||
$.fn.demodulatorPanel = function(){
|
||||
|
@ -1,7 +1,14 @@
|
||||
function FrequencyDisplay(element) {
|
||||
this.suffixes = {
|
||||
'': 0,
|
||||
'k': 3,
|
||||
'M': 6,
|
||||
'G': 9,
|
||||
'T': 12
|
||||
};
|
||||
this.element = $(element);
|
||||
this.digits = [];
|
||||
this.precision = 4;
|
||||
this.precision = 2;
|
||||
this.setupElements();
|
||||
this.setFrequency(0);
|
||||
}
|
||||
@ -9,15 +16,30 @@ function FrequencyDisplay(element) {
|
||||
FrequencyDisplay.prototype.setupElements = function() {
|
||||
this.displayContainer = $('<div>');
|
||||
this.digitContainer = $('<span>');
|
||||
this.displayContainer.html([this.digitContainer, $('<span> MHz</span>')]);
|
||||
this.unitContainer = $('<span> Hz</span>');
|
||||
this.displayContainer.html([this.digitContainer, this.unitContainer]);
|
||||
this.element.html(this.displayContainer);
|
||||
};
|
||||
|
||||
FrequencyDisplay.prototype.getSuffix = function() {
|
||||
var me = this;
|
||||
return Object.keys(me.suffixes).filter(function(key){
|
||||
return me.suffixes[key] == me.exponent;
|
||||
})[0] || "";
|
||||
};
|
||||
|
||||
FrequencyDisplay.prototype.setFrequency = function(freq) {
|
||||
this.frequency = freq;
|
||||
var formatted = (freq / 1e6).toLocaleString(
|
||||
if (this.frequency === 0 || Number.isNaN(this.frequency)) {
|
||||
this.exponent = 0
|
||||
} else {
|
||||
this.exponent = Math.floor(Math.log10(this.frequency) / 3) * 3;
|
||||
}
|
||||
|
||||
var digits = Math.max(0, this.exponent - this.precision);
|
||||
var formatted = (freq / 10 ** this.exponent).toLocaleString(
|
||||
undefined,
|
||||
{maximumFractionDigits: this.precision, minimumFractionDigits: this.precision}
|
||||
{maximumFractionDigits: digits, minimumFractionDigits: digits}
|
||||
);
|
||||
var children = this.digitContainer.children();
|
||||
for (var i = 0; i < formatted.length; i++) {
|
||||
@ -36,10 +58,11 @@ FrequencyDisplay.prototype.setFrequency = function(freq) {
|
||||
while (this.digits.length > formatted.length) {
|
||||
this.digits.pop().remove();
|
||||
}
|
||||
this.unitContainer.text(' ' + this.getSuffix() + 'Hz');
|
||||
};
|
||||
|
||||
FrequencyDisplay.prototype.setFrequencyPrecision = function(precision) {
|
||||
if (!precision) return;
|
||||
FrequencyDisplay.prototype.setTuningPrecision = function(precision) {
|
||||
if (typeof(precision) == 'undefined') return;
|
||||
this.precision = precision;
|
||||
this.setFrequency(this.frequency);
|
||||
};
|
||||
@ -53,22 +76,28 @@ TuneableFrequencyDisplay.prototype = new FrequencyDisplay();
|
||||
|
||||
TuneableFrequencyDisplay.prototype.setupElements = function() {
|
||||
FrequencyDisplay.prototype.setupElements.call(this);
|
||||
this.input = $('<input>');
|
||||
this.input.hide();
|
||||
this.element.append(this.input);
|
||||
this.input = $('<input type="number" step="any">');
|
||||
this.suffixInput = $('<select tabindex="-1">');
|
||||
this.suffixInput.append($.map(this.suffixes, function(e, p) {
|
||||
return $('<option value="' + e + '">' + p + 'Hz</option>');
|
||||
}));
|
||||
this.inputGroup = $('<div class="input-group">');
|
||||
this.inputGroup.append([this.input, this.suffixInput]);
|
||||
this.inputGroup.hide();
|
||||
this.element.append(this.inputGroup);
|
||||
};
|
||||
|
||||
TuneableFrequencyDisplay.prototype.setupEvents = function() {
|
||||
var me = this;
|
||||
|
||||
me.element.on('wheel', function(e){
|
||||
me.displayContainer.on('wheel', function(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var index = me.digitContainer.find('.digit').index(e.target);
|
||||
if (index < 0) return;
|
||||
|
||||
var delta = 10 ** (Math.floor(Math.max(6, Math.log10(me.frequency))) - index);
|
||||
var delta = 10 ** (Math.floor(Math.max(me.exponent, Math.log10(me.frequency))) - index);
|
||||
if (e.originalEvent.deltaY > 0) delta *= -1;
|
||||
var newFrequency = me.frequency + delta;
|
||||
|
||||
@ -76,26 +105,64 @@ TuneableFrequencyDisplay.prototype.setupEvents = function() {
|
||||
});
|
||||
|
||||
var submit = function(){
|
||||
var freq = parseInt(me.input.val());
|
||||
var exponent = parseInt(me.suffixInput.val());
|
||||
var freq = parseFloat(me.input.val()) * 10 ** exponent;
|
||||
if (!isNaN(freq)) {
|
||||
me.element.trigger('frequencychange', freq);
|
||||
}
|
||||
me.input.hide();
|
||||
me.inputGroup.hide();
|
||||
me.displayContainer.show();
|
||||
};
|
||||
me.input.on('blur', submit).on('keyup', function(e){
|
||||
$inputs = $.merge($(), me.input);
|
||||
$inputs = $.merge($inputs, me.suffixInput);
|
||||
$('body').on('click', function(e) {
|
||||
if (!me.input.is(':visible')) return;
|
||||
if ($.contains(me.element[0], e.target)) return;
|
||||
submit();
|
||||
});
|
||||
$inputs.on('blur', function(e){
|
||||
if ($inputs.toArray().indexOf(e.relatedTarget) >= 0) {
|
||||
return;
|
||||
}
|
||||
submit();
|
||||
});
|
||||
me.input.on('keydown', function(e){
|
||||
if (e.keyCode == 13) return submit();
|
||||
if (e.keyCode == 27) {
|
||||
me.input.hide();
|
||||
me.inputGroup.hide();
|
||||
me.displayContainer.show();
|
||||
return;
|
||||
}
|
||||
var c = String.fromCharCode(e.which);
|
||||
Object.entries(me.suffixes).forEach(function(e) {
|
||||
if (e[0].toUpperCase() == c) {
|
||||
me.suffixInput.val(e[1]);
|
||||
return submit();
|
||||
}
|
||||
})
|
||||
});
|
||||
me.input.on('click', function(e){
|
||||
var currentExponent;
|
||||
me.suffixInput.on('change', function() {
|
||||
var newExponent = me.suffixInput.val();
|
||||
delta = currentExponent - newExponent;
|
||||
if (delta >= 0) {
|
||||
me.input.val(parseFloat(me.input.val()) * 10 ** delta);
|
||||
} else {
|
||||
// should not be necessary to handle this separately, but floating point precision in javascript
|
||||
// does not handle this well otherwise
|
||||
me.input.val(parseFloat(me.input.val()) / 10 ** -delta);
|
||||
}
|
||||
currentExponent = newExponent;
|
||||
me.input.focus();
|
||||
});
|
||||
$inputs.on('click', function(e){
|
||||
e.stopPropagation();
|
||||
});
|
||||
me.element.on('click', function(){
|
||||
me.input.val(me.frequency);
|
||||
me.input.show();
|
||||
currentExponent = me.exponent;
|
||||
me.input.val(me.frequency / 10 ** me.exponent);
|
||||
me.suffixInput.val(me.exponent);
|
||||
me.inputGroup.show();
|
||||
me.displayContainer.hide();
|
||||
me.input.focus();
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
function Header(el) {
|
||||
this.el = el;
|
||||
|
||||
var $buttons = this.el.find('#openwebrx-main-buttons').find('[data-toggle-panel]').filter(function(){
|
||||
var $buttons = this.el.find('.openwebrx-main-buttons').find('[data-toggle-panel]').filter(function(){
|
||||
// ignore buttons when the corresponding panel is not in the DOM
|
||||
return $('#' + $(this).data('toggle-panel'))[0];
|
||||
});
|
||||
@ -11,14 +11,13 @@ function Header(el) {
|
||||
});
|
||||
|
||||
this.init_rx_photo();
|
||||
this.download_details();
|
||||
};
|
||||
|
||||
Header.prototype.setDetails = function(details) {
|
||||
this.el.find('#webrx-rx-title').html(details['receiver_name']);
|
||||
this.el.find('#webrx-rx-desc').html(details['receiver_location'] + ' | Loc: ' + details['locator'] + ', ASL: ' + details['receiver_asl'] + ' m');
|
||||
this.el.find('#webrx-rx-photo-title').html(details['photo_title']);
|
||||
this.el.find('#webrx-rx-photo-desc').html(details['photo_desc']);
|
||||
this.el.find('.webrx-rx-title').html(details['receiver_name']);
|
||||
this.el.find('.webrx-rx-desc').html(details['receiver_location'] + ' | Loc: ' + details['locator'] + ', ASL: ' + details['receiver_asl'] + ' m');
|
||||
this.el.find('.webrx-rx-photo-title').html(details['photo_title']);
|
||||
this.el.find('.webrx-rx-photo-desc').html(details['photo_desc']);
|
||||
};
|
||||
|
||||
Header.prototype.init_rx_photo = function() {
|
||||
@ -30,21 +29,19 @@ Header.prototype.init_rx_photo = function() {
|
||||
}
|
||||
});
|
||||
|
||||
$('#webrx-top-container').find('.openwebrx-photo-trigger').click(this.toggle_rx_photo.bind(this));
|
||||
$('.webrx-top-container').find('.openwebrx-photo-trigger').click(this.toggle_rx_photo.bind(this));
|
||||
};
|
||||
|
||||
Header.prototype.close_rx_photo = function() {
|
||||
this.rx_photo_state = 0;
|
||||
this.el.find('#openwebrx-description-container').removeClass('expanded');
|
||||
this.el.find("#openwebrx-rx-details-arrow-down").show();
|
||||
this.el.find("#openwebrx-rx-details-arrow-up").hide();
|
||||
this.el.find('.openwebrx-description-container').removeClass('expanded');
|
||||
this.el.find(".openwebrx-rx-details-arrow").removeClass('openwebrx-rx-details-arrow--up').addClass('openwebrx-rx-details-arrow--down');
|
||||
}
|
||||
|
||||
Header.prototype.open_rx_photo = function() {
|
||||
this.rx_photo_state = 1;
|
||||
this.el.find('#openwebrx-description-container').addClass('expanded');
|
||||
this.el.find("#openwebrx-rx-details-arrow-down").hide();
|
||||
this.el.find("#openwebrx-rx-details-arrow-up").show();
|
||||
this.el.find('.openwebrx-description-container').addClass('expanded');
|
||||
this.el.find(".openwebrx-rx-details-arrow").removeClass('openwebrx-rx-details-arrow--down').addClass('openwebrx-rx-details-arrow--up');
|
||||
}
|
||||
|
||||
Header.prototype.toggle_rx_photo = function(ev) {
|
||||
@ -58,13 +55,6 @@ Header.prototype.toggle_rx_photo = function(ev) {
|
||||
}
|
||||
};
|
||||
|
||||
Header.prototype.download_details = function() {
|
||||
var self = this;
|
||||
$.ajax('api/receiverdetails').done(function(data){
|
||||
self.setDetails(data);
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.header = function() {
|
||||
if (!this.data('header')) {
|
||||
this.data('header', new Header(this));
|
||||
@ -73,5 +63,5 @@ $.fn.header = function() {
|
||||
};
|
||||
|
||||
$(function(){
|
||||
$('#webrx-top-container').header();
|
||||
$('.webrx-top-container').header();
|
||||
});
|
||||
|
@ -78,7 +78,7 @@ WsjtMessagePanel.prototype.pushMessage = function(msg) {
|
||||
return $('<div/>').text(input).html()
|
||||
};
|
||||
|
||||
if (['FT8', 'JT65', 'JT9', 'FT4', 'FST4'].indexOf(msg['mode']) >= 0) {
|
||||
if (['FT8', 'JT65', 'JT9', 'FT4', 'FST4', 'Q65'].indexOf(msg['mode']) >= 0) {
|
||||
matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/);
|
||||
if (matches && matches[2] !== 'RR73') {
|
||||
linkedmsg = html_escape(matches[1]) + '<a href="map?locator=' + matches[2] + '" target="openwebrx-map">' + matches[2] + '</a>';
|
||||
@ -180,6 +180,7 @@ PacketMessagePanel.prototype.pushMessage = function(msg) {
|
||||
}
|
||||
} else if (msg.lat && msg.lon) {
|
||||
classes.push('openwebrx-maps-pin');
|
||||
overlay = '<svg viewBox="0 0 20 35"><use xlink:href="static/gfx/svg-defs.svg#maps-pin"></use></svg>';
|
||||
}
|
||||
var attrs = [
|
||||
'class="' + classes.join(' ') + '"',
|
||||
|
@ -145,7 +145,7 @@ YsfMetaPanel.prototype.setLocation = function(lat, lon, callsign) {
|
||||
this.hasLocation = hasLocation; this.callsign = callsign;
|
||||
var html = '';
|
||||
if (hasLocation) {
|
||||
html = '<a class="openwebrx-maps-pin" href="map?callsign=' + encodeURIComponent(callsign) + '" target="_blank"></a>';
|
||||
html = '<a class="openwebrx-maps-pin" href="map?callsign=' + encodeURIComponent(callsign) + '" target="_blank"><svg viewBox="0 0 20 35"><use xlink:href="static/gfx/svg-defs.svg#maps-pin"></use></svg></a>';
|
||||
}
|
||||
this.el.find('.openwebrx-ysf-source .location').html(html);
|
||||
};
|
||||
@ -162,9 +162,145 @@ YsfMetaPanel.prototype.setDown = function(down) {
|
||||
this.el.find('.openwebrx-ysf-down').text(down || '');
|
||||
}
|
||||
|
||||
function DStarMetaPanel(el) {
|
||||
MetaPanel.call(this, el);
|
||||
this.modes = ['DSTAR'];
|
||||
this.clear();
|
||||
}
|
||||
|
||||
DStarMetaPanel.prototype = new MetaPanel();
|
||||
|
||||
DStarMetaPanel.prototype.update = function(data) {
|
||||
if (!this.isSupported(data)) return;
|
||||
|
||||
if (data['sync'] && data['sync'] == 'voice') {
|
||||
this.el.find(".openwebrx-meta-slot").addClass("active");
|
||||
this.setOurCall(data['ourcall']);
|
||||
this.setYourCall(data['yourcall']);
|
||||
this.setDeparture(data['departure']);
|
||||
this.setDestination(data['destination']);
|
||||
this.setMessage(data['message']);
|
||||
this.setLocation(data['lat'], data['lon'], data['ourcall']);
|
||||
} else {
|
||||
this.clear();
|
||||
}
|
||||
};
|
||||
|
||||
DStarMetaPanel.prototype.setOurCall = function(ourcall) {
|
||||
if (this.ourcall === ourcall) return;
|
||||
this.ourcall = ourcall;
|
||||
this.el.find('.openwebrx-dstar-ourcall .callsign').text(ourcall || '');
|
||||
};
|
||||
|
||||
DStarMetaPanel.prototype.setYourCall = function(yourcall) {
|
||||
if (this.yourcall === yourcall) return;
|
||||
this.yourcall = yourcall;
|
||||
this.el.find('.openwebrx-dstar-yourcall').text(yourcall || '');
|
||||
};
|
||||
|
||||
DStarMetaPanel.prototype.setDeparture = function(departure) {
|
||||
if (this.departure === departure) return;
|
||||
this.departure = departure;
|
||||
this.el.find('.openwebrx-dstar-departure').text(departure || '');
|
||||
};
|
||||
|
||||
DStarMetaPanel.prototype.setDestination = function(destination) {
|
||||
if (this.destination === destination) return;
|
||||
this.destination = destination;
|
||||
this.el.find('.openwebrx-dstar-destination').text(destination || '');
|
||||
};
|
||||
|
||||
DStarMetaPanel.prototype.setMessage = function(message) {
|
||||
if (this.message === message) return;
|
||||
this.message = message;
|
||||
this.el.find('.openwebrx-dstar-message').text(message || '');
|
||||
}
|
||||
|
||||
DStarMetaPanel.prototype.clear = function() {
|
||||
MetaPanel.prototype.clear.call(this);
|
||||
this.setOurCall();
|
||||
this.setYourCall();
|
||||
this.setDeparture();
|
||||
this.setDestination();
|
||||
this.setMessage();
|
||||
this.setLocation();
|
||||
};
|
||||
|
||||
DStarMetaPanel.prototype.setLocation = function(lat, lon, callsign) {
|
||||
var hasLocation = lat && lon && callsign && callsign != '';
|
||||
if (hasLocation === this.hasLocation && this.callsign === callsign) return;
|
||||
this.hasLocation = hasLocation; this.callsign = callsign;
|
||||
var html = '';
|
||||
if (hasLocation) {
|
||||
html = '<a class="openwebrx-maps-pin" href="map?callsign=' + encodeURIComponent(callsign) + '" target="_blank"><svg viewBox="0 0 20 35"><use xlink:href="static/gfx/svg-defs.svg#maps-pin"></use></svg></a>';
|
||||
}
|
||||
this.el.find('.openwebrx-dstar-ourcall .location').html(html);
|
||||
};
|
||||
|
||||
function NxdnMetaPanel(el) {
|
||||
MetaPanel.call(this, el);
|
||||
this.modes = ['NXDN'];
|
||||
this.clear();
|
||||
}
|
||||
|
||||
NxdnMetaPanel.prototype = new MetaPanel();
|
||||
|
||||
NxdnMetaPanel.prototype.update = function(data) {
|
||||
if (!this.isSupported(data)) return;
|
||||
|
||||
if (data['sync'] && data['sync'] == 'voice') {
|
||||
this.el.find(".openwebrx-meta-slot").addClass("active");
|
||||
this.setSource(data['additional'] && data['additional']['callsign'] || data['source']);
|
||||
this.setName(data['additional'] && data['additional']['fname']);
|
||||
this.setDestination(data['destination']);
|
||||
this.setMode(['conference', 'individual'].includes(data['type']) ? data['type'] : undefined);
|
||||
} else {
|
||||
this.clear();
|
||||
}
|
||||
};
|
||||
|
||||
NxdnMetaPanel.prototype.setSource = function(source) {
|
||||
if (this.source === source) return;
|
||||
this.source = source;
|
||||
this.el.find('.openwebrx-nxdn-source').text(source || '');
|
||||
};
|
||||
|
||||
NxdnMetaPanel.prototype.setName = function(name) {
|
||||
if (this.name === name) return;
|
||||
this.name = name;
|
||||
this.el.find('.openwebrx-nxdn-name').text(name || '');
|
||||
};
|
||||
|
||||
NxdnMetaPanel.prototype.setDestination = function(destination) {
|
||||
if (this.destination === destination) return;
|
||||
this.destination = destination;
|
||||
this.el.find('.openwebrx-nxdn-destination').text(destination || '');
|
||||
};
|
||||
|
||||
NxdnMetaPanel.prototype.setMode = function(mode) {
|
||||
if (this.mode === mode) return;
|
||||
this.mode = mode;
|
||||
|
||||
var modes = ['individual', 'conference'];
|
||||
var classes = modes.filter(function(c){
|
||||
return c !== mode;
|
||||
});
|
||||
this.el.find('.openwebrx-meta-slot').removeClass(classes.join(' ')).addClass(mode);
|
||||
};
|
||||
|
||||
NxdnMetaPanel.prototype.clear = function() {
|
||||
MetaPanel.prototype.clear.call(this);
|
||||
this.setMode();
|
||||
this.setSource();
|
||||
this.setName();
|
||||
this.setDestination();
|
||||
};
|
||||
|
||||
MetaPanel.types = {
|
||||
dmr: DmrMetaPanel,
|
||||
ysf: YsfMetaPanel
|
||||
ysf: YsfMetaPanel,
|
||||
dstar: DStarMetaPanel,
|
||||
nxdn: NxdnMetaPanel,
|
||||
};
|
||||
|
||||
$.fn.metaPanel = function() {
|
||||
|
6
htdocs/lib/bootstrap.bundle.min.js
vendored
Normal file
2
htdocs/lib/location-picker.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/* Taken from https://github.com/cyphercodes/location-picker under GPLv3 license */
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.locationPicker=t()}(this,function(){"use strict";return function(e,t){void 0===t&&(t={});var n=t.insertAt;if(e&&"undefined"!=typeof document){var o=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style");i.type="text/css","top"===n&&o.firstChild?o.insertBefore(i,o.firstChild):o.appendChild(i),i.styleSheet?i.styleSheet.cssText=e:i.appendChild(document.createTextNode(e))}}('.location-picker .centerMarker{position:absolute;background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADYAAABWCAYAAACEsWWHAAAGLElEQVR4AdXcA2xsXReH8f3Ztm3btm2br23btm3btm2rd257b835vVnJStL0sj3Tds6TrOTkzN5r/5925qgorQRPwQewDHbHebgXDQxlNXLfeTlmmZzzlNJOpMyXsA86TJ2O7PGl6DnbQr/CncYx1tNj4JzTde+0la5V/6/x+x+Z85Ov6/jWZ0TFduyL12JMjI05E4iev5pxQXwFV0lGOx7Xf/xRulb5n45vflrH1z4xqYo5MTd6RC9JrvGVmRB6C04dLzR/yw10fP2TGbJyRa/oOVHw1Fh7uqS+jAY0e3uaPXvupOM7n48w01LRO9aItSDX/nKrpf6FYRi85AJzfvy1WHxGKtaKNZPhyNIKoadjZ0nfIfvFYrNSsXYiMz2tilg00Bweas7fZO1YYFYrMkQWKVfl7ScadS7z12jcFhVZxsn9ayoHimHI71RbVWRKhiPrZA7pjZn+TFX4zDWW6lSAU/PoFw3auiJjcuqSryjyPJWH9LauyBhZEXxlcdd+VyFOjDGxFhVZk6vCoUwEv5KXSXlFUYuKrJE5+dXCvlt3Ia7TYkKtKjIndxr/XcOXIMzzgrZWFZkje/Kl8WL7QP/xR7Z0wWs/9X5HvutNdnjdq2z6qpdFxXbsi9daulZkT/YZ/zbsQNwTtWSRuz7/YXu9+bU2ePlLFlcxJsa2ZM3InnSEU8EH5J1v3iRWqhs+9QGbv+plS5TKirExp/K6kT0ckg8ULIO4RW/Jd2q81GTkWvGdC4dkmYLdoXvHLSs3zrffVCrmVl4/HJLdC86r/vmKA8X7ImCVqnxACYfkvIL7EE+OKjWNI11FsehRKUM4JPcVNBCPxSo1jcN4RbHoUSlDOCSNgiHEM79KTeMcVVEselTKEA7JUMEA4pqr9mLhkAwUPAqNX36n9m/Fxi+/K3mk4GaY+/df1/7gEQ7JzQUnwPwN16h8XTjbh/twSE4oWBf6jjio9ifocEjWLfgeDN14be0vqcIh+V7BCzFobKw556ffqO1FcGQPh3AJpxLgROjebrPa3rZE9uTEEgT4IwzffENtbzQje/LH8WLPRQPycXatKjInjXAp48GGMHjx+bUTi8zJhmUieAX60ez8359rIxVZ0czsrygLA9uM+6zVoiJrsnVZFHg55sP8jddqe6nImMyP7GVxYA0Yffyxtn4iHNkiY7J6WRJ4Fu6G3n13a1uxyJbcHZnL0oDvQHNwsJmPDNqqIlNkg8haJgOOgKGrL287sciUHFEmC16FTpi/2bptIxVZks7IWKYC/grN+fOa+bBnVisyRBaIbKUKOBsGzjp11sUiQ3J2qQreij7oWn3ZWZOKtZO+yFRaAVaAsSceb3Z874szLhVrxtoQWUqrwFNxeeWfoVX/2dflkaW0ErwPQ2h2Lvf3GZOKtdDMtd9XpgOsByMP3q/j25+bdqlYI9ZK1ivTBZ6JW6D3kH2nXSzWSG6Jtct0gs+iaWSkOfcvv5g2qehtdLSJqM+WmQC7wND110ybWPROdikzBV6Ih2H+5uu1XCp6Jg/HWmUmwa+gOa+rOedHX22ZVPSKngh+VWYDnAP9Jx3TMrHolZxTZgu8B8PxBHbun39eWSp6RC8MR+8ym2AbGLzo3Mpi0SPZpsw2eCm6oPP/f5myVMxNuqJnaQewKgzdMPXDf8xNVi3tAp6Nh2DemstPWirmJNHj2aWdwDIwfNstkxaLOckypd3Ac/AEdP73T0stFWOTJ6JHaUewBgycecpSi8XYZI3SruBlGGwODy/VT0djTIzFYMwt7QwOhZ69d16iWIxJDi3tDr5CPh/5xqcWKRWvxRgEX6mDWP5GOF0r/muRYl0r/ltyV8wpdQCbQ98xhy1SLF5LNi91AV+A0ccfXaRYvJZ8oU5iT0cXNP7wExOlYl/SFWNLncARMH+L9U0Ui33JEaVuYGXoP/lYE8ViX7JyHcW+uahrx9iXfLOOYq+Bse75JorFvuQ1pY6gE8b/kV1sJ52lruCuib+9GtvJXXUWu2ri72fFdnJVncXOhvgXFykmtpOz6yx2MMzfdB0pJraTg+sstiwM33mbxm9/qPG7H4ntZNk6iz0Hd5hA7ntOqTN4OfbDo1mx/fIyzTwJJedUPgRWtocAAAAASUVORK5CYII=") no-repeat;background-size:100%;top:50%;left:50%;z-index:1;margin-left:-14px;margin-top:-43px;height:44px;width:28px;cursor:pointer}'),function(){function e(e,t,n){void 0===t&&(t={}),void 0===n&&(n={});var o={setCurrentPosition:!0};Object.assign(o,t);var i={center:new google.maps.LatLng(o.lat?o.lat:34.4346,o.lng?o.lng:35.8362),zoom:15};Object.assign(i,n),e instanceof HTMLElement?this.element=e:this.element=document.getElementById(e),this.map=new google.maps.Map(this.element,i);var r=document.createElement("div");r.classList.add("centerMarker"),this.element&&(this.element.classList.add("location-picker"),this.element.children[0].appendChild(r)),!o.setCurrentPosition||o.lat||o.lng||this.setCurrentPosition()}return e.prototype.getMarkerPosition=function(){var e=this.map.getCenter();return{lat:e.lat(),lng:e.lng()}},e.prototype.setLocation=function(e,t){this.map.setCenter(new google.maps.LatLng(e,t))},e.prototype.setCurrentPosition=function(){var e=this;navigator.geolocation?navigator.geolocation.getCurrentPosition(function(t){var n={lat:t.coords.latitude,lng:t.coords.longitude};e.map.setCenter(n)},function(){console.log("Could not determine your location...")}):console.log("Your browser does not support Geolocation.")},e}()});
|
402
htdocs/lib/settings/BookmarkTable.js
Normal file
@ -0,0 +1,402 @@
|
||||
function Editor(table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
Editor.prototype.getInputHtml = function() {
|
||||
return '<input>';
|
||||
}
|
||||
|
||||
Editor.prototype.render = function(el) {
|
||||
this.input = $(this.getInputHtml());
|
||||
el.append(this.input);
|
||||
this.setupEvents();
|
||||
};
|
||||
|
||||
Editor.prototype.setupEvents = function() {
|
||||
var me = this;
|
||||
this.input.on('blur', function() { me.submit(); }).on('change', function() { me.submit(); }).on('keydown', function(e){
|
||||
if (e.keyCode == 13) return me.submit();
|
||||
if (e.keyCode == 27) return me.cancel();
|
||||
});
|
||||
};
|
||||
|
||||
Editor.prototype.submit = function() {
|
||||
if (!this.onSubmit) return;
|
||||
var submit = this.onSubmit;
|
||||
delete this.onSubmit;
|
||||
submit();
|
||||
};
|
||||
|
||||
Editor.prototype.cancel = function() {
|
||||
if (!this.onCancel) return;
|
||||
var cancel = this.onCancel;
|
||||
delete this.onCancel;
|
||||
cancel();
|
||||
};
|
||||
|
||||
Editor.prototype.focus = function() {
|
||||
this.input.focus();
|
||||
};
|
||||
|
||||
Editor.prototype.disable = function(flag) {
|
||||
this.input.prop('disabled', flag);
|
||||
};
|
||||
|
||||
Editor.prototype.setValue = function(value) {
|
||||
this.input.val(value);
|
||||
};
|
||||
|
||||
Editor.prototype.getValue = function() {
|
||||
return this.input.val();
|
||||
};
|
||||
|
||||
Editor.prototype.getHtml = function() {
|
||||
return this.getValue();
|
||||
};
|
||||
|
||||
function NameEditor(table) {
|
||||
Editor.call(this, table);
|
||||
}
|
||||
|
||||
NameEditor.prototype = new Editor();
|
||||
|
||||
NameEditor.prototype.getInputHtml = function() {
|
||||
return '<input class="form-control form-control-sm" type="text">';
|
||||
}
|
||||
|
||||
function FrequencyEditor(table) {
|
||||
Editor.call(this, table);
|
||||
}
|
||||
|
||||
FrequencyEditor.suffixes = {
|
||||
'': 0,
|
||||
'K': 3,
|
||||
'M': 6,
|
||||
'G': 9,
|
||||
'T': 12
|
||||
};
|
||||
|
||||
FrequencyEditor.prototype = new Editor();
|
||||
|
||||
FrequencyEditor.prototype.getInputHtml = function() {
|
||||
return '<div class="input-group input-group-sm exponential-input" name="frequency">' +
|
||||
'<input class="form-control form-control-sm" type="number" step="1">' +
|
||||
'<div class="input-group-append">' +
|
||||
'<select class="input-group-text exponent" tabindex="-1">' +
|
||||
$.map(FrequencyEditor.suffixes, function(v, k) {
|
||||
// fix lowercase "kHz"
|
||||
if (k === "K") k = "k";
|
||||
return '<option value="' + v + '">' + k + 'Hz</option>';
|
||||
}).join('') +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
};
|
||||
|
||||
FrequencyEditor.prototype.render = function(el) {
|
||||
this.input = $(this.getInputHtml());
|
||||
el.append(this.input);
|
||||
this.freqInput = el.find('input');
|
||||
this.expInput = el.find('select');
|
||||
this.setupEvents();
|
||||
};
|
||||
|
||||
FrequencyEditor.prototype.setupEvents = function() {
|
||||
var me = this;
|
||||
var inputs = [this.freqInput, this.expInput].map(function(i) { return i[0]; });
|
||||
inputs.forEach(function(input) {
|
||||
$(input).on('blur', function(e){
|
||||
if (inputs.indexOf(e.relatedTarget) >= 0) {
|
||||
return;
|
||||
}
|
||||
me.submit();
|
||||
});
|
||||
});
|
||||
|
||||
var me = this;
|
||||
this.freqInput.on('keydown', function(e){
|
||||
if (e.keyCode == 13) return me.submit();
|
||||
if (e.keyCode == 27) return me.cancel();
|
||||
var c = String.fromCharCode(e.which);
|
||||
if (c in FrequencyEditor.suffixes) {
|
||||
me.expInput.val(FrequencyEditor.suffixes[c]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
FrequencyEditor.prototype.getValue = function() {
|
||||
var frequency = parseFloat(this.freqInput.val());
|
||||
var exp = parseInt(this.expInput.val());
|
||||
return Math.floor(frequency * 10 ** exp);
|
||||
};
|
||||
|
||||
FrequencyEditor.prototype.setValue = function(value) {
|
||||
var value = parseFloat(value);
|
||||
var exp = 0;
|
||||
if (!Number.isNaN(value) && value > 0) {
|
||||
exp = Math.floor(Math.log10(value) / 3) * 3;
|
||||
}
|
||||
this.freqInput.val(value / 10 ** exp);
|
||||
this.expInput.val(exp);
|
||||
};
|
||||
|
||||
FrequencyEditor.prototype.focus = function() {
|
||||
this.freqInput.focus();
|
||||
};
|
||||
|
||||
var renderFrequency = function(freq) {
|
||||
var exp = 0;
|
||||
if (!Number.isNaN(freq)) {
|
||||
exp = Math.floor(Math.log10(freq) / 3) * 3;
|
||||
}
|
||||
var frequency = freq / 10 ** exp;
|
||||
var suffix = Object.entries(FrequencyEditor.suffixes).find(function(e) {
|
||||
return e[1] == exp;
|
||||
});
|
||||
if (!suffix) {
|
||||
return freq + ' Hz';
|
||||
}
|
||||
// fix lowercase 'kHz'
|
||||
suffix = suffix[0] == 'K' ? 'k' : suffix[0];
|
||||
var expString = suffix[0] + 'Hz';
|
||||
return frequency + ' ' + expString;
|
||||
}
|
||||
|
||||
FrequencyEditor.prototype.getHtml = function() {
|
||||
return renderFrequency(this.getValue());
|
||||
};
|
||||
|
||||
function ModulationEditor(table) {
|
||||
Editor.call(this, table);
|
||||
this.modes = table.data('modes');
|
||||
}
|
||||
|
||||
ModulationEditor.prototype = new Editor();
|
||||
|
||||
ModulationEditor.prototype.getInputHtml = function() {
|
||||
return '<select class="form-control form-control-sm">' +
|
||||
$.map(this.modes, function(name, modulation) {
|
||||
return '<option value="' + modulation + '">' + name + '</option>';
|
||||
}).join('') +
|
||||
'</select>';
|
||||
};
|
||||
|
||||
ModulationEditor.prototype.getHtml = function() {
|
||||
var $option = this.input.find('option:selected')
|
||||
return $option.html();
|
||||
};
|
||||
|
||||
$.fn.bookmarktable = function() {
|
||||
var editors = {
|
||||
name: NameEditor,
|
||||
frequency: FrequencyEditor,
|
||||
modulation: ModulationEditor
|
||||
};
|
||||
|
||||
$.each(this, function(){
|
||||
var $table = $(this).find('table');
|
||||
|
||||
$table.on('dblclick', 'td', function(e) {
|
||||
var $cell = $(e.target);
|
||||
var html = $cell.html();
|
||||
|
||||
var $row = $cell.parents('tr');
|
||||
var name = $cell.data('editor');
|
||||
var EditorCls = editors[name];
|
||||
if (!EditorCls) return;
|
||||
|
||||
var editor = new EditorCls($table);
|
||||
editor.render($cell.html(''));
|
||||
editor.setValue($cell.data('value'));
|
||||
editor.focus();
|
||||
|
||||
editor.onSubmit = function() {
|
||||
editor.disable(true);
|
||||
$.ajax(document.location.href + "/" + $row.data('id'), {
|
||||
data: JSON.stringify(Object.fromEntries([[name, editor.getValue()]])),
|
||||
contentType: 'application/json',
|
||||
method: 'POST'
|
||||
}).done(function(){
|
||||
$cell.data('value', editor.getValue());
|
||||
$cell.html(editor.getHtml());
|
||||
});
|
||||
};
|
||||
|
||||
editor.onCancel = function() {
|
||||
$cell.html(html);
|
||||
};
|
||||
});
|
||||
|
||||
var $modal = $('#deleteModal').modal({show:false});
|
||||
|
||||
$modal.on('hidden.bs.modal', function() {
|
||||
var $row = $modal.data('row');
|
||||
if (!$row) return;
|
||||
$row.find('.bookmark-delete').prop('disabled', false);
|
||||
$modal.removeData('row');
|
||||
});
|
||||
|
||||
$modal.on('click', '.confirm', function() {
|
||||
var $row = $modal.data('row');
|
||||
if (!$row) return;
|
||||
$.ajax(document.location.href + "/" + $row.data('id'), {
|
||||
data: "{}",
|
||||
contentType: 'application/json',
|
||||
method: 'DELETE'
|
||||
}).done(function(){
|
||||
$row.remove();
|
||||
$modal.modal('hide');
|
||||
});
|
||||
});
|
||||
|
||||
$table.on('click', '.bookmark-delete', function(e) {
|
||||
var $button = $(e.target);
|
||||
$button.prop('disabled', true);
|
||||
|
||||
var $row = $button.parents('tr');
|
||||
$modal.data('row', $row);
|
||||
$modal.modal('show');
|
||||
});
|
||||
|
||||
$(this).on('click', '.bookmark-add', function() {
|
||||
if ($table.find('tr[data-id="new"]').length) return;
|
||||
|
||||
$table.find('.emptytext').remove();
|
||||
var row = $('<tr data-id="new">');
|
||||
|
||||
var inputs = Object.fromEntries(
|
||||
Object.entries(editors).map(function(e) {
|
||||
return [e[0], new e[1]($table)];
|
||||
})
|
||||
);
|
||||
|
||||
row.append($.map(inputs, function(editor, name){
|
||||
var cell = $('<td data-editor="' + name + '" class="' + name + '">');
|
||||
editor.render(cell);
|
||||
return cell;
|
||||
}));
|
||||
row.append($(
|
||||
'<td>' +
|
||||
'<div class="btn-group btn-group-sm">' +
|
||||
'<button type="button" class="btn btn-primary bookmark-save">Save</button>' +
|
||||
'<button type="button" class="btn btn-secondary bookmark-cancel">Cancel</button>' +
|
||||
'</div>' +
|
||||
'</td>'
|
||||
));
|
||||
|
||||
row.on('click', '.bookmark-cancel', function() {
|
||||
row.remove();
|
||||
});
|
||||
|
||||
row.on('click', '.bookmark-save', function() {
|
||||
var data = Object.fromEntries(
|
||||
$.map(inputs, function(input, name){
|
||||
input.disable(true);
|
||||
// double wrapped because jQuery.map() flattens the result
|
||||
return [[name, input.getValue()]];
|
||||
})
|
||||
);
|
||||
|
||||
$.ajax(document.location.href, {
|
||||
data: JSON.stringify([data]),
|
||||
contentType: 'application/json',
|
||||
method: 'POST'
|
||||
}).done(function(data){
|
||||
if (data.length && data.length === 1 && 'bookmark_id' in data[0]) {
|
||||
row.attr('data-id', data[0]['bookmark_id']);
|
||||
var tds = row.find('td');
|
||||
|
||||
Object.values(inputs).forEach(function(input, index) {
|
||||
var td = $(tds[index]);
|
||||
td.data('value', input.getValue());
|
||||
td.html(input.getHtml());
|
||||
});
|
||||
|
||||
var $cell = row.find('td').last();
|
||||
var $group = $cell.find('.btn-group');
|
||||
if ($group.length) {
|
||||
$group.remove;
|
||||
$cell.html('<div class="btn btn-sm btn-danger bookmark-delete">delete</div>');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$table.append(row);
|
||||
row[0].scrollIntoView();
|
||||
});
|
||||
|
||||
var $importModal = $('#importModal').modal({show: false});
|
||||
|
||||
$(this).find('.bookmark-import').on('click', function() {
|
||||
var storage = new BookmarkLocalStorage();
|
||||
var bookmarks = storage.getBookmarks();
|
||||
if (bookmarks.length) {
|
||||
var modes = $table.data('modes');
|
||||
var $list = $('<table class="table table-sm">');
|
||||
$list.append(bookmarks.map(function(b) {
|
||||
var modulation = b.modulation;
|
||||
if (modulation in modes) {
|
||||
modulation = modes[modulation];
|
||||
}
|
||||
var row = $(
|
||||
'<tr>' +
|
||||
'<td><input class="form-check-input select" type="checkbox"></td>' +
|
||||
'<td>' + b.name + '</td>' +
|
||||
'<td class="frequency">' + renderFrequency(b.frequency) + '</td>' +
|
||||
'<td>' + modulation + '</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
row.data('bookmark', b);
|
||||
return row;
|
||||
}));
|
||||
$importModal.find('.bookmark-list').html($list);
|
||||
} else {
|
||||
$importModal.find('.bookmark-list').html('No personal bookmarks found in this browser');
|
||||
}
|
||||
$importModal.modal('show');
|
||||
});
|
||||
|
||||
$importModal.on('click', '.confirm', function() {
|
||||
var $list = $importModal.find('.bookmark-list table');
|
||||
if ($list.length) {
|
||||
var selected = $list.find('tr').filter(function(){
|
||||
return $(this).find('.select').is(':checked');
|
||||
}).map(function(){
|
||||
return $(this).data('bookmark');
|
||||
}).toArray();
|
||||
if (selected.length) {
|
||||
$.ajax(document.location.href, {
|
||||
data: JSON.stringify(selected),
|
||||
contentType: 'application/json',
|
||||
method: 'POST'
|
||||
}).done(function(data){
|
||||
$table.find('.emptytext').remove();
|
||||
var modes = $table.data('modes');
|
||||
if (data.length && data.length == selected.length) {
|
||||
$table.append(data.map(function(obj, index) {
|
||||
var bookmark = selected[index];
|
||||
var modulation_name = bookmark.modulation;
|
||||
if (modulation_name in modes) {
|
||||
modulation_name = modes[modulation_name];
|
||||
}
|
||||
return $(
|
||||
'<tr data-id="' + obj.bookmark_id + '">' +
|
||||
'<td data-editor="name" data-value="' + bookmark.name + '">' + bookmark.name + '</td>' +
|
||||
'<td data-editor="frequency" data-value="' + bookmark.frequency + '" class="frequency">' + renderFrequency(bookmark.frequency) +'</td>' +
|
||||
'<td data-editor="modulation" data-value="' + bookmark.modulation + '">' + modulation_name + '</td>' +
|
||||
'<td>' +
|
||||
'<button type="button" class="btn btn-sm btn-danger bookmark-delete">delete</button>' +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
)
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
$importModal.modal('hide');
|
||||
});
|
||||
});
|
||||
};
|
45
htdocs/lib/settings/ExponentialInput.js
Normal file
@ -0,0 +1,45 @@
|
||||
$.fn.exponentialInput = function() {
|
||||
var prefixes = {
|
||||
'K': 3,
|
||||
'M': 6,
|
||||
'G': 9,
|
||||
'T': 12
|
||||
};
|
||||
|
||||
this.each(function(){
|
||||
var $group = $(this);
|
||||
var currentExponent = 0;
|
||||
var $input = $group.find('input');
|
||||
|
||||
var setExponent = function() {
|
||||
var newExponent = parseInt($exponent.val());
|
||||
var delta = currentExponent - newExponent;
|
||||
if (delta >= 0) {
|
||||
$input.val(parseFloat($input.val()) * 10 ** delta);
|
||||
} else {
|
||||
// should not be necessary to handle this separately, but floating point precision in javascript
|
||||
// does not handle this well otherwise
|
||||
$input.val(parseFloat($input.val()) / 10 ** -delta);
|
||||
}
|
||||
currentExponent = newExponent;
|
||||
};
|
||||
|
||||
$input.on('keydown', function(e) {
|
||||
var c = String.fromCharCode(e.which);
|
||||
if (c in prefixes) {
|
||||
currentExponent = prefixes[c];
|
||||
$exponent.val(prefixes[c]);
|
||||
}
|
||||
});
|
||||
|
||||
var $exponent = $group.find('select.exponent');
|
||||
$exponent.on('change', setExponent);
|
||||
|
||||
// calculate initial exponent
|
||||
var value = parseFloat($input.val());
|
||||
if (!Number.isNaN(value)) {
|
||||
$exponent.val(Math.floor(Math.log10(Math.abs(value)) / 3) * 3);
|
||||
setExponent();
|
||||
}
|
||||
})
|
||||
};
|
17
htdocs/lib/settings/GainInput.js
Normal file
@ -0,0 +1,17 @@
|
||||
$.fn.gainInput = function() {
|
||||
this.each(function() {
|
||||
var $container = $(this);
|
||||
|
||||
var update = function(value){
|
||||
$container.find('.option').hide();
|
||||
$container.find('.option.' + value).show();
|
||||
}
|
||||
|
||||
var $select = $container.find('select');
|
||||
$select.on('change', function(e) {
|
||||
var value = $(e.target).val();
|
||||
update(value);
|
||||
});
|
||||
update($select.val());
|
||||
});
|
||||
}
|
87
htdocs/lib/settings/ImageUpload.js
Normal file
@ -0,0 +1,87 @@
|
||||
$.fn.imageUpload = function() {
|
||||
$.each(this, function(){
|
||||
var $this = $(this);
|
||||
var $uploadButton = $this.find('button.upload');
|
||||
var $restoreButton = $this.find('button.restore');
|
||||
var $img = $this.find('img');
|
||||
var originalUrl = $img.prop('src');
|
||||
var $input = $this.find('input');
|
||||
var id = $input.prop('id');
|
||||
var maxSize = $this.data('max-size');
|
||||
var $error;
|
||||
var handleError = function(message) {
|
||||
clearError();
|
||||
$error = $('<div class="invalid-feedback">' + message + '</div>');
|
||||
$this.after($error);
|
||||
$this.addClass('is-invalid');
|
||||
};
|
||||
var clearError = function(message) {
|
||||
if ($error) $error.remove();
|
||||
$this.removeClass('is-invalid');
|
||||
};
|
||||
$uploadButton.click(function(){
|
||||
var input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = 'image/jpeg, image/png, image/webp';
|
||||
|
||||
input.onchange = function(e) {
|
||||
$uploadButton.prop('disabled', true);
|
||||
var $spinner = $('<span class="spinner-border spinner-border-sm mr-1" role="status"></span>');
|
||||
$uploadButton.prepend($spinner);
|
||||
|
||||
var reader = new FileReader()
|
||||
reader.readAsArrayBuffer(e.target.files[0]);
|
||||
reader.onprogress = function(e) {
|
||||
if (e.loaded > maxSize) {
|
||||
handleError('Maximum file size exceeded');
|
||||
$uploadButton.prop('disabled', false);
|
||||
$spinner.remove();
|
||||
reader.abort();
|
||||
}
|
||||
};
|
||||
reader.onload = function(e) {
|
||||
if (e.loaded > maxSize) {
|
||||
handleError('Maximum file size exceeded');
|
||||
$uploadButton.prop('disabled', false);
|
||||
$spinner.remove();
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: '../imageupload?id=' + id,
|
||||
type: 'POST',
|
||||
data: e.target.result,
|
||||
processData: false,
|
||||
contentType: 'application/octet-stream',
|
||||
}).done(function(data){
|
||||
$input.val(data.file);
|
||||
$img.one('load', function() {
|
||||
$uploadButton.prop('disabled', false);
|
||||
$spinner.remove();
|
||||
});
|
||||
$img.prop('src', '../imageupload?file=' + data.file);
|
||||
clearError();
|
||||
}).fail(function(xhr, error){
|
||||
try {
|
||||
var res = JSON.parse(xhr.responseText);
|
||||
handleError(res.error || error);
|
||||
} catch (e) {
|
||||
handleError(error);
|
||||
}
|
||||
$uploadButton.prop('disabled', false);
|
||||
$spinner.remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
input.click();
|
||||
return false;
|
||||
});
|
||||
|
||||
$restoreButton.click(function(){
|
||||
$input.val('restore');
|
||||
$img.prop('src', originalUrl + "&mapped=false");
|
||||
clearError();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
function Input(name, value, options) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.options = options;
|
||||
this.label = options && options.label || name;
|
||||
};
|
||||
|
||||
Input.prototype.getClasses = function() {
|
||||
return ['form-control', 'form-control-sm'];
|
||||
}
|
||||
|
||||
Input.prototype.bootstrapify = function(input) {
|
||||
this.getClasses().forEach(input.addClass.bind(input));
|
||||
return [
|
||||
'<div class="form-group row">',
|
||||
'<label class="col-form-label col-form-label-sm col-3" for="' + this.name + '">' + this.label + '</label>',
|
||||
'<div class="col-9">',
|
||||
$.map(input, function(el) {
|
||||
return el.outerHTML;
|
||||
}).join(''),
|
||||
'</div>',
|
||||
'</div>'
|
||||
].join('');
|
||||
};
|
||||
|
||||
function TextInput() {
|
||||
Input.apply(this, arguments);
|
||||
};
|
||||
|
||||
TextInput.prototype = new Input();
|
||||
|
||||
TextInput.prototype.render = function() {
|
||||
return this.bootstrapify($('<input type="text" name="' + this.name + '" value="' + this.value + '">'));
|
||||
}
|
||||
|
||||
function NumberInput() {
|
||||
Input.apply(this, arguments);
|
||||
};
|
||||
|
||||
NumberInput.prototype = new Input();
|
||||
|
||||
NumberInput.prototype.render = function() {
|
||||
return this.bootstrapify($('<input type="number" name="' + this.name + '" value="' + this.value + '">'));
|
||||
};
|
||||
|
||||
function SoapyGainInput() {
|
||||
Input.apply(this, arguments);
|
||||
}
|
||||
|
||||
SoapyGainInput.prototype = new Input();
|
||||
|
||||
SoapyGainInput.prototype.getClasses = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
SoapyGainInput.prototype.render = function(){
|
||||
var markup = $(
|
||||
'<div class="row form-group">' +
|
||||
'<div class="col-4">Gain mode</div>' +
|
||||
'<div class="col-8">' +
|
||||
'<select class="form-control form-control-sm">' +
|
||||
'<option value="auto">automatic gain</option>' +
|
||||
'<option value="single">single gain value</option>' +
|
||||
'<option value="separate">separate gain values</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="row option form-group gain-mode-single">' +
|
||||
'<div class="col-4">Gain</div>' +
|
||||
'<div class="col-8">' +
|
||||
'<input class="form-control form-control-sm" type="number">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
this.options.gains.map(function(g){
|
||||
return '<div class="row option form-group gain-mode-separate">' +
|
||||
'<div class="col-4">' + g + '</div>' +
|
||||
'<div class="col-8">' +
|
||||
'<input class="form-control form-control-sm" data-gain="' + g + '" type="number">' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}).join('')
|
||||
);
|
||||
var el = $(this.bootstrapify(markup))
|
||||
var setMode = function(mode){
|
||||
el.find('select').val(mode);
|
||||
el.find('.option').hide();
|
||||
el.find('.gain-mode-' + mode).show();
|
||||
};
|
||||
el.on('change', 'select', function(){
|
||||
var mode = $(this).val();
|
||||
setMode(mode);
|
||||
});
|
||||
if (typeof(this.value) === 'number') {
|
||||
setMode('single');
|
||||
el.find('.gain-mode-single input').val(this.value);
|
||||
} else if (typeof(this.value) === 'string') {
|
||||
if (this.value === 'auto') {
|
||||
setMode('auto');
|
||||
} else {
|
||||
setMode('separate');
|
||||
values = $.extend.apply($, this.value.split(',').map(function(seg){
|
||||
var split = seg.split('=');
|
||||
if (split.length < 2) return;
|
||||
var res = {};
|
||||
res[split[0]] = parseInt(split[1]);
|
||||
return res;
|
||||
}));
|
||||
el.find('.gain-mode-separate input').each(function(){
|
||||
var $input = $(this);
|
||||
var g = $input.data('gain');
|
||||
$input.val(g in values ? values[g] : 0);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setMode('auto');
|
||||
}
|
||||
return el;
|
||||
};
|
||||
|
||||
function ProfileInput() {
|
||||
Input.apply(this, arguments);
|
||||
};
|
||||
|
||||
ProfileInput.prototype = new Input();
|
||||
|
||||
ProfileInput.prototype.render = function() {
|
||||
return $('<div><h3>Profiles</h3></div>');
|
||||
};
|
||||
|
||||
function SchedulerInput() {
|
||||
Input.apply(this, arguments);
|
||||
};
|
||||
|
||||
SchedulerInput.prototype = new Input();
|
||||
|
||||
SchedulerInput.prototype.render = function() {
|
||||
return $('<div><h3>Scheduler</h3></div>');
|
||||
};
|