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
|
- 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
|
- 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
|
- 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
|
- New reporting infrastructure, allowing WSPR and FST4W spots to be sent to wsprnet.org
|
||||||
- Add some basic filtering capabilities to the map
|
- 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:
|
- New devices supported:
|
||||||
- HPSDR devices (Hermes Lite 2)
|
- HPSDR devices (Hermes Lite 2) thanks to @jancona
|
||||||
- BBRF103 / RX666 / RX888 devices supported by libsddc
|
- 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**
|
**0.20.1**
|
||||||
- Remove broken OSM map fallback
|
- Remove broken OSM map fallback
|
||||||
|
@ -13,8 +13,7 @@ It has the following features:
|
|||||||
- it works in Google Chrome, Chromium and Mozilla Firefox
|
- 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)
|
- supports a wide range of [SDR hardware](https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices)
|
||||||
- Multiple SDR devices can be used simultaneously
|
- Multiple SDR devices can be used simultaneously
|
||||||
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag)
|
- [digiham](https://github.com/jketterl/digiham) based demodularors (DMR, YSF, Pocsag, D-Star, NXDN)
|
||||||
- [dsd](https://github.com/f4exb/dsdcc) based demodulators (D-Star, NXDN)
|
|
||||||
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
|
- [wsjt-x](https://physics.princeton.edu/pulsar/k1jt/wsjtx.html) based demodulators (FT8, FT4, WSPR, JT65, JT9, FST4,
|
||||||
FST4W)
|
FST4W)
|
||||||
- [direwolf](https://github.com/wb2osz/direwolf) based demodulation of APRS packets
|
- [direwolf](https://github.com/wb2osz/direwolf) based demodulation of APRS packets
|
||||||
|
150
bands.json
@ -6,7 +6,8 @@
|
|||||||
"frequencies": {
|
"frequencies": {
|
||||||
"fst4": 136000,
|
"fst4": 136000,
|
||||||
"fst4w": 136000
|
"fst4w": 136000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "630m",
|
"name": "630m",
|
||||||
@ -15,7 +16,8 @@
|
|||||||
"frequencies": {
|
"frequencies": {
|
||||||
"fst4": 474200,
|
"fst4": 474200,
|
||||||
"fst4w": 474200
|
"fst4w": 474200
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "160m",
|
"name": "160m",
|
||||||
@ -30,7 +32,8 @@
|
|||||||
"js8": 1842000,
|
"js8": 1842000,
|
||||||
"fst4": 1839000,
|
"fst4": 1839000,
|
||||||
"fst4w": 1836800
|
"fst4w": 1836800
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "80m",
|
"name": "80m",
|
||||||
@ -44,7 +47,8 @@
|
|||||||
"jt9": 3572000,
|
"jt9": 3572000,
|
||||||
"ft4": [3568000, 3575000],
|
"ft4": [3568000, 3575000],
|
||||||
"js8": 3578000
|
"js8": 3578000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "60m",
|
"name": "60m",
|
||||||
@ -53,7 +57,8 @@
|
|||||||
"frequencies": {
|
"frequencies": {
|
||||||
"ft8": 5357000,
|
"ft8": 5357000,
|
||||||
"wspr": 5364700
|
"wspr": 5364700
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "40m",
|
"name": "40m",
|
||||||
@ -67,7 +72,8 @@
|
|||||||
"jt9": 7078000,
|
"jt9": 7078000,
|
||||||
"ft4": 7047500,
|
"ft4": 7047500,
|
||||||
"js8": 7078000
|
"js8": 7078000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "30m",
|
"name": "30m",
|
||||||
@ -81,7 +87,8 @@
|
|||||||
"jt9": 10140000,
|
"jt9": 10140000,
|
||||||
"ft4": 10140000,
|
"ft4": 10140000,
|
||||||
"js8": 10130000
|
"js8": 10130000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "20m",
|
"name": "20m",
|
||||||
@ -95,7 +102,8 @@
|
|||||||
"jt9": 14078000,
|
"jt9": 14078000,
|
||||||
"ft4": 14080000,
|
"ft4": 14080000,
|
||||||
"js8": 14078000
|
"js8": 14078000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "17m",
|
"name": "17m",
|
||||||
@ -109,7 +117,8 @@
|
|||||||
"jt9": 18104000,
|
"jt9": 18104000,
|
||||||
"ft4": 18104000,
|
"ft4": 18104000,
|
||||||
"js8": 18104000
|
"js8": 18104000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "15m",
|
"name": "15m",
|
||||||
@ -123,7 +132,8 @@
|
|||||||
"jt9": 21078000,
|
"jt9": 21078000,
|
||||||
"ft4": 21140000,
|
"ft4": 21140000,
|
||||||
"js8": 21078000
|
"js8": 21078000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "12m",
|
"name": "12m",
|
||||||
@ -137,7 +147,8 @@
|
|||||||
"jt9": 24919000,
|
"jt9": 24919000,
|
||||||
"ft4": 24919000,
|
"ft4": 24919000,
|
||||||
"js8": 24922000
|
"js8": 24922000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "10m",
|
"name": "10m",
|
||||||
@ -151,7 +162,8 @@
|
|||||||
"jt9": 28078000,
|
"jt9": 28078000,
|
||||||
"ft4": 28180000,
|
"ft4": 28180000,
|
||||||
"js8": 28078000
|
"js8": 28078000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "6m",
|
"name": "6m",
|
||||||
@ -164,8 +176,10 @@
|
|||||||
"jt65": 50310000,
|
"jt65": 50310000,
|
||||||
"jt9": 50312000,
|
"jt9": 50312000,
|
||||||
"ft4": 50318000,
|
"ft4": 50318000,
|
||||||
"js8": 50318000
|
"js8": 50318000,
|
||||||
}
|
"q65": [50211000, 50275000]
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "4m",
|
"name": "4m",
|
||||||
@ -173,7 +187,8 @@
|
|||||||
"upper_bound": 70200000,
|
"upper_bound": 70200000,
|
||||||
"frequencies": {
|
"frequencies": {
|
||||||
"wspr": 70091000
|
"wspr": 70091000
|
||||||
}
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "2m",
|
"name": "2m",
|
||||||
@ -184,110 +199,169 @@
|
|||||||
"ft8": 144174000,
|
"ft8": 144174000,
|
||||||
"ft4": 144170000,
|
"ft4": 144170000,
|
||||||
"jt65": 144120000,
|
"jt65": 144120000,
|
||||||
"packet": 144800000
|
"packet": 144800000,
|
||||||
}
|
"q65": 144116000
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "70cm",
|
"name": "70cm",
|
||||||
"lower_bound": 430000000,
|
"lower_bound": 430000000,
|
||||||
"upper_bound": 440000000,
|
"upper_bound": 440000000,
|
||||||
"frequencies": {
|
"frequencies": {
|
||||||
"pocsag": 439987500
|
"pocsag": 439987500,
|
||||||
}
|
"q65": 432065000
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "23cm",
|
"name": "23cm",
|
||||||
"lower_bound": 1240000000,
|
"lower_bound": 1240000000,
|
||||||
"upper_bound": 1300000000
|
"upper_bound": 1300000000,
|
||||||
|
"frequencies": {
|
||||||
|
"q65": 1296065000
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "13cm",
|
"name": "13cm",
|
||||||
"lower_bound": 2320000000,
|
"lower_bound": 2320000000,
|
||||||
"upper_bound": 2450000000
|
"upper_bound": 2450000000,
|
||||||
|
"frequencies": {
|
||||||
|
"q65": [2301065000, 2304065000, 2320065000]
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "9cm",
|
"name": "9cm",
|
||||||
"lower_bound": 3400000000,
|
"lower_bound": 3400000000,
|
||||||
"upper_bound": 3475000000
|
"upper_bound": 3475000000,
|
||||||
|
"frequencies": {
|
||||||
|
"q65": 3400065000
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "6cm",
|
"name": "6cm",
|
||||||
"lower_bound": 5650000000,
|
"lower_bound": 5650000000,
|
||||||
"upper_bound": 5850000000
|
"upper_bound": 5850000000,
|
||||||
|
"frequencies": {
|
||||||
|
"q65": 5760200000
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "3cm",
|
"name": "3cm",
|
||||||
"lower_bound": 10000000000,
|
"lower_bound": 10000000000,
|
||||||
"upper_bound": 10500000000
|
"upper_bound": 10500000000,
|
||||||
|
"frequencies": {
|
||||||
|
"q65": 10368200000
|
||||||
|
},
|
||||||
|
"tags": ["hamradio"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "120m Broadcast",
|
"name": "120m Broadcast",
|
||||||
"lower_bound": 2300000,
|
"lower_bound": 2300000,
|
||||||
"upper_bound": 2495000
|
"upper_bound": 2495000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "90m Broadcast",
|
"name": "90m Broadcast",
|
||||||
"lower_bound": 3200000,
|
"lower_bound": 3200000,
|
||||||
"upper_bound": 3400000
|
"upper_bound": 3400000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "75m Broadcast",
|
"name": "75m Broadcast",
|
||||||
"lower_bound": 3900000,
|
"lower_bound": 3900000,
|
||||||
"upper_bound": 4000000
|
"upper_bound": 4000000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "60m Broadcast",
|
"name": "60m Broadcast",
|
||||||
"lower_bound": 4750000,
|
"lower_bound": 4750000,
|
||||||
"upper_bound": 4995000
|
"upper_bound": 4995000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "49m Broadcast",
|
"name": "49m Broadcast",
|
||||||
"lower_bound": 5900000,
|
"lower_bound": 5900000,
|
||||||
"upper_bound": 6200000
|
"upper_bound": 6200000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "41m Broadcast",
|
"name": "41m Broadcast",
|
||||||
"lower_bound": 7200000,
|
"lower_bound": 7200000,
|
||||||
"upper_bound": 7450000
|
"upper_bound": 7450000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "31m Broadcast",
|
"name": "31m Broadcast",
|
||||||
"lower_bound": 9400000,
|
"lower_bound": 9400000,
|
||||||
"upper_bound": 9900000
|
"upper_bound": 9900000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "25m Broadcast",
|
"name": "25m Broadcast",
|
||||||
"lower_bound": 11600000,
|
"lower_bound": 11600000,
|
||||||
"upper_bound": 12100000
|
"upper_bound": 12100000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "22m Broadcast",
|
"name": "22m Broadcast",
|
||||||
"lower_bound": 13570000,
|
"lower_bound": 13570000,
|
||||||
"upper_bound": 13870000
|
"upper_bound": 13870000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "19m Broadcast",
|
"name": "19m Broadcast",
|
||||||
"lower_bound": 15100000,
|
"lower_bound": 15100000,
|
||||||
"upper_bound": 15830000
|
"upper_bound": 15830000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "16m Broadcast",
|
"name": "16m Broadcast",
|
||||||
"lower_bound": 17480000,
|
"lower_bound": 17480000,
|
||||||
"upper_bound": 17900000
|
"upper_bound": 17900000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "15m Broadcast",
|
"name": "15m Broadcast",
|
||||||
"lower_bound": 18900000,
|
"lower_bound": 18900000,
|
||||||
"upper_bound": 19020000
|
"upper_bound": 19020000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "13m Broadcast",
|
"name": "13m Broadcast",
|
||||||
"lower_bound": 21450000,
|
"lower_bound": 21450000,
|
||||||
"upper_bound": 21850000
|
"upper_bound": 21850000,
|
||||||
|
"tags": ["broadcast"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "11m Broadcast",
|
"name": "11m Broadcast",
|
||||||
"lower_bound": 25670000,
|
"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"
|
|
||||||
}
|
|
||||||
]
|
|
415
config_webrx.py
@ -32,32 +32,45 @@ config_webrx: configuration options for OpenWebRX
|
|||||||
and use them for running your web service with 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.
|
# 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:
|
# NOTE: you can find additional information about configuring OpenWebRX in the Wiki:
|
||||||
# https://github.com/jketterl/openwebrx/wiki/Configuration-guide
|
# https://github.com/jketterl/openwebrx/wiki/Configuration-guide
|
||||||
|
|
||||||
# ==== Server settings ====
|
# ==== Server settings ====
|
||||||
web_port = 8073
|
#max_clients = 20
|
||||||
max_clients = 20
|
|
||||||
|
|
||||||
# ==== Web GUI configuration ====
|
# ==== Web GUI configuration ====
|
||||||
receiver_name = "[Callsign]"
|
#receiver_name = "[Callsign]"
|
||||||
receiver_location = "Budapest, Hungary"
|
#receiver_location = "Budapest, Hungary"
|
||||||
receiver_asl = 200
|
#receiver_asl = 200
|
||||||
receiver_admin = "example@example.com"
|
#receiver_admin = "example@example.com"
|
||||||
receiver_gps = {"lat": 47.000000, "lon": 19.000000}
|
#receiver_gps = {"lat": 47.000000, "lon": 19.000000}
|
||||||
photo_title = "Panorama of Budapest from Schönherz Zoltán Dormitory"
|
#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.
|
# 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.
|
# The lines below should give you some examples of what's possible.
|
||||||
photo_desc = """
|
#photo_desc = """
|
||||||
You can add your own background photo and receiver information.<br />
|
#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/>
|
#Receiver is operated by: <a href="mailto:openwebrx@localhost" target="_blank">Receiver Operator</a><br/>
|
||||||
Device: Receiver Device<br />
|
#Device: Receiver Device<br />
|
||||||
Antenna: Receiver Antenna<br />
|
#Antenna: Receiver Antenna<br />
|
||||||
Website: <a href="http://localhost" target="_blank">http://localhost</a>
|
#Website: <a href="http://localhost" target="_blank">http://localhost</a>
|
||||||
"""
|
#"""
|
||||||
|
|
||||||
# ==== Public receiver listings ====
|
# ==== Public receiver listings ====
|
||||||
# You can publish your receiver on online receiver directories, like https://www.receiverbook.de
|
# 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
|
# Please note that you not share your receiver keys publicly since anyone that obtains your receiver key can take over
|
||||||
# your public listing.
|
# your public listing.
|
||||||
# Your receiver keys should be placed into this array:
|
# 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
|
# 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:
|
# keys to the arraylike this:
|
||||||
# receiver_keys += ["my-receiver-key"]
|
# 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:
|
# If you're not sure, simply copy & paste the code you received from your listing site below this line:
|
||||||
|
|
||||||
# ==== DSP/RX settings ====
|
# ==== DSP/RX settings ====
|
||||||
fft_fps = 9
|
#fft_fps = 9
|
||||||
fft_size = 4096 # Should be power of 2
|
#fft_size = 4096 # Should be power of 2
|
||||||
fft_voverlap_factor = (
|
#fft_voverlap_factor = (
|
||||||
0.3 # If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the diagram.
|
# 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"
|
#audio_compression = "adpcm" # valid values: "adpcm", "none"
|
||||||
fft_compression = "adpcm" # valid values: "adpcm", "none"
|
#fft_compression = "adpcm" # valid values: "adpcm", "none"
|
||||||
|
|
||||||
# Tau setting for WFM (broadcast FM) deemphasis\
|
# Tau setting for WFM (broadcast FM) deemphasis\
|
||||||
# Quote from wikipedia https://en.wikipedia.org/wiki/FM_broadcasting#Pre-emphasis_and_de-emphasis
|
# 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"
|
# "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:
|
# Enable one of the following lines, depending on your location:
|
||||||
# wfm_deemphasis_tau = 75e-6 # for US and South Korea
|
# 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
|
# 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
|
# 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
|
# 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:
|
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:
|
# Currently supported types of sdr receivers:
|
||||||
# "rtl_sdr", "rtl_sdr_soapy", "sdrplay", "hackrf", "airspy", "airspyhf", "fifi_sdr",
|
# "rtl_sdr", "rtl_sdr_soapy", "sdrplay", "hackrf", "airspy", "airspyhf", "fifi_sdr",
|
||||||
# "perseussdr", "lime_sdr", "pluto_sdr", "soapy_remote", "hpsdr", "red_pitaya", "uhd",
|
# "perseussdr", "lime_sdr", "pluto_sdr", "soapy_remote", "hpsdr", "uhd",
|
||||||
# "radioberry", "fcdpp", "rtl_tcp", "sddc", "eb200"
|
# "radioberry", "fcdpp", "rtl_tcp", "sddc", "runds"
|
||||||
|
|
||||||
# For more details on specific types, please checkout the wiki:
|
# For more details on specific types, please checkout the wiki:
|
||||||
# https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices
|
# https://github.com/jketterl/openwebrx/wiki/Supported-Hardware#sdr-devices
|
||||||
|
|
||||||
sdrs = {
|
#sdrs = {
|
||||||
"rtlsdr": {
|
# "rtlsdr": {
|
||||||
"name": "RTL-SDR USB Stick",
|
# "name": "RTL-SDR USB Stick",
|
||||||
"type": "rtl_sdr",
|
# "type": "rtl_sdr",
|
||||||
"ppm": 0,
|
# "ppm": 0,
|
||||||
# you can change this if you use an upconverter. formula is:
|
# # you can change this if you use an upconverter. formula is:
|
||||||
# center_freq + lfo_offset = actual frequency on the sdr
|
# # center_freq + lfo_offset = actual frequency on the sdr
|
||||||
# "lfo_offset": 0,
|
# # "lfo_offset": 0,
|
||||||
"profiles": {
|
# "profiles": {
|
||||||
"70cm": {
|
# "70cm": {
|
||||||
"name": "70cm Relais",
|
# "name": "70cm Relais",
|
||||||
"center_freq": 438800000,
|
# "center_freq": 438800000,
|
||||||
"rf_gain": 29,
|
# "rf_gain": 29,
|
||||||
"samp_rate": 2400000,
|
# "samp_rate": 2400000,
|
||||||
"start_freq": 439275000,
|
# "start_freq": 439275000,
|
||||||
"start_mod": "nfm",
|
# "start_mod": "nfm",
|
||||||
},
|
# },
|
||||||
"2m": {
|
# "2m": {
|
||||||
"name": "2m komplett",
|
# "name": "2m komplett",
|
||||||
"center_freq": 145000000,
|
# "center_freq": 145000000,
|
||||||
"rf_gain": 29,
|
# "rf_gain": 29,
|
||||||
"samp_rate": 2048000,
|
# "samp_rate": 2048000,
|
||||||
"start_freq": 145725000,
|
# "start_freq": 145725000,
|
||||||
"start_mod": "nfm",
|
# "start_mod": "nfm",
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
"airspy": {
|
# "airspy": {
|
||||||
"name": "Airspy HF+",
|
# "name": "Airspy HF+",
|
||||||
"type": "airspyhf",
|
# "type": "airspyhf",
|
||||||
"ppm": 0,
|
# "ppm": 0,
|
||||||
"rf_gain": "auto",
|
# "rf_gain": "auto",
|
||||||
"profiles": {
|
# "profiles": {
|
||||||
"20m": {
|
# "20m": {
|
||||||
"name": "20m",
|
# "name": "20m",
|
||||||
"center_freq": 14150000,
|
# "center_freq": 14150000,
|
||||||
"samp_rate": 384000,
|
# "samp_rate": 384000,
|
||||||
"start_freq": 14070000,
|
# "start_freq": 14070000,
|
||||||
"start_mod": "usb",
|
# "start_mod": "usb",
|
||||||
},
|
# },
|
||||||
"30m": {
|
# "30m": {
|
||||||
"name": "30m",
|
# "name": "30m",
|
||||||
"center_freq": 10125000,
|
# "center_freq": 10125000,
|
||||||
"samp_rate": 192000,
|
# "samp_rate": 192000,
|
||||||
"start_freq": 10142000,
|
# "start_freq": 10142000,
|
||||||
"start_mod": "usb",
|
# "start_mod": "usb",
|
||||||
},
|
# },
|
||||||
"40m": {
|
# "40m": {
|
||||||
"name": "40m",
|
# "name": "40m",
|
||||||
"center_freq": 7100000,
|
# "center_freq": 7100000,
|
||||||
"samp_rate": 256000,
|
# "samp_rate": 256000,
|
||||||
"start_freq": 7070000,
|
# "start_freq": 7070000,
|
||||||
"start_mod": "lsb",
|
# "start_mod": "lsb",
|
||||||
},
|
# },
|
||||||
"80m": {
|
# "80m": {
|
||||||
"name": "80m",
|
# "name": "80m",
|
||||||
"center_freq": 3650000,
|
# "center_freq": 3650000,
|
||||||
"samp_rate": 384000,
|
# "samp_rate": 384000,
|
||||||
"start_freq": 3570000,
|
# "start_freq": 3570000,
|
||||||
"start_mod": "lsb",
|
# "start_mod": "lsb",
|
||||||
},
|
# },
|
||||||
"49m": {
|
# "49m": {
|
||||||
"name": "49m Broadcast",
|
# "name": "49m Broadcast",
|
||||||
"center_freq": 6050000,
|
# "center_freq": 6050000,
|
||||||
"samp_rate": 384000,
|
# "samp_rate": 384000,
|
||||||
"start_freq": 6070000,
|
# "start_freq": 6070000,
|
||||||
"start_mod": "am",
|
# "start_mod": "am",
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
"sdrplay": {
|
# "sdrplay": {
|
||||||
"name": "SDRPlay RSP2",
|
# "name": "SDRPlay RSP2",
|
||||||
"type": "sdrplay",
|
# "type": "sdrplay",
|
||||||
"ppm": 0,
|
# "ppm": 0,
|
||||||
"antenna": "Antenna A",
|
# "antenna": "Antenna A",
|
||||||
"profiles": {
|
# "profiles": {
|
||||||
"20m": {
|
# "20m": {
|
||||||
"name": "20m",
|
# "name": "20m",
|
||||||
"center_freq": 14150000,
|
# "center_freq": 14150000,
|
||||||
"rf_gain": 0,
|
# "rf_gain": 0,
|
||||||
"samp_rate": 500000,
|
# "samp_rate": 500000,
|
||||||
"start_freq": 14070000,
|
# "start_freq": 14070000,
|
||||||
"start_mod": "usb",
|
# "start_mod": "usb",
|
||||||
},
|
# },
|
||||||
"30m": {
|
# "30m": {
|
||||||
"name": "30m",
|
# "name": "30m",
|
||||||
"center_freq": 10125000,
|
# "center_freq": 10125000,
|
||||||
"rf_gain": 0,
|
# "rf_gain": 0,
|
||||||
"samp_rate": 250000,
|
# "samp_rate": 250000,
|
||||||
"start_freq": 10142000,
|
# "start_freq": 10142000,
|
||||||
"start_mod": "usb",
|
# "start_mod": "usb",
|
||||||
},
|
# },
|
||||||
"40m": {
|
# "40m": {
|
||||||
"name": "40m",
|
# "name": "40m",
|
||||||
"center_freq": 7100000,
|
# "center_freq": 7100000,
|
||||||
"rf_gain": 0,
|
# "rf_gain": 0,
|
||||||
"samp_rate": 500000,
|
# "samp_rate": 500000,
|
||||||
"start_freq": 7070000,
|
# "start_freq": 7070000,
|
||||||
"start_mod": "lsb",
|
# "start_mod": "lsb",
|
||||||
},
|
# },
|
||||||
"80m": {
|
# "80m": {
|
||||||
"name": "80m",
|
# "name": "80m",
|
||||||
"center_freq": 3650000,
|
# "center_freq": 3650000,
|
||||||
"rf_gain": 0,
|
# "rf_gain": 0,
|
||||||
"samp_rate": 500000,
|
# "samp_rate": 500000,
|
||||||
"start_freq": 3570000,
|
# "start_freq": 3570000,
|
||||||
"start_mod": "lsb",
|
# "start_mod": "lsb",
|
||||||
},
|
# },
|
||||||
"49m": {
|
# "49m": {
|
||||||
"name": "49m Broadcast",
|
# "name": "49m Broadcast",
|
||||||
"center_freq": 6000000,
|
# "center_freq": 6000000,
|
||||||
"rf_gain": 0,
|
# "rf_gain": 0,
|
||||||
"samp_rate": 500000,
|
# "samp_rate": 500000,
|
||||||
"start_freq": 6070000,
|
# "start_freq": 6070000,
|
||||||
"start_mod": "am",
|
# "start_mod": "am",
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
},
|
# },
|
||||||
}
|
#}
|
||||||
|
|
||||||
# ==== Color themes ====
|
# ==== Color themes ====
|
||||||
|
|
||||||
### google turbo colormap (see: https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html)
|
### 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:
|
### original theme by teejez:
|
||||||
#waterfall_colors = [0x000000, 0x0000FF, 0x00FFFF, 0x00FF00, 0xFFFF00, 0xFF0000, 0xFF00FF, 0xFFFFFF]
|
#waterfall_scheme = "TeejeezWaterfall"
|
||||||
|
|
||||||
### old theme by HA7ILM:
|
### old theme by HA7ILM:
|
||||||
#waterfall_colors = [0x000000, 0x2e6893, 0x69a5d0, 0x214b69, 0x9dc4e0, 0xfff775, 0xff8a8a, 0xb20000]
|
#waterfall_scheme = "Ha7ilmWaterfall"
|
||||||
# waterfall_min_level = -115 #in dB
|
|
||||||
# waterfall_max_level = 0
|
|
||||||
# waterfall_auto_level_margin = {"min": 20, "max": 30}
|
|
||||||
##For the old colors, you might also want to set [fft_voverlap_factor] to 0.
|
##For the old colors, you might also want to set [fft_voverlap_factor] to 0.
|
||||||
|
|
||||||
waterfall_min_level = -88 # in dB
|
### custom waterfall schemes can be configured like this:
|
||||||
waterfall_max_level = -20
|
#waterfall_scheme = "CustomWaterfall"
|
||||||
waterfall_auto_level_margin = {"min": 3, "max": 10, "min_range": 50}
|
#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:
|
# 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_levels.min] = [current_min_power_level] - [waterfall_auto_levels["min"]]
|
||||||
# [waterfall_max_level] = [current_max_power_level] + [waterfall_auto_level_margin["max"]]
|
# [waterfall_levels.max] = [current_max_power_level] + [waterfall_auto_levels["max"]]
|
||||||
#
|
#
|
||||||
# ___|________________________________________|____________________________________|________________________________________|___> signal power
|
# ___|__________________________________|____________________________________|__________________________________|___> signal power
|
||||||
# \_waterfall_auto_level_margin["min"]_/ |__ current_min_power_level | \_waterfall_auto_level_margin["max"]_/
|
# \_waterfall_auto_levels["min"]_/ |__ current_min_power_level | \_waterfall_auto_levels["max"]_/
|
||||||
# current_max_power_level __|
|
# current_max_power_level __|
|
||||||
|
|
||||||
# This setting allows you to modify the precision of the frequency displays in OpenWebRX.
|
# 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:
|
# Set this to exponent of 10 to select the most precise digit in Hz you'd like to see
|
||||||
frequency_display_precision = 4
|
# 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.
|
# 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
|
# Lowering this setting will give you a more sensitive squelch, but it may also cause unwanted squelch openings when
|
||||||
# using the auto squelch.
|
# using the auto squelch.
|
||||||
squelch_auto_margin = 10 # in dB
|
#squelch_auto_margin = 10 # in dB
|
||||||
|
|
||||||
# === Experimental settings ===
|
#google_maps_api_key = ""
|
||||||
# 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 = ""
|
|
||||||
|
|
||||||
# how long should positions be visible on the map?
|
# how long should positions be visible on the map?
|
||||||
# they will start fading out after half of that
|
# they will start fading out after half of that
|
||||||
# in seconds; default: 2 hours
|
# in seconds; default: 2 hours
|
||||||
map_position_retention_time = 2 * 60 * 60
|
#map_position_retention_time = 2 * 60 * 60
|
||||||
|
|
||||||
# decoder queue configuration
|
# 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
|
# 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.
|
# 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.
|
# 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)
|
# 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
|
# 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
|
# 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
|
# 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 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
|
# can also be set for each mode separately
|
||||||
# jt65 seems to be somewhat prone to erroneous decodes, this setting handles that to some extent
|
# 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.
|
# 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
|
# 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.
|
# FST4W can be transmitted in different intervals. This setting determines which intervals will be decoded.
|
||||||
# available values (in seconds): 120, 300, 900, 1800
|
# 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 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; higher value will get more results, but will also consume more cpu
|
||||||
js8_decoding_depth = 3
|
#js8_decoding_depth = 3
|
||||||
|
|
||||||
temporary_directory = "/tmp"
|
|
||||||
|
|
||||||
# Enable background service for decoding digital data. You can find more information at:
|
# Enable background service for decoding digital data. You can find more information at:
|
||||||
# https://github.com/jketterl/openwebrx/wiki/Background-decoding
|
# https://github.com/jketterl/openwebrx/wiki/Background-decoding
|
||||||
services_enabled = False
|
#services_enabled = False
|
||||||
services_decoders = ["ft8", "ft4", "wspr", "packet"]
|
#services_decoders = ["ft8", "ft4", "wspr", "packet"]
|
||||||
|
|
||||||
# === aprs igate settings ===
|
# === aprs igate settings ===
|
||||||
# If you want to share your APRS decodes with the aprs network, configure these settings accordingly.
|
# 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.
|
# Make sure that you have set services_enabled to true and customize services_decoders to your needs.
|
||||||
aprs_callsign = "N0CALL"
|
#aprs_callsign = "N0CALL"
|
||||||
aprs_igate_enabled = False
|
#aprs_igate_enabled = False
|
||||||
aprs_igate_server = "euro.aprs2.net"
|
#aprs_igate_server = "euro.aprs2.net"
|
||||||
aprs_igate_password = ""
|
#aprs_igate_password = ""
|
||||||
# beacon uses the receiver_gps setting, so if you enable this, make sure the location is correct there
|
# beacon uses the receiver_gps setting, so if you enable this, make sure the location is correct there
|
||||||
aprs_igate_beacon = False
|
#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"
|
|
||||||
|
|
||||||
# Uncomment the following to customize gateway beacon details reported to the aprs network
|
# 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:
|
# 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 ===
|
# === PSK Reporter settings ===
|
||||||
# enable this if you want to upload all ft8, ft4 etc spots to pskreporter.info
|
# 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
|
# this also uses the receiver_gps setting from above, so make sure it contains a correct locator
|
||||||
pskreporter_enabled = False
|
#pskreporter_enabled = False
|
||||||
pskreporter_callsign = "N0CALL"
|
#pskreporter_callsign = "N0CALL"
|
||||||
# optional antenna information, uncomment to enable
|
# optional antenna information, uncomment to enable
|
||||||
#pskreporter_antenna_information = "Dipole"
|
#pskreporter_antenna_information = "Dipole"
|
||||||
|
|
||||||
# === WSPRNet reporting settings
|
# === WSPRNet reporting settings
|
||||||
# enable this if you want to upload WSPR spots to wsprnet.ort
|
# 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
|
# in addition to these settings also make sure that receiver_gps contains your correct location
|
||||||
wsprnet_enabled = False
|
#wsprnet_enabled = False
|
||||||
wsprnet_callsign = "N0CALL"
|
#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
|
|
||||||
|
@ -28,10 +28,10 @@ import threading
|
|||||||
import math
|
import math
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from owrx.kiss import KissClient, DirewolfConfig
|
from csdr.output import Output
|
||||||
from owrx.wsjt import Ft8Profile, WsprProfile, Jt9Profile, Jt65Profile, Ft4Profile, Fst4Profile, Fst4wProfile
|
|
||||||
from owrx.js8 import Js8Profiles
|
from owrx.kiss import KissClient, DirewolfConfig, DirewolfConfigSubscriber
|
||||||
from owrx.audio import AudioChopper
|
from owrx.audio.chopper import AudioChopper
|
||||||
|
|
||||||
from csdr.pipe import Pipe
|
from csdr.pipe import Pipe
|
||||||
|
|
||||||
@ -40,40 +40,8 @@ import logging
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class output(object):
|
class Dsp(DirewolfConfigSubscriber):
|
||||||
def send_output(self, t, read_fn):
|
def __init__(self, output: Output):
|
||||||
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):
|
|
||||||
self.pycsdr_enabled = True
|
self.pycsdr_enabled = True
|
||||||
self.pycsdr_chain = None
|
self.pycsdr_chain = None
|
||||||
self.buffer = None
|
self.buffer = None
|
||||||
@ -98,9 +66,6 @@ class dsp(object):
|
|||||||
self.decimation = None
|
self.decimation = None
|
||||||
self.last_decimation = None
|
self.last_decimation = None
|
||||||
self.nc_port = None
|
self.nc_port = None
|
||||||
self.csdr_dynamic_bufsize = False
|
|
||||||
self.csdr_print_bufsizes = False
|
|
||||||
self.csdr_through = False
|
|
||||||
self.squelch_level = -150
|
self.squelch_level = -150
|
||||||
self.fft_averages = 50
|
self.fft_averages = 50
|
||||||
self.wfm_deemphasis_tau = 50e-6
|
self.wfm_deemphasis_tau = 50e-6
|
||||||
@ -124,6 +89,7 @@ class dsp(object):
|
|||||||
self.secondary_pipe_names = {"secondary_shift_pipe": Pipe.WRITE}
|
self.secondary_pipe_names = {"secondary_shift_pipe": Pipe.WRITE}
|
||||||
self.secondary_offset_freq = 1000
|
self.secondary_offset_freq = 1000
|
||||||
self.unvoiced_quality = 1
|
self.unvoiced_quality = 1
|
||||||
|
self.codecserver = None
|
||||||
self.modification_lock = threading.Lock()
|
self.modification_lock = threading.Lock()
|
||||||
self.output = output
|
self.output = output
|
||||||
|
|
||||||
@ -133,7 +99,7 @@ class dsp(object):
|
|||||||
|
|
||||||
self.is_service = False
|
self.is_service = False
|
||||||
self.direwolf_config = None
|
self.direwolf_config = None
|
||||||
self.direwolf_port = None
|
self.direwolf_config_path = None
|
||||||
self.process = None
|
self.process = None
|
||||||
|
|
||||||
def setBuffer(self, buffer):
|
def setBuffer(self, buffer):
|
||||||
@ -150,10 +116,6 @@ class dsp(object):
|
|||||||
|
|
||||||
def chain(self, which):
|
def chain(self, which):
|
||||||
chain = ["nc -v 127.0.0.1 {nc_port}"]
|
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}"]
|
chain += ["csdr shift_addfast_cc --fifo {shift_pipe}"]
|
||||||
if self.decimation > 1:
|
if self.decimation > 1:
|
||||||
chain += ["csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING"]
|
chain += ["csdr fir_decimate_cc {decimation} {ddc_transition_bw} HAMMING"]
|
||||||
@ -199,42 +161,42 @@ class dsp(object):
|
|||||||
elif self.isDigitalVoice(which):
|
elif self.isDigitalVoice(which):
|
||||||
chain += ["csdr fmdemod_quadri_cf"]
|
chain += ["csdr fmdemod_quadri_cf"]
|
||||||
chain += last_decimation_block
|
chain += last_decimation_block
|
||||||
# dsd modes
|
chain += ["dc_block"]
|
||||||
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 - ",
|
|
||||||
]
|
|
||||||
# m17
|
# m17
|
||||||
elif which == "m17":
|
if which == "m17":
|
||||||
chain += [
|
chain += [
|
||||||
"csdr limit_ff",
|
"csdr limit_ff",
|
||||||
"csdr convert_f_s16",
|
"csdr convert_f_s16",
|
||||||
"m17-demod",
|
"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:
|
else:
|
||||||
chain += ["dc_block", "rrc_filter", "gfsk_demodulator"]
|
# digiham modes
|
||||||
|
if which == "dstar":
|
||||||
|
chain += [
|
||||||
|
"fsk_demodulator -s 10",
|
||||||
|
"dstar_decoder --fifo {meta_pipe}",
|
||||||
|
"mbe_synthesizer -d {codecserver_arg}",
|
||||||
|
]
|
||||||
|
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":
|
if which == "dmr":
|
||||||
chain += [
|
chain += [
|
||||||
"dmr_decoder --fifo {meta_pipe} --control-fifo {dmr_control_pipe}",
|
"dmr_decoder --fifo {meta_pipe} --control-fifo {dmr_control_pipe}",
|
||||||
"mbe_synthesizer -f -u {unvoiced_quality}",
|
"mbe_synthesizer {codecserver_arg}",
|
||||||
]
|
]
|
||||||
elif which == "ysf":
|
elif which == "ysf":
|
||||||
chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y -f -u {unvoiced_quality}"]
|
chain += ["ysf_decoder --fifo {meta_pipe}", "mbe_synthesizer -y {codecserver_arg}"]
|
||||||
max_gain = 0.005
|
chain += ["digitalvoice_filter"]
|
||||||
chain += [
|
chain += [
|
||||||
"digitalvoice_filter -f",
|
"CSDR_FIXED_BUFSIZE=32 csdr agc_s16 --max 30 --initial 3",
|
||||||
"CSDR_FIXED_BUFSIZE=32 csdr agc_ff --max 0.005 --initial 0.0005",
|
"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 - ",
|
||||||
"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 == "am":
|
elif which == "am":
|
||||||
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
|
chain += ["csdr amdemod_cf", "csdr fastdcblock_ff"]
|
||||||
@ -377,14 +339,10 @@ class dsp(object):
|
|||||||
if_samp_rate=self.if_samp_rate(),
|
if_samp_rate=self.if_samp_rate(),
|
||||||
last_decimation=self.last_decimation,
|
last_decimation=self.last_decimation,
|
||||||
audio_rate=self.get_audio_rate(),
|
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)
|
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"):
|
if self.output.supports_type("secondary_fft"):
|
||||||
secondary_command_fft = " | ".join(self.secondary_chain("fft"))
|
secondary_command_fft = " | ".join(self.secondary_chain("fft"))
|
||||||
secondary_command_fft = secondary_command_fft.format(
|
secondary_command_fft = secondary_command_fft.format(
|
||||||
@ -397,7 +355,7 @@ class dsp(object):
|
|||||||
logger.debug("secondary command (fft) = %s", secondary_command_fft)
|
logger.debug("secondary command (fft) = %s", secondary_command_fft)
|
||||||
|
|
||||||
self.secondary_process_fft = subprocess.Popen(
|
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(
|
self.output.send_output(
|
||||||
"secondary_fft",
|
"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.
|
# 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
|
secondary_output = subprocess.DEVNULL if self.isPacket() else subprocess.PIPE
|
||||||
self.secondary_process_demod = subprocess.Popen(
|
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
|
self.secondary_processes_running = True
|
||||||
|
|
||||||
if self.isWsjtMode():
|
if self.isWsjtMode() or self.isJs8():
|
||||||
smd = self.get_secondary_demodulator()
|
chopper = AudioChopper(self, self.get_secondary_demodulator())
|
||||||
chopper_profiles = None
|
chopper.send_output("audio", self.secondary_process_demod.stdout.read)
|
||||||
if smd == "ft8":
|
output_type = "js8_demod" if self.isJs8() else "wsjt_demod"
|
||||||
chopper_profiles = [Ft8Profile()]
|
self.output.send_output(output_type, chopper.read)
|
||||||
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)
|
|
||||||
elif self.isPacket():
|
elif self.isPacket():
|
||||||
# we best get the ax25 packets from the kiss socket
|
# 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)
|
self.output.send_output("packet_demod", kiss.read)
|
||||||
elif self.isPocsag():
|
elif self.isPocsag():
|
||||||
self.output.send_output("pocsag_demod", self.secondary_process_demod.stdout.readline)
|
self.output.send_output("pocsag_demod", self.secondary_process_demod.stdout.readline)
|
||||||
@ -487,11 +425,16 @@ class dsp(object):
|
|||||||
return self.secondary_demodulator
|
return self.secondary_demodulator
|
||||||
|
|
||||||
def set_secondary_fft_size(self, secondary_fft_size):
|
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.secondary_fft_size = secondary_fft_size
|
||||||
|
self.restart()
|
||||||
|
|
||||||
def set_audio_compression(self, what):
|
def set_audio_compression(self, what):
|
||||||
|
if self.audio_compression == what:
|
||||||
|
return
|
||||||
self.audio_compression = what
|
self.audio_compression = what
|
||||||
|
self.restart()
|
||||||
|
|
||||||
def get_audio_bytes_to_read(self):
|
def get_audio_bytes_to_read(self):
|
||||||
# desired latency: 5ms
|
# desired latency: 5ms
|
||||||
@ -506,6 +449,7 @@ class dsp(object):
|
|||||||
if self.fft_compression == what:
|
if self.fft_compression == what:
|
||||||
return
|
return
|
||||||
self.fft_compression = what
|
self.fft_compression = what
|
||||||
|
self.restart()
|
||||||
|
|
||||||
def get_secondary_fft_bytes_to_read(self):
|
def get_secondary_fft_bytes_to_read(self):
|
||||||
if self.fft_compression == "none":
|
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())
|
(self.decimation, self.last_decimation) = self.get_decimation(self.samp_rate, self.get_audio_rate())
|
||||||
|
|
||||||
def get_decimation(self, input_rate, output_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
|
decimation = 1
|
||||||
target_rate = output_rate
|
target_rate = output_rate
|
||||||
# wideband fm has a much higher frequency deviation (75kHz).
|
# wideband fm has a much higher frequency deviation (75kHz).
|
||||||
@ -571,7 +517,7 @@ class dsp(object):
|
|||||||
def isWsjtMode(self, demodulator=None):
|
def isWsjtMode(self, demodulator=None):
|
||||||
if demodulator is None:
|
if demodulator is None:
|
||||||
demodulator = self.get_secondary_demodulator()
|
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):
|
def isJs8(self, demodulator=None):
|
||||||
if demodulator is None:
|
if demodulator is None:
|
||||||
@ -665,7 +611,7 @@ class dsp(object):
|
|||||||
# no squelch required on digital voice modes
|
# no squelch required on digital voice modes
|
||||||
actual_squelch = (
|
actual_squelch = (
|
||||||
-150
|
-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
|
else self.squelch_level
|
||||||
)
|
)
|
||||||
if self.running:
|
if self.running:
|
||||||
@ -678,6 +624,15 @@ class dsp(object):
|
|||||||
def get_unvoiced_quality(self):
|
def get_unvoiced_quality(self):
|
||||||
return self.unvoiced_quality
|
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):
|
def set_dmr_filter(self, filter):
|
||||||
if self.has_pipe("dmr_control_pipe"):
|
if self.has_pipe("dmr_control_pipe"):
|
||||||
self.pipes["dmr_control_pipe"].write("{0}\n".format(filter))
|
self.pipes["dmr_control_pipe"].write("{0}\n".format(filter))
|
||||||
@ -718,27 +673,34 @@ class dsp(object):
|
|||||||
|
|
||||||
def try_create_configs(self, command):
|
def try_create_configs(self, command):
|
||||||
if "{direwolf_config}" in 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)
|
tmp_dir=self.temporary_directory, myid=id(self)
|
||||||
)
|
)
|
||||||
self.direwolf_port = KissClient.getFreePort()
|
self.direwolf_config = DirewolfConfig()
|
||||||
file = open(self.direwolf_config, "w")
|
self.direwolf_config.wire(self)
|
||||||
file.write(DirewolfConfig().getConfig(self.direwolf_port, self.is_service))
|
file = open(self.direwolf_config_path, "w")
|
||||||
|
file.write(self.direwolf_config.getConfig(self.is_service))
|
||||||
file.close()
|
file.close()
|
||||||
else:
|
else:
|
||||||
self.direwolf_config = None
|
self.direwolf_config = None
|
||||||
self.direwolf_port = None
|
self.direwolf_config_path = None
|
||||||
|
|
||||||
def try_delete_configs(self):
|
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:
|
try:
|
||||||
os.unlink(self.direwolf_config)
|
os.unlink(self.direwolf_config_path)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
# result suits our expectations. fine :)
|
# result suits our expectations. fine :)
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("try_delete_configs()")
|
logger.exception("try_delete_configs()")
|
||||||
self.direwolf_config = None
|
self.direwolf_config_path = None
|
||||||
|
|
||||||
|
def onConfigChanged(self):
|
||||||
|
self.restart()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
with self.modification_lock:
|
with self.modification_lock:
|
||||||
@ -781,19 +743,15 @@ class dsp(object):
|
|||||||
output_rate=self.get_output_rate(),
|
output_rate=self.get_output_rate(),
|
||||||
smeter_report_every=int(self.if_samp_rate() / 6000),
|
smeter_report_every=int(self.if_samp_rate() / 6000),
|
||||||
unvoiced_quality=self.get_unvoiced_quality(),
|
unvoiced_quality=self.get_unvoiced_quality(),
|
||||||
|
codecserver_arg=self.get_codecserver_arg(),
|
||||||
audio_rate=self.get_audio_rate(),
|
audio_rate=self.get_audio_rate(),
|
||||||
wfm_deemphasis_tau=self.wfm_deemphasis_tau,
|
wfm_deemphasis_tau=self.wfm_deemphasis_tau,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug("Command = %s", command)
|
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
|
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():
|
def watch_thread():
|
||||||
rc = self.process.wait()
|
rc = self.process.wait()
|
||||||
@ -837,10 +795,6 @@ class dsp(object):
|
|||||||
|
|
||||||
self.output.send_output("meta", read_meta)
|
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):
|
def stop(self):
|
||||||
with self.modification_lock:
|
with self.modification_lock:
|
||||||
self.running = False
|
self.running = False
|
||||||
@ -859,6 +813,7 @@ class dsp(object):
|
|||||||
self.stop_secondary_demodulator()
|
self.stop_secondary_demodulator()
|
||||||
|
|
||||||
self.try_delete_pipes(self.pipe_names)
|
self.try_delete_pipes(self.pipe_names)
|
||||||
|
self.try_delete_configs()
|
||||||
|
|
||||||
def restart(self):
|
def restart(self):
|
||||||
if not self.running:
|
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
|
* Introduced `squelch_auto_margin` config option that allows configuring the
|
||||||
auto squelch level
|
auto squelch level
|
||||||
* Removed `port` configuration option; `rtltcp_compat` takes the port number
|
* Removed `port` configuration option; `rtltcp_compat` takes the port number
|
||||||
with the new connectors
|
with the new connectors
|
||||||
* Added support for new WSJT-X modes FST4 and FST4W (only available with
|
* Added support for new WSJT-X modes FST4, FST4W (only available with WSJT-X
|
||||||
WSJT-X 2.3)
|
2.3) and Q65 (only available with WSJT-X 2.4)
|
||||||
* Added support for demodulating M17 digital voice signals using
|
* Added support for demodulating M17 digital voice signals using
|
||||||
m17-cxx-demod
|
m17-cxx-demod
|
||||||
* New reporting infrastructure, allowing WSPR and FST4W spots to be sent to
|
* New reporting infrastructure, allowing WSPR and FST4W spots to be sent to
|
||||||
wsprnet.org
|
wsprnet.org
|
||||||
* Add some basic filtering capabilities to the map
|
* 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:
|
* New devices supported:
|
||||||
- HPSDR devices (Hermes Lite 2) (`"type": "hpsdr"`)
|
- HPSDR devices (Hermes Lite 2) thanks to @jancona
|
||||||
- BBRF103 / RX666 / RX888 devices supported by libsddc (`"type": "sddc"`)
|
- BBRF103 / RX666 / RX888 devices supported by libsddc
|
||||||
- Devices using the EB200 protocol (`"type": "eb200"`)
|
- 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
|
openwebrx (0.20.1) buster focal; urgency=low
|
||||||
|
|
||||||
|
4
debian/control
vendored
@ -10,7 +10,7 @@ Vcs-Git: https://github.com/jketterl/openwebrx.git
|
|||||||
|
|
||||||
Package: openwebrx
|
Package: openwebrx
|
||||||
Architecture: all
|
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}
|
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.3), dsd (>= 1.7), sox, direwolf (>= 1.4), wsjtx, eb200-connector, hpsdrconnector, aprs-symbols, m17-demod
|
Recommends: digiham (>= 0.5), sox, direwolf (>= 1.4), wsjtx, runds-connector (>= 0.2), hpsdrconnector, aprs-symbols, m17-demod, js8call
|
||||||
Description: multi-user web sdr
|
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/
|
bands.json etc/openwebrx/
|
||||||
bookmarks.json etc/openwebrx/
|
openwebrx.conf etc/openwebrx/
|
||||||
users.json etc/openwebrx/
|
|
||||||
systemd/openwebrx.service lib/systemd/system/
|
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
|
set -euo pipefail
|
||||||
|
|
||||||
ARCH=$(uname -m)
|
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"
|
ALL_ARCHS="x86_64 armv7l aarch64"
|
||||||
TAG=${TAG:-"latest"}
|
TAG=${TAG:-"latest"}
|
||||||
ARCHTAG="$TAG-$ARCH"
|
ARCHTAG="${TAG}-${ARCH}"
|
||||||
|
|
||||||
usage () {
|
usage () {
|
||||||
echo "Usage: ${0} [command]"
|
echo "Usage: ${0} [command]"
|
||||||
@ -36,7 +36,7 @@ build () {
|
|||||||
|
|
||||||
push () {
|
push () {
|
||||||
for image in ${IMAGES}; do
|
for image in ${IMAGES}; do
|
||||||
docker push jketterl/$image:$ARCHTAG
|
docker push jketterl/${image}:${ARCHTAG}
|
||||||
done
|
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
|
# 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}"
|
rm -rf "${HOME}/.docker/manifests/docker.io_jketterl_${image}-${TAG}"
|
||||||
IMAGE_LIST=""
|
IMAGE_LIST=""
|
||||||
for a in $ALL_ARCHS; do
|
for a in ${ALL_ARCHS}; do
|
||||||
IMAGE_LIST="$IMAGE_LIST jketterl/$image:$TAG-$a"
|
IMAGE_LIST="${IMAGE_LIST} jketterl/${image}:${TAG}-${a}"
|
||||||
done
|
done
|
||||||
docker manifest create jketterl/$image:$TAG $IMAGE_LIST
|
docker manifest create jketterl/${image}:${TAG} ${IMAGE_LIST}
|
||||||
docker manifest push --purge jketterl/$image:$TAG
|
docker manifest push --purge jketterl/${image}:${TAG}
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,16 @@ COPY docker/scripts/install-owrx-tools.sh /
|
|||||||
RUN /install-owrx-tools.sh && \
|
RUN /install-owrx-tools.sh && \
|
||||||
rm /install-owrx-tools.sh
|
rm /install-owrx-tools.sh
|
||||||
|
|
||||||
|
COPY docker/files/services/codecserver /etc/services.d/codecserver
|
||||||
|
|
||||||
ENTRYPOINT ["/init"]
|
ENTRYPOINT ["/init"]
|
||||||
|
|
||||||
WORKDIR /opt/openwebrx
|
WORKDIR /opt/openwebrx
|
||||||
|
|
||||||
VOLUME /etc/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
|
EXPOSE 8073
|
||||||
|
@ -18,10 +18,9 @@ RUN /install-dependencies-rtlsdr.sh &&\
|
|||||||
/install-dependencies-fcdpp.sh &&\
|
/install-dependencies-fcdpp.sh &&\
|
||||||
/install-dependencies-radioberry.sh &&\
|
/install-dependencies-radioberry.sh &&\
|
||||||
/install-dependencies-uhd.sh &&\
|
/install-dependencies-uhd.sh &&\
|
||||||
/install-dependencies-redpitaya.sh &&\
|
|
||||||
/install-dependencies-hpsdr.sh &&\
|
/install-dependencies-hpsdr.sh &&\
|
||||||
/install-connectors.sh &&\
|
/install-connectors.sh &&\
|
||||||
/install-dependencies-eb200.sh &&\
|
/install-dependencies-runds.sh &&\
|
||||||
rm /install-dependencies-*.sh &&\
|
rm /install-dependencies-*.sh &&\
|
||||||
rm /install-lib.*.patch && \
|
rm /install-lib.*.patch && \
|
||||||
rm /install-connectors.sh
|
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
|
FROM openwebrx-base:$ARCHTAG
|
||||||
|
|
||||||
COPY docker/scripts/install-connectors.sh \
|
COPY docker/scripts/install-connectors.sh \
|
||||||
docker/scripts/install-dependencies-eb200.sh /
|
docker/scripts/install-dependencies-runds.sh /
|
||||||
|
|
||||||
RUN /install-connectors.sh &&\
|
RUN /install-connectors.sh &&\
|
||||||
rm /install-connectors.sh && \
|
rm /install-connectors.sh && \
|
||||||
/install-dependencies-eb200.sh && \
|
/install-dependencies-runds.sh && \
|
||||||
rm /install-dependencies-eb200.sh
|
rm /install-dependencies-runds.sh
|
||||||
|
|
||||||
COPY . /opt/openwebrx
|
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.orig 2021-03-30 15:28:36.956587995 +0200
|
||||||
+++ CMakeLists.txt 2020-07-21 21:01:25.444836112 +0200
|
+++ CMakeLists.txt 2021-03-30 15:29:45.719326832 +0200
|
||||||
@@ -80,24 +80,6 @@
|
@@ -106,24 +106,6 @@
|
||||||
|
|
||||||
include (ExternalProject)
|
|
||||||
|
|
||||||
-
|
#
|
||||||
-#
|
|
||||||
-# build and install hamlib locally so it can be referenced by the
|
-# build and install hamlib locally so it can be referenced by the
|
||||||
-# WSJT-X build
|
-# WSJT-X build
|
||||||
-#
|
-#
|
||||||
-ExternalProject_Add (hamlib
|
-ExternalProject_Add (hamlib
|
||||||
- GIT_REPOSITORY ${hamlib_repo}
|
- GIT_REPOSITORY ${hamlib_repo}
|
||||||
- GIT_TAG ${hamlib_TAG}
|
- 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}
|
- URL_HASH MD5=${hamlib_md5sum}
|
||||||
- #UPDATE_COMMAND ${CMAKE_COMMAND} -E env "[ -f ./bootstrap ] && ./bootstrap"
|
- #UPDATE_COMMAND ${CMAKE_COMMAND} -E env "[ -f ./bootstrap ] && ./bootstrap"
|
||||||
- PATCH_COMMAND ${PATCH_EXECUTABLE} -p1 -N < ${CMAKE_CURRENT_SOURCE_DIR}/hamlib.patch
|
- PATCH_COMMAND ${PATCH_EXECUTABLE} -p1 -N < ${CMAKE_CURRENT_SOURCE_DIR}/hamlib.patch
|
||||||
@ -22,10 +21,11 @@
|
|||||||
- STEP_TARGETS update install
|
- STEP_TARGETS update install
|
||||||
- )
|
- )
|
||||||
-
|
-
|
||||||
#
|
-#
|
||||||
# custom target to make a hamlib source tarball
|
# 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
|
# build and optionally install WSJT-X using the hamlib package built
|
||||||
# above
|
# above
|
||||||
#
|
#
|
||||||
@ -33,11 +33,18 @@
|
|||||||
ExternalProject_Add (wsjtx
|
ExternalProject_Add (wsjtx
|
||||||
GIT_REPOSITORY ${wsjtx_repo}
|
GIT_REPOSITORY ${wsjtx_repo}
|
||||||
GIT_TAG ${WSJTX_TAG}
|
GIT_TAG ${WSJTX_TAG}
|
||||||
@@ -160,7 +141,6 @@
|
@@ -186,14 +167,8 @@
|
||||||
DEPENDEES build
|
DEPENDEES build
|
||||||
)
|
)
|
||||||
|
|
||||||
-set_target_properties (hamlib PROPERTIES EXCLUDE_FROM_ALL 1)
|
-set_target_properties (hamlib PROPERTIES EXCLUDE_FROM_ALL 1)
|
||||||
set_target_properties (wsjtx 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
|
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-orig/CMake/Modules/Findhamlib.cmake 2021-05-31 18:56:20.657682124 +0200
|
||||||
+++ wsjtx/CMake/Modules/Findhamlib.cmake 2020-07-21 21:11:03.368019114 +0200
|
+++ wsjtx/CMake/Modules/Findhamlib.cmake 2021-05-31 18:57:03.963994898 +0200
|
||||||
@@ -85,4 +85,4 @@
|
@@ -85,4 +85,4 @@
|
||||||
# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to
|
# Handle the QUIETLY and REQUIRED arguments and set HAMLIB_FOUND to
|
||||||
# TRUE if all listed variables are TRUE
|
# 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 hamlib_LIBRARY_DIRS)
|
||||||
+find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES)
|
+find_package_handle_standard_args (hamlib DEFAULT_MSG hamlib_INCLUDE_DIRS hamlib_LIBRARIES)
|
||||||
diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
||||||
--- wsjtx-orig/CMakeLists.txt 2020-07-21 21:10:43.124810140 +0200
|
--- wsjtx-orig/CMakeLists.txt 2021-05-31 18:56:20.657682124 +0200
|
||||||
+++ wsjtx/CMakeLists.txt 2020-07-21 22:14:04.454639589 +0200
|
+++ wsjtx/CMakeLists.txt 2021-05-31 19:08:02.768474060 +0200
|
||||||
@@ -871,7 +871,7 @@
|
@@ -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
|
# libhamlib setup
|
||||||
#
|
#
|
||||||
@ -19,31 +103,47 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
|||||||
find_package (hamlib 3 REQUIRED)
|
find_package (hamlib 3 REQUIRED)
|
||||||
find_program (RIGCTL_EXE rigctl)
|
find_program (RIGCTL_EXE rigctl)
|
||||||
find_program (RIGCTLD_EXE rigctld)
|
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
|
-# 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
|
-add_executable (wsjtx MACOSX_BUNDLE
|
||||||
- ${wsjtx_CXXSRCS}
|
- ${wsjtx_CXXSRCS}
|
||||||
- ${wsjtx_GENUISRCS}
|
- ${wsjtx_GENUISRCS}
|
||||||
- wsjtx.rc
|
|
||||||
- ${WSJTX_ICON_FILE}
|
- ${WSJTX_ICON_FILE}
|
||||||
- ${wsjtx_RESOURCES_RCC}
|
- ${wsjtx_RESOURCES_RCC}
|
||||||
|
- ${wsjtx_VERSION_RESOURCES}
|
||||||
- )
|
- )
|
||||||
-
|
-
|
||||||
if (WSJT_CREATE_WINMAIN)
|
-if (WSJT_CREATE_WINMAIN)
|
||||||
set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
- set_target_properties (wsjtx PROPERTIES WIN32_EXECUTABLE ON)
|
||||||
endif (WSJT_CREATE_WINMAIN)
|
-endif (WSJT_CREATE_WINMAIN)
|
||||||
|
-
|
||||||
-set_target_properties (wsjtx PROPERTIES
|
-set_target_properties (wsjtx PROPERTIES
|
||||||
- MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
|
- 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_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||||
- MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION}
|
- MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
|
||||||
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}"
|
- MACOSX_BUNDLE_SHORT_VERSION_STRING "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
|
||||||
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}"
|
- MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${SCS_VERSION_STR}"
|
||||||
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}"
|
- MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_BUNDLE_NAME}"
|
||||||
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
- MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
||||||
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
- MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
||||||
- MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
- 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})
|
-target_include_directories (wsjtx PRIVATE ${FFTW3_INCLUDE_DIRS})
|
||||||
-if (APPLE)
|
-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 ()
|
-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)
|
- if (OpenMP_C_FLAGS)
|
||||||
- set_target_properties (wsjtx PROPERTIES
|
- set_target_properties (wsjtx PROPERTIES
|
||||||
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
- COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||||
@ -65,18 +165,42 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
|||||||
- )
|
- )
|
||||||
- if (WIN32)
|
- if (WIN32)
|
||||||
- set_target_properties (wsjtx PROPERTIES
|
- set_target_properties (wsjtx PROPERTIES
|
||||||
- LINK_FLAGS -Wl,--stack,16777216
|
- LINK_FLAGS -Wl,--stack,0x1000000,--heap,0x20000000
|
||||||
- )
|
- )
|
||||||
- endif ()
|
- endif ()
|
||||||
-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
|
# make a library for WSJT-X UDP servers
|
||||||
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
# add_library (wsjtx_udp SHARED ${UDP_library_CXXSRCS})
|
||||||
add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
|
add_library (wsjtx_udp-static STATIC ${UDP_library_CXXSRCS})
|
||||||
@@ -1437,24 +1394,9 @@
|
@@ -1473,47 +1349,9 @@
|
||||||
set_target_properties (message_aggregator PROPERTIES WIN32_EXECUTABLE ON)
|
add_executable (wsjtx_app_version AppVersion/AppVersion.cpp ${wsjtx_app_version_VERSION_RESOURCES})
|
||||||
endif (WSJT_CREATE_WINMAIN)
|
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 (UNIX)
|
||||||
- if (NOT WSJT_SKIP_MANPAGES)
|
- if (NOT WSJT_SKIP_MANPAGES)
|
||||||
- add_subdirectory (manpages)
|
- add_subdirectory (manpages)
|
||||||
@ -98,21 +222,21 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
|||||||
|
|
||||||
# install (TARGETS wsjtx_udp EXPORT udp
|
# install (TARGETS wsjtx_udp EXPORT udp
|
||||||
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
# RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
@@ -1473,12 +1415,7 @@
|
@@ -1532,12 +1370,7 @@
|
||||||
# DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wsjtx
|
# 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
|
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||||
- BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
- BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||||
- )
|
- )
|
||||||
-
|
-
|
||||||
-install (TARGETS jt9 wsprd fmtave fcal fmeasure
|
-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
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||||
BUNDLE 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)
|
endif(WSJT_BUILD_UTILS)
|
||||||
|
|
||||||
@ -143,13 +267,50 @@ diff -ur wsjtx-orig/CMakeLists.txt wsjtx/CMakeLists.txt
|
|||||||
- AUTHORS
|
- AUTHORS
|
||||||
- THANKS
|
- THANKS
|
||||||
- NEWS
|
- NEWS
|
||||||
- INSTALL
|
|
||||||
- BUGS
|
- BUGS
|
||||||
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
- DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||||
- #COMPONENT runtime
|
- #COMPONENT runtime
|
||||||
- )
|
- )
|
||||||
-
|
-
|
||||||
install (FILES
|
install (FILES
|
||||||
contrib/Ephemeris/JPLEPH
|
cty.dat
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
|
cty.dat_copyright.txt
|
||||||
Only in wsjtx: .idea
|
@@ -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
|
apt-get -y install --no-install-recommends $BUILD_PACKAGES
|
||||||
|
|
||||||
git clone https://github.com/jketterl/owrx_connector.git
|
git clone https://github.com/jketterl/owrx_connector.git
|
||||||
# latest develop as of 2020-11-28 (int32 samples; debhelper)
|
# latest develop as of 2021-05-18 (individual connector versions)
|
||||||
cmakebuild owrx_connector 87a2fcc54e221aad71ec0700737ca7f385c388de
|
cmakebuild owrx_connector 167324219813f61b2be8164eb4acb1237ba2c304
|
||||||
|
|
||||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||||
apt-get clean
|
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 update
|
||||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||||
|
|
||||||
git clone https://github.com/jketterl/eb200_connector.git
|
git clone https://github.com/jketterl/runds_connector.git
|
||||||
# latest from develop as of 2020-12-01
|
# latest develop as of 2021-05-18 (individual connector versions)
|
||||||
cmakebuild eb200_connector 9c8313770c1072df72d2fdb85307ca206c29c60a
|
cmakebuild runds_connector adfa04bee4ee36852feb07e7b845be2c3d3f97c7
|
||||||
|
|
||||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||||
apt-get clean
|
apt-get clean
|
@ -48,9 +48,9 @@ cd ..
|
|||||||
rm -rf sdrplay
|
rm -rf sdrplay
|
||||||
rm $BINARY
|
rm $BINARY
|
||||||
|
|
||||||
git clone https://github.com/SDRplay/SoapySDRPlay.git
|
git clone https://github.com/pothosware/SoapySDRPlay3.git
|
||||||
# latest from master as of 2020-09-04
|
# latest from master as of 2021-06-19 (reliability fixes)
|
||||||
cmakebuild SoapySDRPlay 105f8a6b3d449982d7ef860790c201aa066b8fa9
|
cmakebuild SoapySDRPlay3 a869f25364a1f0d5b16169ff908aa21a2ace475d
|
||||||
|
|
||||||
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
SUDO_FORCE_REMOVE=yes apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
@ -18,8 +18,8 @@ function cmakebuild() {
|
|||||||
|
|
||||||
cd /tmp
|
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"
|
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"
|
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 update
|
||||||
apt-get -y install auto-apt-proxy
|
apt-get -y install auto-apt-proxy
|
||||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
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 /
|
tar xzf s6-overlay-${PLATFORM}.tar.gz -C /
|
||||||
rm s6-overlay-${PLATFORM}.tar.gz
|
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_VERSION=2.2.0
|
||||||
JS8CALL_DIR=js8call
|
JS8CALL_DIR=js8call
|
||||||
JS8CALL_TGZ=js8call-${JS8CALL_VERSION}.tgz
|
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}
|
CMAKE_ARGS="-D CMAKE_CXX_FLAGS=-DJS8_USE_HAMLIB_THREE" cmakebuild ${JS8CALL_DIR}
|
||||||
rm ${JS8CALL_TGZ}
|
rm ${JS8CALL_TGZ}
|
||||||
|
|
||||||
WSJT_DIR=wsjtx-2.2.2
|
WSJT_DIR=wsjtx-2.4.0
|
||||||
WSJT_TGZ=${WSJT_DIR}.tgz
|
WSJT_TGZ=${WSJT_DIR}.tgz
|
||||||
wget http://physics.princeton.edu/pulsar/k1jt/${WSJT_TGZ}
|
wget http://physics.princeton.edu/pulsar/k1jt/${WSJT_TGZ}
|
||||||
tar xfz ${WSJT_TGZ}
|
tar xfz ${WSJT_TGZ}
|
||||||
@ -111,12 +102,14 @@ rm -rf dream
|
|||||||
rm dream-2.1.1-svn808.tar.gz
|
rm dream-2.1.1-svn808.tar.gz
|
||||||
|
|
||||||
git clone https://github.com/mobilinkd/m17-cxx-demod.git
|
git clone https://github.com/mobilinkd/m17-cxx-demod.git
|
||||||
# latest master as of 2020-12-27 (new sync words)
|
# latest master as of 2021-04-20
|
||||||
cmakebuild m17-cxx-demod 2b84657676efb3b07b33de3ab3d0a6218e9d88b5
|
cmakebuild m17-cxx-demod c1d954fd5e5c53d28a2524e99484f832f9dcb826
|
||||||
|
|
||||||
git clone https://github.com/hessu/aprs-symbols /usr/share/aprs-symbols
|
git clone https://github.com/hessu/aprs-symbols /usr/share/aprs-symbols
|
||||||
pushd /usr/share/aprs-symbols
|
pushd /usr/share/aprs-symbols
|
||||||
git checkout 5c2abe2658ee4d2563f3c73b90c6f59124839802
|
git checkout 5c2abe2658ee4d2563f3c73b90c6f59124839802
|
||||||
|
# remove unused files (including git meta information)
|
||||||
|
rm -rf .git aprs-symbols.ai aprs-sym-export.js
|
||||||
popd
|
popd
|
||||||
|
|
||||||
apt-get -y purge --autoremove $BUILD_PACKAGES
|
apt-get -y purge --autoremove $BUILD_PACKAGES
|
||||||
|
@ -18,8 +18,8 @@ function cmakebuild() {
|
|||||||
|
|
||||||
cd /tmp
|
cd /tmp
|
||||||
|
|
||||||
STATIC_PACKAGES="libfftw3-bin"
|
STATIC_PACKAGES="libfftw3-bin libprotobuf17"
|
||||||
BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++"
|
BUILD_PACKAGES="git autoconf automake libtool libfftw3-dev pkg-config cmake make gcc g++ libprotobuf-dev protobuf-compiler"
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
apt-get -y install --no-install-recommends $STATIC_PACKAGES $BUILD_PACKAGES
|
||||||
|
|
||||||
@ -40,8 +40,15 @@ make install
|
|||||||
cd ..
|
cd ..
|
||||||
rm -rf csdr
|
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
|
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 -y purge --autoremove $BUILD_PACKAGES
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
@ -1,19 +1,25 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
mkdir -p /etc/openwebrx/
|
mkdir -p /etc/openwebrx/openwebrx.conf.d
|
||||||
|
mkdir -p /var/lib/openwebrx
|
||||||
mkdir -p /tmp/openwebrx/
|
mkdir -p /tmp/openwebrx/
|
||||||
if [[ ! -f /etc/openwebrx/config_webrx.py ]] ; then
|
if [[ ! -f /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf ]] ; then
|
||||||
sed 's/temporary_directory = "\/tmp"/temporary_directory = "\/tmp\/openwebrx"/' < "/opt/openwebrx/config_webrx.py" > "/etc/openwebrx/config_webrx.py"
|
cat << EOF > /etc/openwebrx/openwebrx.conf.d/20-temporary-directory.conf
|
||||||
|
[core]
|
||||||
|
temporary_directory = /tmp/openwebrx
|
||||||
|
EOF
|
||||||
fi
|
fi
|
||||||
if [[ ! -f /etc/openwebrx/bands.json ]] ; then
|
if [[ ! -f /etc/openwebrx/bands.json ]] ; then
|
||||||
cp bands.json /etc/openwebrx/
|
cp bands.json /etc/openwebrx/
|
||||||
fi
|
fi
|
||||||
if [[ ! -f /etc/openwebrx/bookmarks.json ]] ; then
|
if [[ ! -f /etc/openwebrx/openwebrx.conf ]] ; then
|
||||||
cp bookmarks.json /etc/openwebrx/
|
cp openwebrx.conf /etc/openwebrx/
|
||||||
fi
|
fi
|
||||||
if [[ ! -f /etc/openwebrx/users.json ]] ; then
|
if [[ ! -z "${OPENWEBRX_ADMIN_USER:-}" ]] && [[ ! -z "${OPENWEBRX_ADMIN_PASSWORD:-}" ]] ; then
|
||||||
cp users.json /etc/openwebrx/
|
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
|
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-header.css");
|
||||||
@import url("openwebrx-globals.css");
|
@import url("openwebrx-globals.css");
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin-bottom: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background: #444;
|
||||||
|
}
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #222;
|
||||||
|
z-index: 2;
|
||||||
|
padding: 10px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
border-top: 1px solid #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row .map-input {
|
.row .map-input {
|
||||||
margin: 15px 15px 0;
|
margin: 15px 15px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.device {
|
.settings-section h3 {
|
||||||
margin-top: 20px;
|
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-header.css");
|
||||||
@import url("openwebrx-globals.css");
|
@import url("openwebrx-globals.css");
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.login {
|
.login {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
@ -6,10 +6,6 @@ body {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-top-container {
|
|
||||||
flex: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openwebrx-map {
|
.openwebrx-map {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
@ -5,21 +5,3 @@ html, body
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
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;
|
position: relative;
|
||||||
z-index:1000;
|
z-index:1000;
|
||||||
background-color: #575757;
|
background-color: #575757;
|
||||||
@ -12,7 +12,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-description-container {
|
.openwebrx-description-container {
|
||||||
transition-property: height, opacity;
|
transition-property: height, opacity;
|
||||||
transition-duration: 1s;
|
transition-duration: 1s;
|
||||||
transition-timing-function: ease-out;
|
transition-timing-function: ease-out;
|
||||||
@ -23,12 +23,12 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-description-container.expanded {
|
.openwebrx-description-container.expanded {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
height: 283px;
|
height: 283px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.webrx-top-bar-parts {
|
.webrx-top-bar {
|
||||||
height:67px;
|
height:67px;
|
||||||
|
|
||||||
background: rgba(128, 128, 128, 0.15);
|
background: rgba(128, 128, 128, 0.15);
|
||||||
@ -46,26 +46,27 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.webrx-top-bar-parts > * {
|
.webrx-top-bar > * {
|
||||||
flex: 0;
|
flex: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-top-container, #webrx-top-container * {
|
.webrx-top-container, .webrx-top-container * {
|
||||||
line-height: initial;
|
line-height: initial;
|
||||||
box-sizing: initial;
|
box-sizing: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-top-logo {
|
.webrx-top-logo {
|
||||||
|
width: 261px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
filter: drop-shadow(0 0 2.5px rgba(0, 0, 0, .9));
|
||||||
/* overwritten by media queries */
|
/* overwritten by media queries */
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-avatar {
|
.webrx-rx-avatar {
|
||||||
background-color: rgba(154, 154, 154, .5);
|
background-color: rgba(154, 154, 154, .5);
|
||||||
margin: 7px;
|
margin: 7px;
|
||||||
|
|
||||||
cursor:pointer;
|
|
||||||
width: 46px;
|
width: 46px;
|
||||||
height: 46px;
|
height: 46px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
@ -73,82 +74,66 @@
|
|||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-texts {
|
.webrx-rx-texts {
|
||||||
/* minimum layout width */
|
/* minimum layout width */
|
||||||
width: 0;
|
width: 0;
|
||||||
/* will be getting wider with flex */
|
/* will be getting wider with flex */
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
margin: auto 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-texts div {
|
.webrx-rx-texts div, .webrx-rx-texts h1 {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
white-space:nowrap;
|
white-space:nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor:pointer;
|
|
||||||
color: #909090;
|
color: #909090;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-texts div:first-child {
|
.webrx-rx-title {
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#webrx-rx-title {
|
|
||||||
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
font-family: "DejaVu Sans", Verdana, Geneva, sans-serif;
|
||||||
font-size: 11pt;
|
font-size: 11pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-desc {
|
.webrx-rx-desc {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-rx-details-arrow {
|
.openwebrx-main-buttons .button {
|
||||||
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 {
|
|
||||||
display: block;
|
display: block;
|
||||||
width: 55px;
|
width: 55px;
|
||||||
cursor:pointer;
|
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 */
|
/* will be enabled by javascript if the panel is present in the DOM */
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-main-buttons .button img {
|
.openwebrx-main-buttons .button img,
|
||||||
|
.openwebrx-main-buttons .button svg {
|
||||||
height: 38px;
|
height: 38px;
|
||||||
|
filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-main-buttons a {
|
.openwebrx-main-buttons a {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: inherit;
|
text-decoration: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-main-buttons .button:hover {
|
.openwebrx-main-buttons .button:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.3);
|
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);
|
background-color: rgba(255, 255, 255, 0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#openwebrx-main-buttons {
|
.openwebrx-main-buttons {
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
@ -160,7 +145,7 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-photo-title {
|
.webrx-rx-photo-title {
|
||||||
margin: 10px 15px;
|
margin: 10px 15px;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 16pt;
|
font-size: 16pt;
|
||||||
@ -168,7 +153,7 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-photo-desc {
|
.webrx-rx-photo-desc {
|
||||||
margin: 10px 15px;
|
margin: 10px 15px;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
@ -178,17 +163,21 @@
|
|||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#webrx-rx-photo-desc a {
|
.webrx-rx-photo-desc a {
|
||||||
color: #5ca8ff;
|
color: #5ca8ff;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openwebrx-photo-trigger {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Responsive stuff
|
* Responsive stuff
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@media (min-width: 576px) {
|
@media (min-width: 576px) {
|
||||||
#webrx-rx-texts {
|
.webrx-rx-texts {
|
||||||
display: initial;
|
display: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,7 +186,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 992px) {
|
@media (min-width: 992px) {
|
||||||
#webrx-top-logo {
|
.webrx-top-logo {
|
||||||
display: initial;
|
display: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,47 +195,33 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sprites (images)
|
* RX details arrow up/down switching
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.sprite-panel-status {
|
.openwebrx-rx-details-arrow {
|
||||||
background-position: 0 0;
|
position: absolute;
|
||||||
width: 44px;
|
bottom: 0;
|
||||||
height: 38px;
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 0;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-panel-log {
|
.openwebrx-rx-details-arrow svg {
|
||||||
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;
|
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-rx-details-arrow-up {
|
.openwebrx-rx-details-arrow .up {
|
||||||
background-position: -43px -65px;
|
display: none;
|
||||||
width: 43px;
|
}
|
||||||
height: 12px;
|
|
||||||
|
.openwebrx-rx-details-arrow--up .down {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openwebrx-rx-details-arrow--up .up {
|
||||||
|
display: initial;
|
||||||
}
|
}
|
@ -36,15 +36,14 @@ input
|
|||||||
vertical-align:middle;
|
vertical-align:middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=range]
|
input[type=range] {
|
||||||
{
|
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
margin: 0 0;
|
margin: 0 0;
|
||||||
background: transparent;
|
background: transparent !important;
|
||||||
--track-background: #B6B6B6;
|
--track-background: #B6B6B6;
|
||||||
}
|
}
|
||||||
input[type=range]:focus
|
|
||||||
{
|
input[type=range]:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,11 +296,13 @@ input[type=range]:disabled {
|
|||||||
#webrx-canvas-container canvas
|
#webrx-canvas-container canvas
|
||||||
{
|
{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
border-style: none;
|
border-style: none;
|
||||||
image-rendering: crisp-edges;
|
image-rendering: crisp-edges;
|
||||||
image-rendering: -webkit-optimize-contrast;
|
image-rendering: -webkit-optimize-contrast;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-log-scroll
|
#openwebrx-log-scroll
|
||||||
@ -336,12 +337,58 @@ input[type=range]:disabled {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.webrx-actual-freq > * {
|
.webrx-actual-freq > * {
|
||||||
flex: 1;
|
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 {
|
.webrx-actual-freq input {
|
||||||
font-family: 'roboto-mono';
|
font-family: 'roboto-mono';
|
||||||
width: 0;
|
width: 0;
|
||||||
@ -355,7 +402,10 @@ input[type=range]:disabled {
|
|||||||
.webrx-actual-freq, .webrx-actual-freq input {
|
.webrx-actual-freq, .webrx-actual-freq input {
|
||||||
font-size: 16pt;
|
font-size: 16pt;
|
||||||
font-family: 'roboto-mono';
|
font-family: 'roboto-mono';
|
||||||
line-height: 22px;
|
}
|
||||||
|
|
||||||
|
.webrx-actual-freq .digit {
|
||||||
|
cursor: ns-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.webrx-actual-freq .digit:hover {
|
.webrx-actual-freq .digit:hover {
|
||||||
@ -552,6 +602,7 @@ img.openwebrx-mirror-img
|
|||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
z-index: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-progressbar-bar {
|
.openwebrx-progressbar-bar {
|
||||||
@ -564,6 +615,7 @@ img.openwebrx-mirror-img
|
|||||||
transition-timing-function: ease-in-out;
|
transition-timing-function: ease-in-out;
|
||||||
transform: translate(-100%) translateZ(0);
|
transform: translate(-100%) translateZ(0);
|
||||||
will-change: transform, background-color;
|
will-change: transform, background-color;
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-progressbar--over .openwebrx-progressbar-bar {
|
.openwebrx-progressbar--over .openwebrx-progressbar-bar {
|
||||||
@ -573,11 +625,11 @@ img.openwebrx-mirror-img
|
|||||||
.openwebrx-progressbar-text
|
.openwebrx-progressbar-text
|
||||||
{
|
{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left:50;
|
left:50%;
|
||||||
top:50%;
|
top:50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
z-index: 1;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-panel-status
|
#openwebrx-panel-status
|
||||||
@ -602,6 +654,7 @@ img.openwebrx-mirror-img
|
|||||||
#openwebrx-panel-receiver .frequencies-container {
|
#openwebrx-panel-receiver .frequencies-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-panel-receiver .frequencies {
|
#openwebrx-panel-receiver .frequencies {
|
||||||
@ -614,16 +667,6 @@ img.openwebrx-mirror-img
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-mute-on
|
|
||||||
{
|
|
||||||
color: lime;
|
|
||||||
}
|
|
||||||
|
|
||||||
#openwebrx-mute-off
|
|
||||||
{
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openwebrx-panel-slider
|
.openwebrx-panel-slider
|
||||||
{
|
{
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -631,13 +674,6 @@ img.openwebrx-mirror-img
|
|||||||
width: 95px;
|
width: 95px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-sliderbtn-img
|
|
||||||
{
|
|
||||||
width: 14px;
|
|
||||||
position:relative;
|
|
||||||
top: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openwebrx-panel-line
|
.openwebrx-panel-line
|
||||||
{
|
{
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
@ -714,7 +750,7 @@ img.openwebrx-mirror-img
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-overlay {
|
.openwebrx-overlay {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -735,8 +771,7 @@ img.openwebrx-mirror-img
|
|||||||
transition: opacity 0.3s linear;
|
transition: opacity 0.3s linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
#openwebrx-autoplay-overlay img
|
#openwebrx-autoplay-overlay svg {
|
||||||
{
|
|
||||||
width: 150px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -768,11 +803,14 @@ img.openwebrx-mirror-img
|
|||||||
#openwebrx-digimode-canvas-container canvas
|
#openwebrx-digimode-canvas-container canvas
|
||||||
{
|
{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition: width 500ms, left 500ms;
|
transition: width 500ms, left 500ms;
|
||||||
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-panel select,
|
.openwebrx-panel select,
|
||||||
|
.openwebrx-panel input,
|
||||||
.openwebrx-dialog select,
|
.openwebrx-dialog select,
|
||||||
.openwebrx-dialog input {
|
.openwebrx-dialog input {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@ -781,11 +819,26 @@ img.openwebrx-mirror-img
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 13pt;
|
font-size: 13pt;
|
||||||
margin-right: 1px;
|
margin-right: 1px;
|
||||||
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.0 , #373737), color-stop(1, #4F4F4F) );
|
background:linear-gradient(#373737, #4F4F4F);
|
||||||
background:-moz-linear-gradient( center top, #373737 0%, #4F4F4F 100% );
|
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border-width: 0px;
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports(-moz-appearance: none) {
|
||||||
|
.openwebrx-panel select,
|
||||||
|
.openwebrx-dialog select {
|
||||||
-moz-appearance: none;
|
-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,
|
.openwebrx-panel select option,
|
||||||
@ -912,6 +965,8 @@ img.openwebrx-mirror-img
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
/* compatibility with iOS 14.2 */
|
||||||
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot {
|
.openwebrx-meta-slot {
|
||||||
@ -928,26 +983,22 @@ img.openwebrx-mirror-img
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot > * {
|
.openwebrx-meta-slot > * {
|
||||||
flex: 0;
|
flex: 1 0 0;
|
||||||
flex-basis: 1.2em;
|
|
||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot, .openwebrx-meta-slot.muted:before {
|
.openwebrx-meta-slot, .openwebrx-meta-slot .mute {
|
||||||
-webkit-border-radius: 5px;
|
-webkit-border-radius: 5px;
|
||||||
-moz-border-radius: 5px;
|
-moz-border-radius: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot.muted:before {
|
.openwebrx-meta-slot .mute {
|
||||||
display: block;
|
display: none;
|
||||||
content: "";
|
|
||||||
background-image: url("../gfx/openwebrx-mute.png");
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -958,6 +1009,17 @@ img.openwebrx-mirror-img
|
|||||||
background-color: rgba(0,0,0,.3);
|
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 {
|
.openwebrx-meta-slot.active {
|
||||||
background-color: #95bbdf;
|
background-color: #95bbdf;
|
||||||
}
|
}
|
||||||
@ -974,18 +1036,29 @@ img.openwebrx-mirror-img
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot .openwebrx-meta-user-image {
|
.openwebrx-meta-slot .openwebrx-meta-user-image {
|
||||||
flex: 1;
|
flex: 0 1 100%;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
line-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image,
|
.openwebrx-meta-slot .openwebrx-meta-user-image img {
|
||||||
#openwebrx-panel-metadata-ysf .openwebrx-meta-slot.active .openwebrx-meta-user-image {
|
max-width: 100%;
|
||||||
background-image: url("../gfx/openwebrx-directcall.png");
|
max-height: 100%;
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-meta-slot.active.group .openwebrx-meta-user-image {
|
.openwebrx-meta-slot.active.direct .openwebrx-meta-user-image .directcall,
|
||||||
background-image: url("../gfx/openwebrx-groupcall.png");
|
.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 {
|
.openwebrx-meta-slot.group .openwebrx-dmr-target:not(:empty):before {
|
||||||
@ -998,6 +1071,7 @@ img.openwebrx-mirror-img
|
|||||||
|
|
||||||
.openwebrx-dmr-timeslot-panel * {
|
.openwebrx-dmr-timeslot-panel * {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-ysf-mode:not(:empty):before {
|
.openwebrx-ysf-mode:not(:empty):before {
|
||||||
@ -1012,14 +1086,30 @@ img.openwebrx-mirror-img
|
|||||||
content: "Down: ";
|
content: "Down: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-maps-pin {
|
.openwebrx-dstar-yourcall:not(:empty):before {
|
||||||
background-image: url("../gfx/google_maps_pin.svg");
|
content: "UR: ";
|
||||||
background-position: center;
|
}
|
||||||
background-repeat: no-repeat;
|
|
||||||
|
.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;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
background-size: contain;
|
vertical-align: middle;
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-message-panel {
|
.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="js8"] #openwebrx-digimode-content-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="fst4"] #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="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="ft8"] #openwebrx-digimode-select-channel,
|
||||||
#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel,
|
#openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel,
|
||||||
#openwebrx-panel-digimodes[data-mode="jt65"] #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="pocsag"] #openwebrx-digimode-select-channel,
|
||||||
#openwebrx-panel-digimodes[data-mode="js8"] #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="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;
|
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="pocsag"] #openwebrx-digimode-canvas-container,
|
||||||
#openwebrx-panel-digimodes[data-mode="js8"] #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="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;
|
height: 200px;
|
||||||
margin: -10px;
|
margin: -10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-zoom-in {
|
.openwebrx-zoom-button svg {
|
||||||
background-position: 0 -38px;
|
|
||||||
width: 27px;
|
|
||||||
height: 27px;
|
height: 27px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-zoom-out {
|
.openwebrx-slider-button svg {
|
||||||
background-position: -27px -38px;
|
position:relative;
|
||||||
width: 27px;
|
top: 1px;
|
||||||
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;
|
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-trashcan {
|
.openwebrx-mute-button svg.muted {
|
||||||
background-position: -145px -38px;
|
display: none;
|
||||||
width: 14px;
|
}
|
||||||
|
|
||||||
|
.openwebrx-mute-button.muted svg.muted {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openwebrx-mute-button.muted svg.unmuted {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark .bookmark-actions .openwebrx-button svg {
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-speaker {
|
#openwebrx-waterfall-colors-auto .continuous {
|
||||||
width: 14px;
|
display: none;
|
||||||
height: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-mute-button .sprite-speaker {
|
#openwebrx-waterfall-colors-auto.highlighted .continuous {
|
||||||
background-position: -103px -38px;
|
display: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openwebrx-mute-button.muted .sprite-speaker {
|
#openwebrx-waterfall-colors-auto.highlighted .auto {
|
||||||
background-position: -117px -38px;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-squelch {
|
.openwebrx-waterfall-container {
|
||||||
background-position: -131px -38px;
|
flex-grow: 1;
|
||||||
width: 14px;
|
display: flex;
|
||||||
height: 13px;
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sprite-waterfall-auto {
|
.openwebrx-waterfall-container > * {
|
||||||
background-position: -103px -53px;
|
flex: 0 0 auto;
|
||||||
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;
|
|
||||||
}
|
}
|
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="shortcut icon" type="image/x-icon" href="static/favicon.ico" />
|
||||||
<link rel="stylesheet" href="static/css/bootstrap.min.css" />
|
<link rel="stylesheet" href="static/css/bootstrap.min.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="static/css/admin.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="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/jquery-3.2.1.min.js"></script>
|
||||||
<script src="static/lib/Header.js"></script>
|
<script src="static/lib/Header.js"></script>
|
||||||
@ -11,6 +10,7 @@
|
|||||||
</HEAD><BODY>
|
</HEAD><BODY>
|
||||||
${header}
|
${header}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
${breadcrumb}
|
||||||
<h1>OpenWebRX Feature Report</h1>
|
<h1>OpenWebRX Feature Report</h1>
|
||||||
<table class="features table">
|
<table class="features table">
|
||||||
<tr>
|
<tr>
|
||||||
@ -20,5 +20,6 @@
|
|||||||
<th>Available</th>
|
<th>Available</th>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
${breadcrumb}
|
||||||
</div>
|
</div>
|
||||||
</BODY></HTML>
|
</BODY></HTML>
|
@ -13,8 +13,7 @@ $(function(){
|
|||||||
});
|
});
|
||||||
$table.append(
|
$table.append(
|
||||||
'<tr>' +
|
'<tr>' +
|
||||||
'<td colspan=2>' + name + '</td>' +
|
'<td colspan=3>' + name + '</td>' +
|
||||||
'<td>' + converter.makeHtml(details.description) + '</td>' +
|
|
||||||
'<td>' + (details.available ? 'YES' : 'NO') + '</td>' +
|
'<td>' + (details.available ? 'YES' : 'NO') + '</td>' +
|
||||||
'</tr>' +
|
'</tr>' +
|
||||||
requirements.join("")
|
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 class="webrx-top-container">
|
||||||
<div id="webrx-top-bar" class="webrx-top-bar-parts">
|
<div class="webrx-top-bar">
|
||||||
<a href="https://www.openwebrx.de/" target="_blank"><img src="static/gfx/openwebrx-top-logo.png" id="webrx-top-logo" alt="OpenWebRX Logo"/></a>
|
<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 id="webrx-rx-avatar" class="openwebrx-photo-trigger" src="static/gfx/openwebrx-avatar.png" alt="Receiver avatar"/>
|
<img class="webrx-rx-avatar openwebrx-photo-trigger" src="${document_root}static/gfx/openwebrx-avatar.png" alt="Receiver avatar"/>
|
||||||
<div id="webrx-rx-texts">
|
<div class="webrx-rx-texts openwebrx-photo-trigger">
|
||||||
<div id="webrx-rx-title" class="openwebrx-photo-trigger"></div>
|
<h1 class="webrx-rx-title">${receiver_name}</h1>
|
||||||
<div id="webrx-rx-desc" class="openwebrx-photo-trigger"></div>
|
<div class="webrx-rx-desc">${receiver_location} | Loc: ${locator}, ASL: ${receiver_asl} m</div>
|
||||||
</div>
|
</div>
|
||||||
<section id="openwebrx-main-buttons">
|
<section class="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-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"><span class="sprite sprite-panel-log"></span><br/>Log</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"><span class="sprite sprite-panel-receiver"></span><br/>Receiver</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="map" target="openwebrx-map"><span class="sprite sprite-panel-map"></span><br/>Map</a>
|
<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>
|
||||||
${settingslink}
|
<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>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div id="openwebrx-description-container">
|
<div class="openwebrx-description-container">
|
||||||
<div id="webrx-rx-photo-title"></div>
|
<div class="webrx-rx-photo-title">${photo_title}</div>
|
||||||
<div id="webrx-rx-photo-desc"></div>
|
<div class="webrx-rx-photo-desc">${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>
|
</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>
|
</div>
|
||||||
|
@ -23,7 +23,14 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>OpenWebRX | Open Source SDR Web App for Everyone!</title>
|
<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>
|
<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/lib/nanoscroller.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="static/css/openwebrx.css" />
|
<link rel="stylesheet" type="text/css" href="static/css/openwebrx.css" />
|
||||||
@ -34,6 +41,7 @@
|
|||||||
<body onload="openwebrx_init();">
|
<body onload="openwebrx_init();">
|
||||||
<div id="webrx-page-container">
|
<div id="webrx-page-container">
|
||||||
${header}
|
${header}
|
||||||
|
<div class="openwebrx-waterfall-container">
|
||||||
<div id="openwebrx-frequency-container">
|
<div id="openwebrx-frequency-container">
|
||||||
<div id="openwebrx-bookmarks-container"></div>
|
<div id="openwebrx-bookmarks-container"></div>
|
||||||
<div id="openwebrx-scale-container">
|
<div id="openwebrx-scale-container">
|
||||||
@ -69,26 +77,63 @@
|
|||||||
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-ysf" style="display: none;" data-panel-name="metadata-ysf">
|
<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-meta-slot">
|
||||||
<div class="openwebrx-ysf-mode"></div>
|
<div class="openwebrx-ysf-mode"></div>
|
||||||
<div class="openwebrx-meta-user-image"></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-source"><span class="location"></span><span class="callsign"></span></div>
|
||||||
<div class="openwebrx-ysf-up"></div>
|
<div class="openwebrx-ysf-up"></div>
|
||||||
<div class="openwebrx-ysf-down"></div>
|
<div class="openwebrx-ysf-down"></div>
|
||||||
</div>
|
</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-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-meta-slot openwebrx-dmr-timeslot-panel">
|
||||||
<div class="openwebrx-dmr-slot">Timeslot 1</div>
|
<div class="openwebrx-dmr-slot">Timeslot 1</div>
|
||||||
<div class="openwebrx-meta-user-image"></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-id"></div>
|
||||||
<div class="openwebrx-dmr-name"></div>
|
<div class="openwebrx-dmr-name"></div>
|
||||||
<div class="openwebrx-dmr-target"></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-meta-slot openwebrx-dmr-timeslot-panel">
|
<div class="openwebrx-meta-slot openwebrx-dmr-timeslot-panel">
|
||||||
<div class="openwebrx-dmr-slot">Timeslot 2</div>
|
<div class="openwebrx-dmr-slot">Timeslot 2</div>
|
||||||
<div class="openwebrx-meta-user-image"></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-id"></div>
|
||||||
<div class="openwebrx-dmr-name"></div>
|
<div class="openwebrx-dmr-name"></div>
|
||||||
<div class="openwebrx-dmr-target"></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>
|
</div>
|
||||||
<div class="openwebrx-panel" id="openwebrx-panel-log" data-panel-name="debug" style="width: 619px;">
|
<div class="openwebrx-panel" id="openwebrx-panel-log" data-panel-name="debug" style="width: 619px;">
|
||||||
@ -121,7 +166,7 @@
|
|||||||
<div class="webrx-mouse-freq"></div>
|
<div class="webrx-mouse-freq"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="openwebrx-button openwebrx-square-button openwebrx-bookmark-button" style="display:none;" title="Add bookmark...">
|
<div class="openwebrx-button openwebrx-square-button openwebrx-bookmark-button" style="display:none;" title="Add bookmark...">
|
||||||
<span class="sprite sprite-bookmark"></span>
|
<svg viewBox="0 0 80 80"><use xlink:href="static/gfx/svg-defs.svg#bookmark"></use></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="openwebrx-panel-line">
|
<div class="openwebrx-panel-line">
|
||||||
@ -130,22 +175,32 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="openwebrx-modes openwebrx-panel-line"></div>
|
<div class="openwebrx-modes openwebrx-panel-line"></div>
|
||||||
<div class="openwebrx-panel-line">
|
<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>
|
<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()">
|
<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>
|
<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()">
|
<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>
|
||||||
<div class="openwebrx-panel-line">
|
<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>
|
<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">
|
<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>
|
<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()">
|
<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>
|
||||||
<div class="openwebrx-panel-line">
|
<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 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" onclick="zoomOutOneStep();" title="Zoom out one step"><span class="sprite sprite-zoom-out"></span></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" onclick="zoomInTotal();" title="Zoom in totally"><span class="sprite sprite-zoom-in-total"></span></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" onclick="zoomOutTotal();" title="Zoom out totally"><span class="sprite sprite-zoom-out-total"></span></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 id="openwebrx-smeter-db">0 dB</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="openwebrx-panel-line">
|
<div class="openwebrx-panel-line">
|
||||||
@ -156,13 +211,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</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" />
|
|
||||||
<div>Start OpenWebRX</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="openwebrx-error-overlay" class="openwebrx-overlay" style="display:none;">
|
<div id="openwebrx-error-overlay" class="openwebrx-overlay" style="display:none;">
|
||||||
<div class="overlay-content">
|
<div class="overlay-content">
|
||||||
<div>This receiver is currently unavailable due to technical issues.</div>
|
<div>This receiver is currently unavailable due to technical issues.</div>
|
||||||
@ -170,6 +218,14 @@
|
|||||||
<div class="errormessage"></div>
|
<div class="errormessage"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="openwebrx-autoplay-overlay" class="openwebrx-overlay" style="display:none;">
|
||||||
|
<div class="overlay-content">
|
||||||
|
<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-dialog-bookmark" class="openwebrx-dialog" style="display:none;">
|
<div id="openwebrx-dialog-bookmark" class="openwebrx-dialog" style="display:none;">
|
||||||
<form>
|
<form>
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
|
@ -6,27 +6,15 @@ function AudioEngine(maxBufferLength, audioReporter) {
|
|||||||
this.audioReporter = audioReporter;
|
this.audioReporter = audioReporter;
|
||||||
this.initStats();
|
this.initStats();
|
||||||
this.resetStats();
|
this.resetStats();
|
||||||
var ctx = window.AudioContext || window.webkitAudioContext;
|
|
||||||
if (!ctx) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onStartCallbacks = [];
|
this.onStartCallbacks = [];
|
||||||
|
|
||||||
this.started = false;
|
this.started = false;
|
||||||
// try common working sample rates
|
this.audioContext = this.buildAudioContext();
|
||||||
if (![48000, 44100].some(function(sr) {
|
if (!this.audioContext) {
|
||||||
try {
|
return;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var me = this;
|
var me = this;
|
||||||
this.audioContext.onstatechange = function() {
|
this.audioContext.onstatechange = function() {
|
||||||
if (me.audioContext.state !== 'running') return;
|
if (me.audioContext.state !== 'running') return;
|
||||||
@ -43,6 +31,38 @@ function AudioEngine(maxBufferLength, audioReporter) {
|
|||||||
this.maxBufferSize = maxBufferLength * this.getSampleRate();
|
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(){
|
AudioEngine.prototype.resume = function(){
|
||||||
this.audioContext.resume();
|
this.audioContext.resume();
|
||||||
}
|
}
|
||||||
|
@ -87,8 +87,8 @@ BookmarkBar.prototype.render = function(){
|
|||||||
var $bookmark = $(
|
var $bookmark = $(
|
||||||
'<div class="bookmark" data-source="' + b.source + '"' + (b.editable?' editable="editable"':'') + '>' +
|
'<div class="bookmark" data-source="' + b.source + '"' + (b.editable?' editable="editable"':'') + '>' +
|
||||||
'<div class="bookmark-actions">' +
|
'<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="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"><span class="sprite sprite-trashcan"><span></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>' +
|
||||||
'<div class="bookmark-content">' + b.name + '</div>' +
|
'<div class="bookmark-content">' + b.name + '</div>' +
|
||||||
'</div>'
|
'</div>'
|
||||||
@ -145,21 +145,3 @@ BookmarkBar.prototype.getDemodulatorPanel = function() {
|
|||||||
BookmarkBar.prototype.getDemodulator = function() {
|
BookmarkBar.prototype.getDemodulator = function() {
|
||||||
return this.getDemodulatorPanel().getDemodulator();
|
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() {
|
Filter.prototype.getLimits = function() {
|
||||||
var max_bw;
|
var max_bw;
|
||||||
if (this.demodulator.get_secondary_demod() === 'pocsag') {
|
if (['pocsag', 'packet'].indexOf(this.demodulator.get_secondary_demod()) >= 0) {
|
||||||
max_bw = 12500;
|
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') {
|
} else if (this.demodulator.get_modulation() === 'wfm') {
|
||||||
max_bw = 100000;
|
max_bw = 100000;
|
||||||
} else if (this.demodulator.get_modulation() === 'drm') {
|
} else if (this.demodulator.get_modulation() === 'drm') {
|
||||||
max_bw = 100000;
|
max_bw = 50000;
|
||||||
} else if (this.demodulator.get_secondary_demod() === 'packet') {
|
|
||||||
max_bw = 12500;
|
|
||||||
} else {
|
} else {
|
||||||
max_bw = (audioEngine.getOutputRate() / 2) - 1;
|
max_bw = (audioEngine.getOutputRate() / 2) - 1;
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ DemodulatorPanel.prototype.updatePanels = function() {
|
|||||||
var modulation = this.getDemodulator().get_secondary_demod();
|
var modulation = this.getDemodulator().get_secondary_demod();
|
||||||
$('#openwebrx-panel-digimodes').attr('data-mode', modulation);
|
$('#openwebrx-panel-digimodes').attr('data-mode', modulation);
|
||||||
toggle_panel("openwebrx-panel-digimodes", !!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-js8-message", modulation == "js8");
|
||||||
toggle_panel("openwebrx-panel-packet-message", modulation === "packet");
|
toggle_panel("openwebrx-panel-packet-message", modulation === "packet");
|
||||||
toggle_panel("openwebrx-panel-pocsag-message", modulation === "pocsag");
|
toggle_panel("openwebrx-panel-pocsag-message", modulation === "pocsag");
|
||||||
@ -213,6 +213,10 @@ DemodulatorPanel.prototype.setInitialParams = function(params) {
|
|||||||
$.extend(this.initialParams, params);
|
$.extend(this.initialParams, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DemodulatorPanel.prototype.resetInitialParams = function() {
|
||||||
|
this.initialParams = {};
|
||||||
|
};
|
||||||
|
|
||||||
DemodulatorPanel.prototype.onHashChange = function() {
|
DemodulatorPanel.prototype.onHashChange = function() {
|
||||||
this._apply(this.transformHashParams(this.parseHash()));
|
this._apply(this.transformHashParams(this.parseHash()));
|
||||||
};
|
};
|
||||||
@ -341,7 +345,7 @@ DemodulatorPanel.prototype.updateSquelch = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
DemodulatorPanel.prototype.setSquelchMargin = function(margin) {
|
DemodulatorPanel.prototype.setSquelchMargin = function(margin) {
|
||||||
if (!margin || this.squelchMargin == margin) return;
|
if (typeof(margin) === 'undefined' || this.squelchMargin == margin) return;
|
||||||
this.squelchMargin = margin;
|
this.squelchMargin = margin;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -353,9 +357,9 @@ DemodulatorPanel.prototype.setMouseFrequency = function(freq) {
|
|||||||
this.mouseFrequencyDisplay.setFrequency(freq);
|
this.mouseFrequencyDisplay.setFrequency(freq);
|
||||||
};
|
};
|
||||||
|
|
||||||
DemodulatorPanel.prototype.setFrequencyPrecision = function(precision) {
|
DemodulatorPanel.prototype.setTuningPrecision = function(precision) {
|
||||||
this.tuneableFrequencyDisplay.setFrequencyPrecision(precision);
|
this.tuneableFrequencyDisplay.setTuningPrecision(precision);
|
||||||
this.mouseFrequencyDisplay.setFrequencyPrecision(precision);
|
this.mouseFrequencyDisplay.setTuningPrecision(precision);
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.demodulatorPanel = function(){
|
$.fn.demodulatorPanel = function(){
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
function FrequencyDisplay(element) {
|
function FrequencyDisplay(element) {
|
||||||
|
this.suffixes = {
|
||||||
|
'': 0,
|
||||||
|
'k': 3,
|
||||||
|
'M': 6,
|
||||||
|
'G': 9,
|
||||||
|
'T': 12
|
||||||
|
};
|
||||||
this.element = $(element);
|
this.element = $(element);
|
||||||
this.digits = [];
|
this.digits = [];
|
||||||
this.precision = 4;
|
this.precision = 2;
|
||||||
this.setupElements();
|
this.setupElements();
|
||||||
this.setFrequency(0);
|
this.setFrequency(0);
|
||||||
}
|
}
|
||||||
@ -9,15 +16,30 @@ function FrequencyDisplay(element) {
|
|||||||
FrequencyDisplay.prototype.setupElements = function() {
|
FrequencyDisplay.prototype.setupElements = function() {
|
||||||
this.displayContainer = $('<div>');
|
this.displayContainer = $('<div>');
|
||||||
this.digitContainer = $('<span>');
|
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);
|
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) {
|
FrequencyDisplay.prototype.setFrequency = function(freq) {
|
||||||
this.frequency = 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,
|
undefined,
|
||||||
{maximumFractionDigits: this.precision, minimumFractionDigits: this.precision}
|
{maximumFractionDigits: digits, minimumFractionDigits: digits}
|
||||||
);
|
);
|
||||||
var children = this.digitContainer.children();
|
var children = this.digitContainer.children();
|
||||||
for (var i = 0; i < formatted.length; i++) {
|
for (var i = 0; i < formatted.length; i++) {
|
||||||
@ -36,10 +58,11 @@ FrequencyDisplay.prototype.setFrequency = function(freq) {
|
|||||||
while (this.digits.length > formatted.length) {
|
while (this.digits.length > formatted.length) {
|
||||||
this.digits.pop().remove();
|
this.digits.pop().remove();
|
||||||
}
|
}
|
||||||
|
this.unitContainer.text(' ' + this.getSuffix() + 'Hz');
|
||||||
};
|
};
|
||||||
|
|
||||||
FrequencyDisplay.prototype.setFrequencyPrecision = function(precision) {
|
FrequencyDisplay.prototype.setTuningPrecision = function(precision) {
|
||||||
if (!precision) return;
|
if (typeof(precision) == 'undefined') return;
|
||||||
this.precision = precision;
|
this.precision = precision;
|
||||||
this.setFrequency(this.frequency);
|
this.setFrequency(this.frequency);
|
||||||
};
|
};
|
||||||
@ -53,22 +76,28 @@ TuneableFrequencyDisplay.prototype = new FrequencyDisplay();
|
|||||||
|
|
||||||
TuneableFrequencyDisplay.prototype.setupElements = function() {
|
TuneableFrequencyDisplay.prototype.setupElements = function() {
|
||||||
FrequencyDisplay.prototype.setupElements.call(this);
|
FrequencyDisplay.prototype.setupElements.call(this);
|
||||||
this.input = $('<input>');
|
this.input = $('<input type="number" step="any">');
|
||||||
this.input.hide();
|
this.suffixInput = $('<select tabindex="-1">');
|
||||||
this.element.append(this.input);
|
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() {
|
TuneableFrequencyDisplay.prototype.setupEvents = function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
me.element.on('wheel', function(e){
|
me.displayContainer.on('wheel', function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
var index = me.digitContainer.find('.digit').index(e.target);
|
var index = me.digitContainer.find('.digit').index(e.target);
|
||||||
if (index < 0) return;
|
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;
|
if (e.originalEvent.deltaY > 0) delta *= -1;
|
||||||
var newFrequency = me.frequency + delta;
|
var newFrequency = me.frequency + delta;
|
||||||
|
|
||||||
@ -76,26 +105,64 @@ TuneableFrequencyDisplay.prototype.setupEvents = function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var submit = 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)) {
|
if (!isNaN(freq)) {
|
||||||
me.element.trigger('frequencychange', freq);
|
me.element.trigger('frequencychange', freq);
|
||||||
}
|
}
|
||||||
me.input.hide();
|
me.inputGroup.hide();
|
||||||
me.displayContainer.show();
|
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 == 13) return submit();
|
||||||
if (e.keyCode == 27) {
|
if (e.keyCode == 27) {
|
||||||
me.input.hide();
|
me.inputGroup.hide();
|
||||||
me.displayContainer.show();
|
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();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
me.element.on('click', function(){
|
me.element.on('click', function(){
|
||||||
me.input.val(me.frequency);
|
currentExponent = me.exponent;
|
||||||
me.input.show();
|
me.input.val(me.frequency / 10 ** me.exponent);
|
||||||
|
me.suffixInput.val(me.exponent);
|
||||||
|
me.inputGroup.show();
|
||||||
me.displayContainer.hide();
|
me.displayContainer.hide();
|
||||||
me.input.focus();
|
me.input.focus();
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
function Header(el) {
|
function Header(el) {
|
||||||
this.el = 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
|
// ignore buttons when the corresponding panel is not in the DOM
|
||||||
return $('#' + $(this).data('toggle-panel'))[0];
|
return $('#' + $(this).data('toggle-panel'))[0];
|
||||||
});
|
});
|
||||||
@ -11,14 +11,13 @@ function Header(el) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.init_rx_photo();
|
this.init_rx_photo();
|
||||||
this.download_details();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Header.prototype.setDetails = function(details) {
|
Header.prototype.setDetails = function(details) {
|
||||||
this.el.find('#webrx-rx-title').html(details['receiver_name']);
|
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-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-title').html(details['photo_title']);
|
||||||
this.el.find('#webrx-rx-photo-desc').html(details['photo_desc']);
|
this.el.find('.webrx-rx-photo-desc').html(details['photo_desc']);
|
||||||
};
|
};
|
||||||
|
|
||||||
Header.prototype.init_rx_photo = function() {
|
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() {
|
Header.prototype.close_rx_photo = function() {
|
||||||
this.rx_photo_state = 0;
|
this.rx_photo_state = 0;
|
||||||
this.el.find('#openwebrx-description-container').removeClass('expanded');
|
this.el.find('.openwebrx-description-container').removeClass('expanded');
|
||||||
this.el.find("#openwebrx-rx-details-arrow-down").show();
|
this.el.find(".openwebrx-rx-details-arrow").removeClass('openwebrx-rx-details-arrow--up').addClass('openwebrx-rx-details-arrow--down');
|
||||||
this.el.find("#openwebrx-rx-details-arrow-up").hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Header.prototype.open_rx_photo = function() {
|
Header.prototype.open_rx_photo = function() {
|
||||||
this.rx_photo_state = 1;
|
this.rx_photo_state = 1;
|
||||||
this.el.find('#openwebrx-description-container').addClass('expanded');
|
this.el.find('.openwebrx-description-container').addClass('expanded');
|
||||||
this.el.find("#openwebrx-rx-details-arrow-down").hide();
|
this.el.find(".openwebrx-rx-details-arrow").removeClass('openwebrx-rx-details-arrow--down').addClass('openwebrx-rx-details-arrow--up');
|
||||||
this.el.find("#openwebrx-rx-details-arrow-up").show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Header.prototype.toggle_rx_photo = function(ev) {
|
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() {
|
$.fn.header = function() {
|
||||||
if (!this.data('header')) {
|
if (!this.data('header')) {
|
||||||
this.data('header', new Header(this));
|
this.data('header', new Header(this));
|
||||||
@ -73,5 +63,5 @@ $.fn.header = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$(function(){
|
$(function(){
|
||||||
$('#webrx-top-container').header();
|
$('.webrx-top-container').header();
|
||||||
});
|
});
|
||||||
|
@ -78,7 +78,7 @@ WsjtMessagePanel.prototype.pushMessage = function(msg) {
|
|||||||
return $('<div/>').text(input).html()
|
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})$/);
|
matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/);
|
||||||
if (matches && matches[2] !== 'RR73') {
|
if (matches && matches[2] !== 'RR73') {
|
||||||
linkedmsg = html_escape(matches[1]) + '<a href="map?locator=' + matches[2] + '" target="openwebrx-map">' + matches[2] + '</a>';
|
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) {
|
} else if (msg.lat && msg.lon) {
|
||||||
classes.push('openwebrx-maps-pin');
|
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 = [
|
var attrs = [
|
||||||
'class="' + classes.join(' ') + '"',
|
'class="' + classes.join(' ') + '"',
|
||||||
|
@ -145,7 +145,7 @@ YsfMetaPanel.prototype.setLocation = function(lat, lon, callsign) {
|
|||||||
this.hasLocation = hasLocation; this.callsign = callsign;
|
this.hasLocation = hasLocation; this.callsign = callsign;
|
||||||
var html = '';
|
var html = '';
|
||||||
if (hasLocation) {
|
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);
|
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 || '');
|
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 = {
|
MetaPanel.types = {
|
||||||
dmr: DmrMetaPanel,
|
dmr: DmrMetaPanel,
|
||||||
ysf: YsfMetaPanel
|
ysf: YsfMetaPanel,
|
||||||
|
dstar: DStarMetaPanel,
|
||||||
|
nxdn: NxdnMetaPanel,
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.metaPanel = function() {
|
$.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>');
|
|
||||||
};
|
|