diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6cf3f88..00f04d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,14 @@ _v6.5.3_
- Add filename to dirwatch error messages (issue #248).
- Dirwatch.type=default now defaults to the current date and time if none are provided by the metatags (discussion #250).
+_v6.5.4_
+
+- Fixed some warnings when linting server code.
+- New dirwatch type `DSDPlus Fast Lane` (discussion #244).
+- Added new error catches on dirwatch (issue 254).
+- Fixed search by inaccurate time (issue #258).
+- Reverted sync.Map to regular map with sync.Mutex.
+
## Version 6.4
- New `-cmd` command line options to allow advanced administrative tasks.
diff --git a/COMPILING.md b/COMPILING.md
index 9dcb9b4..7a83ba8 100644
--- a/COMPILING.md
+++ b/COMPILING.md
@@ -27,13 +27,13 @@ Clone the official repository on your computer and start the build process.
When finished, you will find the precompiled versions for various platforms in the `dist` folder.
- rdio-scanner-darwin-amd64-v6.5.3.zip
- rdio-scanner-darwin-arm64-v6.5.3.zip
- rdio-scanner-freebsd-amd64-v6.5.3.zip
- rdio-scanner-linux-386-v6.5.3.zip
- rdio-scanner-linux-amd64-v6.5.3.zip
- rdio-scanner-linux-arm64-v6.5.3.zip
- rdio-scanner-linux-arm-v6.5.3.zip
- rdio-scanner-windows-amd64-v6.5.3.zip
+ rdio-scanner-darwin-amd64-v6.5.4.zip
+ rdio-scanner-darwin-arm64-v6.5.4.zip
+ rdio-scanner-freebsd-amd64-v6.5.4.zip
+ rdio-scanner-linux-386-v6.5.4.zip
+ rdio-scanner-linux-amd64-v6.5.4.zip
+ rdio-scanner-linux-arm64-v6.5.4.zip
+ rdio-scanner-linux-arm-v6.5.4.zip
+ rdio-scanner-windows-amd64-v6.5.4.zip
**Happy Rdio scanning !**
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 33ee168..55456b8 100644
--- a/Makefile
+++ b/Makefile
@@ -16,8 +16,8 @@
################################################################################
app := rdio-scanner
-date := 2022/08/10
-ver := 6.5.3
+date := 2022/09/09
+ver := 6.5.4
client := $(wildcard client/*.json client/*.ts)
server := $(wildcard server/*.go)
diff --git a/README.md b/README.md
index e18bd5c..d324a0c 100644
--- a/README.md
+++ b/README.md
@@ -16,9 +16,10 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
| -------------------------------------------------------------- | --- | -------- |
| [Trunk Recorder](https://github.com/robotastic/trunk-recorder) | X | X |
| [RTLSDR-Airband](https://github.com/szpajder/RTLSDR-Airband) | | X |
-| [sdrtrunk](https://github.com/DSheirer/sdrtrunk) | | X |
+| [SDRTrunk](https://github.com/DSheirer/sdrtrunk) | | X |
| [voxcall](https://github.com/aaknitt/voxcall) | X | |
| [ProScan](https://www.proscan.org/) | | X |
+| [DSDPlus Fast Lane](https://https://www.dsdplus.com/) | | X |
# Quick start
diff --git a/client/package-lock.json b/client/package-lock.json
index 2c5be47..f1e3c7c 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "rdio-scanner",
- "version": "6.5.3",
+ "version": "6.5.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "rdio-scanner",
- "version": "6.5.2",
+ "version": "6.5.4",
"license": "LICENSE",
"dependencies": {
"@angular/animations": "^13.3.10",
diff --git a/client/package.json b/client/package.json
index 07c2fae..39c7f79 100644
--- a/client/package.json
+++ b/client/package.json
@@ -38,5 +38,5 @@
"build": "ng build --base-href ./ --configuration production",
"start": "ng serve"
},
- "version": "6.5.3"
+ "version": "6.5.4"
}
diff --git a/client/src/app/components/rdio-scanner/admin/admin.service.ts b/client/src/app/components/rdio-scanner/admin/admin.service.ts
index d7a1e7b..a631195 100644
--- a/client/src/app/components/rdio-scanner/admin/admin.service.ts
+++ b/client/src/app/components/rdio-scanner/admin/admin.service.ts
@@ -637,6 +637,10 @@ export class RdioScannerAdminService implements OnDestroy {
return null;
}
+ if (control.value.startsWith('\\')) {
+ return { network: true }
+ }
+
const dirWatch: DirWatch[] = control.parent?.parent?.getRawValue() || [];
const count = dirWatch.reduce((c, a) => c += a.directory === control.value ? 1 : 0, 0);
@@ -653,7 +657,7 @@ export class RdioScannerAdminService implements OnDestroy {
const type = dirwatch.type;
- return ['sdr-trunk'].includes(type) || control.value !== null || /#SYS/.test(mask) ? null : { required: true };
+ return ['dsdplus', 'sdr-trunk'].includes(type) || control.value !== null || /#SYS/.test(mask) ? null : { required: true };
};
}
@@ -665,7 +669,7 @@ export class RdioScannerAdminService implements OnDestroy {
const type = dirwatch.type;
- return ['trunk-recorder', 'sdr-trunk'].includes(type) || control.value !== null || /#TG/.test(mask) ? null : { required: true };
+ return ['dsdplus', 'trunk-recorder', 'sdr-trunk'].includes(type) || control.value !== null || /#TG/.test(mask) ? null : { required: true };
};
}
diff --git a/client/src/app/components/rdio-scanner/admin/config/dir-watch/dir-watch.component.html b/client/src/app/components/rdio-scanner/admin/config/dir-watch/dir-watch.component.html
index 6f6459a..3e5c3d1 100644
--- a/client/src/app/components/rdio-scanner/admin/config/dir-watch/dir-watch.component.html
+++ b/client/src/app/components/rdio-scanner/admin/config/dir-watch/dir-watch.component.html
@@ -33,6 +33,28 @@
+ Type
+
+ Dirwatch type defines how the metadata are obtained.
+
+
+
+
Directory
@@ -49,9 +71,12 @@
Extension
The audio call extension to monitor without the period. Ex.: "mp3",
@@ -64,29 +89,14 @@
- Type
- When SDR Trunk, metadata are obtained from the MP3 tags. Note that
- the label of the SDR Trunk system must match the label of the Rdio Scanner system label. When
- trunk-recorder, metadata are obtained from the JSON file.
-
System
System to where the audio files should go.
Talkgroup
Talkgroup to where the audio files should go.
Mask
Some metadata can be extracted from the file name of the audio file using
@@ -156,7 +166,7 @@
Frequency
Fake frequency in hertz displayed on the main screen.
@@ -168,7 +178,7 @@
Delay
Depending on the recorder, audio files can be ingested too soon after the
diff --git a/docs/docker/README.md b/docs/docker/README.md
index e856e20..91243b4 100644
--- a/docs/docker/README.md
+++ b/docs/docker/README.md
@@ -53,12 +53,12 @@ $ docker run --detach --env TZ=America/Toronto --name rdio-scanner --publish 300
520cdbf51fca11d8bacea12d81245f1cb4d984f80d2be2e3039727b59533a6a9
$ docker logs rdio-scanner
-Rdio Scanner v6.5.3
+Rdio Scanner v6.5.4
----------------------------------
-2022/08/10 08:57:23 server started
-2022/08/10 08:57:23 base folder is /app/data
-2022/08/10 08:57:23 main interface at http://6d87e8dc37a0:3000
-2022/08/10 08:57:23 admin interface at http://6d87e8dc37a0:3000/admin
+2022/09/09 08:57:23 server started
+2022/09/09 08:57:23 base folder is /app/data
+2022/09/09 08:57:23 main interface at http://6d87e8dc37a0:3000
+2022/09/09 08:57:23 admin interface at http://6d87e8dc37a0:3000/admin
```
You can also use docker-compose to start the server with this simple `docker-compose.yml`:
diff --git a/docs/platforms/darwin.md b/docs/platforms/darwin.md
index d8ce24b..5aab629 100644
--- a/docs/platforms/darwin.md
+++ b/docs/platforms/darwin.md
@@ -18,9 +18,10 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
| -------------------------------------------------------------- | --- | -------- |
| [Trunk Recorder](https://github.com/robotastic/trunk-recorder) | X | X |
| [RTLSDR-Airband](https://github.com/szpajder/RTLSDR-Airband) | | X |
-| [sdrtrunk](https://github.com/DSheirer/sdrtrunk) | | X |
+| [SDRTrunk](https://github.com/DSheirer/sdrtrunk) | | X |
| [voxcall](https://github.com/aaknitt/voxcall) | X | |
| [ProScan](https://www.proscan.org/) | | X |
+| [DSDPlus Fast Lane](https://https://www.dsdplus.com/) | | X |
# Improve your experience on the go
@@ -42,8 +43,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@macos ~ % mkdir rdio-scanner
rdio@macos ~ % cd rdio-scanner
rdio@macos rdio-scanner % unzip \
- > ~/Downloads/rdio-scanner-darwin-arm64-v6.5.3.zip
- Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.5.3.zip
+ > ~/Downloads/rdio-scanner-darwin-arm64-v6.5.4.zip
+ Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.5.4.zip
inflating: rdio-scanner
inflating: rdio-scanner.pdf
@@ -51,11 +52,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@macos rdio-scanner % ./rdio-scanner
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 08:38:06 server started
- 2022/08/10 08:38:06 main interface at http://macos.local:3000
- 2022/08/10 08:38:06 admin interface at http://macos.local:3000/admin
+ 2022/09/09 08:38:06 server started
+ 2022/09/09 08:38:06 main interface at http://macos.local:3000
+ 2022/09/09 08:38:06 admin interface at http://macos.local:3000/admin
4. Access the administrative dashboard to finalize the configuration.
@@ -77,11 +78,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
rdio@macos rdio-scanner % ./rdio-scanner --listen :80
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 08:48:03 server started
- 2022/08/10 08:48:03 main interface at http://macos.local
- 2022/08/10 08:48:03 admin interface at http://macos.local/admin
+ 2022/09/09 08:48:03 server started
+ 2022/09/09 08:48:03 main interface at http://macos.local
+ 2022/09/09 08:48:03 admin interface at http://macos.local/admin
## Listening on a SSL port
@@ -95,12 +96,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
> -ssl_key_file mykey.key \
> -ssl_listen :443
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 08:50:58 server started
- 2022/08/10 08:50:58 main interface at http://macos.local
- 2022/08/10 08:50:58 main interface at https://macos.local
- 2022/08/10 08:50:58 admin interface at https://macos.local/admin
+ 2022/09/09 08:50:58 server started
+ 2022/09/09 08:50:58 main interface at http://macos.local
+ 2022/09/09 08:50:58 main interface at https://macos.local
+ 2022/09/09 08:50:58 admin interface at https://macos.local/admin
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
@@ -118,7 +119,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
> -ssl_auto_cert mydomain.com \
> -ssl_listen :443 \
> -config_save
- 2022/08/10 08:52:24 rdio-scanner.ini file created
+ 2022/09/09 08:52:24 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@@ -132,12 +133,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
rdio@macos rdio-scanner % ./rdio-scanner
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 08:54:08 server started
- 2022/08/10 08:54:08 main interface at http://macos.local
- 2022/08/10 08:54:08 main interface at https://macos.local
- 2022/08/10 08:54:08 admin interface at https://macos.local/admin
+ 2022/09/09 08:54:08 server started
+ 2022/09/09 08:54:08 main interface at http://macos.local
+ 2022/09/09 08:54:08 main interface at https://macos.local
+ 2022/09/09 08:54:08 admin interface at https://macos.local/admin
## Install Rdio Scanner as a service
diff --git a/docs/platforms/freebsd.md b/docs/platforms/freebsd.md
index 73189cd..b743a9f 100644
--- a/docs/platforms/freebsd.md
+++ b/docs/platforms/freebsd.md
@@ -18,9 +18,10 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
| -------------------------------------------------------------- | --- | -------- |
| [Trunk Recorder](https://github.com/robotastic/trunk-recorder) | X | X |
| [RTLSDR-Airband](https://github.com/szpajder/RTLSDR-Airband) | | X |
-| [sdrtrunk](https://github.com/DSheirer/sdrtrunk) | | X |
+| [SDRTrunk](https://github.com/DSheirer/sdrtrunk) | | X |
| [voxcall](https://github.com/aaknitt/voxcall) | X | |
| [ProScan](https://www.proscan.org/) | | X |
+| [DSDPlus Fast Lane](https://https://www.dsdplus.com/) | | X |
# Improve your experience on the go
@@ -42,8 +43,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@pc-freebsd:~ $ mkdir rdio-scanner
rdio@pc-freebsd:~ $ cd rdio-scanner
rdio@pc-freebsd:~/rdio-scanner $ unzip \
- > ~/rdio-scanner-freebsd-amd64-v6.5.3.zip
- Archive: ../rdio-scanner-freebsd-amd64-v6.5.3.zip
+ > ~/rdio-scanner-freebsd-amd64-v6.5.4.zip
+ Archive: ../rdio-scanner-freebsd-amd64-v6.5.4.zip
extracting: rdio-scanner
extracting: rdio-scanner.pdf
@@ -51,11 +52,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 08:16:36 server started
- 2022/08/10 08:16:36 main interface at http://pc-freebsd:3000
- 2022/08/10 08:16:36 admin interface at http://pc-freebsd:3000/admin
+ 2022/09/09 08:16:36 server started
+ 2022/09/09 08:16:36 main interface at http://pc-freebsd:3000
+ 2022/09/09 08:16:36 admin interface at http://pc-freebsd:3000/admin
4. Access the administrative dashboard to finalize the configuration.
@@ -81,11 +82,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
Password:
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 08:19:38 server started
- 2022/08/10 08:19:38 main interface at http://pc-freebsd
- 2022/08/10 08:19:38 admin interface at http://pc-freebsd/admin
+ 2022/09/09 08:19:38 server started
+ 2022/09/09 08:19:38 main interface at http://pc-freebsd
+ 2022/09/09 08:19:38 admin interface at http://pc-freebsd/admin
## Listening on a SSL port
@@ -101,12 +102,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
> -ssl_key_file mykey.key \
> -ssl_listen :443
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 10:34:29 server started
- 2022/08/10 10:34:29 main interface at http://pc-freebsd
- 2022/08/10 10:34:29 main interface at https://pc-freebsd
- 2022/08/10 10:34:29 admin interface at https://pc-freebsd/admin
+ 2022/09/09 10:34:29 server started
+ 2022/09/09 10:34:29 main interface at http://pc-freebsd
+ 2022/09/09 10:34:29 main interface at https://pc-freebsd
+ 2022/09/09 10:34:29 admin interface at https://pc-freebsd/admin
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
@@ -126,7 +127,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
> -ssl_auto_cert mydomain.com \
> -ssl_listen :443 \
> -config_save
- 2022/08/10 10:37:00 rdio-scanner.ini file created
+ 2022/09/09 10:37:00 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@@ -142,12 +143,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
Password:
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 10:38:28 server started
- 2022/08/10 10:38:29 main interface at http://pc-freebsd
- 2022/08/10 10:38:29 main interface at https://pc-freebsd
- 2022/08/10 10:38:29 admin interface at https://pc-freebsd/admin
+ 2022/09/09 10:38:28 server started
+ 2022/09/09 10:38:29 main interface at http://pc-freebsd
+ 2022/09/09 10:38:29 main interface at https://pc-freebsd
+ 2022/09/09 10:38:29 admin interface at https://pc-freebsd/admin
## Install Rdio Scanner as a service
diff --git a/docs/platforms/linux.md b/docs/platforms/linux.md
index e57998f..4f90790 100644
--- a/docs/platforms/linux.md
+++ b/docs/platforms/linux.md
@@ -18,9 +18,10 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
| -------------------------------------------------------------- | --- | -------- |
| [Trunk Recorder](https://github.com/robotastic/trunk-recorder) | X | X |
| [RTLSDR-Airband](https://github.com/szpajder/RTLSDR-Airband) | | X |
-| [sdrtrunk](https://github.com/DSheirer/sdrtrunk) | | X |
+| [SDRTrunk](https://github.com/DSheirer/sdrtrunk) | | X |
| [voxcall](https://github.com/aaknitt/voxcall) | X | |
| [ProScan](https://www.proscan.org/) | | X |
+| [DSDPlus Fast Lane](https://https://www.dsdplus.com/) | | X |
# Improve your experience on the go
@@ -42,8 +43,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
[rdio@pc-linux ~]$ mkdir rdio-scanner
[rdio@pc-linux ~]$ cd rdio-scanner
[rdio@pc-linux rdio-scanner]$ unzip \
- > ~/Downloads/rdio-scanner-linux-amd64-v6.5.3.zip
- Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.5.3.zip
+ > ~/Downloads/rdio-scanner-linux-amd64-v6.5.4.zip
+ Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.5.4.zip
inflating: rdio-scanner
inflating: rdio-scanner.pdf
@@ -51,11 +52,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 09:11:48 server started
- 2022/08/10 09:11:48 main interface at http://pc-linux:3000
- 2022/08/10 09:11:48 admin interface at http://pc-linux:3000/admin
+ 2022/09/09 09:11:48 server started
+ 2022/09/09 09:11:48 main interface at http://pc-linux:3000
+ 2022/09/09 09:11:48 admin interface at http://pc-linux:3000/admin
4. Access the administrative dashboard to finalize the configuration.
@@ -78,11 +79,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
[sudo] password for rdio:
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 09:14:00 server started
- 2022/08/10 09:14:00 main interface at http://pc-linux
- 2022/08/10 09:14:00 admin interface at http://pc-linux/admin
+ 2022/09/09 09:14:00 server started
+ 2022/09/09 09:14:00 main interface at http://pc-linux
+ 2022/09/09 09:14:00 admin interface at http://pc-linux/admin
## Listening on a SSL port
@@ -97,12 +98,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
> -ssl_listen :443
[sudo] password for rdio:
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 09:16:47 server started
- 2022/08/10 09:16:47 main interface at http://pc-linux
- 2022/08/10 09:16:47 main interface at https://pc-linux
- 2022/08/10 09:16:47 admin interface at https://pc-linux/admin
+ 2022/09/09 09:16:47 server started
+ 2022/09/09 09:16:47 main interface at http://pc-linux
+ 2022/09/09 09:16:47 main interface at https://pc-linux
+ 2022/09/09 09:16:47 admin interface at https://pc-linux/admin
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
@@ -120,7 +121,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
> -ssl_auto_cert mydomain.com \
> -ssl_listen :443 \
> -config_save
- 2022/08/10 09:19:29 rdio-scanner.ini file created
+ 2022/09/09 09:19:29 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@@ -135,12 +136,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner
[sudo] Mot de passe de rdio :
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 09:20:40 server started
- 2022/08/10 09:20:40 main interface at http://pc-linux
- 2022/08/10 09:20:40 main interface at https://pc-linux
- 2022/08/10 09:20:40 admin interface at https://pc-linux/admin
+ 2022/09/09 09:20:40 server started
+ 2022/09/09 09:20:40 main interface at http://pc-linux
+ 2022/09/09 09:20:40 main interface at https://pc-linux
+ 2022/09/09 09:20:40 admin interface at https://pc-linux/admin
## Install Rdio Scanner as a service
diff --git a/docs/platforms/windows.md b/docs/platforms/windows.md
index 2c8a538..5d7d38a 100644
--- a/docs/platforms/windows.md
+++ b/docs/platforms/windows.md
@@ -18,9 +18,10 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
| -------------------------------------------------------------- | --- | -------- |
| [Trunk Recorder](https://github.com/robotastic/trunk-recorder) | X | X |
| [RTLSDR-Airband](https://github.com/szpajder/RTLSDR-Airband) | | X |
-| [sdrtrunk](https://github.com/DSheirer/sdrtrunk) | | X |
+| [SDRTrunk](https://github.com/DSheirer/sdrtrunk) | | X |
| [voxcall](https://github.com/aaknitt/voxcall) | X | |
| [ProScan](https://www.proscan.org/) | | X |
+| [DSDPlus Fast Lane](https://https://www.dsdplus.com/) | | X |
# Improve your experience on the go
@@ -44,7 +45,7 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
C:\Users\rdio> cd rdio-scanner
C:\Users\rdio\rdio-scanner> tar -xvf ^
- ..\downloads\rdio-scanner-windows-amd64-v6.5.3.zip
+ ..\downloads\rdio-scanner-windows-amd64-v6.5.4.zip
x rdio-scanner.exe
x rdio-scanner.pdf
@@ -52,11 +53,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
C:\Users\rdio\rdio-scanner>rdio-scanner
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 13:48:48 server started
- 2022/08/10 13:48:48 main interface at http://pc-windows:3000
- 2022/08/10 13:48:48 admin interface at http://pc-windows:3000/admin
+ 2022/09/09 13:48:48 server started
+ 2022/09/09 13:48:48 main interface at http://pc-windows:3000
+ 2022/09/09 13:48:48 admin interface at http://pc-windows:3000/admin
4. Access the administrative dashboard to finalize the configuration.
@@ -78,11 +79,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 10:53:31 server started
- 2022/08/10 10:53:31 main interface at http://pc-windows
- 2022/08/10 10:53:31 admin interface at http://pc-windows/admin
+ 2022/09/09 10:53:31 server started
+ 2022/09/09 10:53:31 main interface at http://pc-windows
+ 2022/09/09 10:53:31 admin interface at http://pc-windows/admin
## Listening on a SSL port
@@ -96,12 +97,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
-ssl_key_file meykey.key ^
-ssl_listen :443
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 11:05:43 server started
- 2022/08/10 11:05:43 main interface at http://pc-windows
- 2022/08/10 11:05:43 main interface at https://pc-windows
- 2022/08/10 11:05:43 admin interface at https://pc-windows/admin
+ 2022/09/09 11:05:43 server started
+ 2022/09/09 11:05:43 main interface at http://pc-windows
+ 2022/09/09 11:05:43 main interface at https://pc-windows
+ 2022/09/09 11:05:43 admin interface at https://pc-windows/admin
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
@@ -119,7 +120,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
-ssl_auto_cert mydomain.com ^
-ssl_listen :443 ^
-config_save
- 2022/08/10 11:08:28 rdio-scanner.ini file created
+ 2022/09/09 11:08:28 rdio-scanner.ini file created
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
@@ -133,12 +134,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
C:\Users\rdio\rdio-scanner>rdio-scanner
- Rdio Scanner v6.5.3
+ Rdio Scanner v6.5.4
----------------------------------
- 2022/08/10 11:11:28 server started
- 2022/08/10 11:11:28 main interface at http://pc-windows
- 2022/08/10 11:11:28 main interface at https://pc-windows
- 2022/08/10 11:11:28 admin interface at https://pc-windows/admin
+ 2022/09/09 11:11:28 server started
+ 2022/09/09 11:11:28 main interface at http://pc-windows
+ 2022/09/09 11:11:28 main interface at https://pc-windows
+ 2022/09/09 11:11:28 admin interface at https://pc-windows/admin
\pagebreak{}
diff --git a/server/call.go b/server/call.go
index dc8b284..8e7f3e8 100644
--- a/server/call.go
+++ b/server/call.go
@@ -338,6 +338,8 @@ func (calls *Calls) Search(searchOptions *CallsSearchOptions, client *Client) (*
if t, err = db.ParseDateTime(dateTime); err == nil {
searchResults.DateStop = t
+ } else {
+ searchResults.DateStop = time.Now()
}
switch v := searchOptions.Sort.(type) {
@@ -364,8 +366,8 @@ func (calls *Calls) Search(searchOptions *CallsSearchOptions, client *Client) (*
stop = start.Add(time.Hour*24 - time.Millisecond)
} else {
- start = time.Date(v.Year(), v.Month(), v.Day(), v.Hour(), v.Minute(), 0, 0, time.UTC).Add(time.Hour*-24 - time.Duration(v.Hour())).Add(time.Minute * time.Duration(-v.Minute()))
- stop = start.Add(time.Hour*24 - time.Millisecond - time.Duration(v.Hour())).Add(time.Minute * time.Duration(-v.Minute()))
+ start = time.Date(v.Year(), v.Month(), v.Day(), v.Hour(), v.Minute(), 0, 0, time.UTC).Add(time.Hour*-24 + time.Millisecond)
+ stop = time.Date(v.Year(), v.Month(), v.Day(), v.Hour(), v.Minute(), 0, 0, time.UTC)
}
where += fmt.Sprintf(" and (`dateTime` between '%v' and '%v')", start.Format(df), stop.Format(df))
diff --git a/server/client.go b/server/client.go
index 7036bec..66eb73a 100644
--- a/server/client.go
+++ b/server/client.go
@@ -206,91 +206,90 @@ func (client *Client) SendListenersCount(count int) {
}
type Clients struct {
- Map sync.Map
- count int
+ Map map[*Client]bool
+ mutex sync.Mutex
}
func NewClients() *Clients {
return &Clients{
- Map: sync.Map{},
- count: 0,
+ Map: map[*Client]bool{},
+ mutex: sync.Mutex{},
}
}
func (clients *Clients) AccessCount(client *Client) int {
+ clients.mutex.Lock()
+ defer clients.mutex.Unlock()
+
count := 0
- clients.Map.Range(func(k any, _ any) bool {
- switch c := k.(type) {
- case *Client:
- if c.Access == client.Access {
- count++
- }
+ for c := range clients.Map {
+ if c.Access == client.Access {
+ count++
}
- return true
- })
+ }
return count
}
func (clients *Clients) Add(client *Client) {
- clients.count = clients.count + 1
- clients.Map.Store(client, true)
+ clients.mutex.Lock()
+ defer clients.mutex.Unlock()
+
+ clients.Map[client] = true
}
func (clients *Clients) Count() int {
- return clients.count
+ clients.mutex.Lock()
+ defer clients.mutex.Unlock()
+
+ return len(clients.Map)
}
func (clients *Clients) EmitCall(call *Call, restricted bool) {
- clients.Map.Range(func(k any, _ any) bool {
- switch c := k.(type) {
- case *Client:
- if (!restricted || c.Access.HasAccess(call)) && c.Livefeed.IsEnabled(call) {
- c.Send <- &Message{Command: MessageCommandCall, Payload: call}
- }
- }
+ clients.mutex.Lock()
+ defer clients.mutex.Unlock()
- return true
- })
+ for c := range clients.Map {
+ if (!restricted || c.Access.HasAccess(call)) && c.Livefeed.IsEnabled(call) {
+ c.Send <- &Message{Command: MessageCommandCall, Payload: call}
+ }
+ }
}
func (clients *Clients) EmitConfig(groups *Groups, options *Options, systems *Systems, tags *Tags, restricted bool) {
- count := clients.Count()
+ clients.mutex.Lock()
+ defer clients.mutex.Unlock()
- clients.Map.Range(func(k any, _ any) bool {
- switch c := k.(type) {
- case *Client:
- if restricted {
- c.Send <- &Message{Command: MessageCommandPin}
- } else {
- c.SendConfig(groups, options, systems, tags)
- }
+ count := len(clients.Map)
- if options.ShowListenersCount {
- c.SendListenersCount(count)
- }
+ for c := range clients.Map {
+ if restricted {
+ c.Send <- &Message{Command: MessageCommandPin}
+ } else {
+ c.SendConfig(groups, options, systems, tags)
}
- return true
- })
+ if options.ShowListenersCount {
+ c.SendListenersCount(count)
+ }
+ }
}
func (clients *Clients) EmitListenersCount() {
- count := clients.Count()
+ clients.mutex.Lock()
+ defer clients.mutex.Unlock()
- clients.Map.Range(func(k any, _ any) bool {
- switch c := k.(type) {
- case *Client:
- c.SendListenersCount(count)
- }
+ count := len(clients.Map)
- return true
- })
+ for c := range clients.Map {
+ c.SendListenersCount(count)
+ }
}
func (clients *Clients) Remove(client *Client) {
- if _, loaded := clients.Map.LoadAndDelete(client); loaded {
- clients.count = clients.count - 1
- }
+ clients.mutex.Lock()
+ defer clients.mutex.Unlock()
+
+ delete(clients.Map, client)
}
diff --git a/server/command.go b/server/command.go
index 6762ffe..4739289 100644
--- a/server/command.go
+++ b/server/command.go
@@ -138,7 +138,7 @@ func (command *Command) Do(action string) {
command.url = readVal()
if err != nil || !regexp.MustCompile(`^https?://`).Match([]byte(command.url)) {
- command.exitWithError(errors.New("Invalid URL"))
+ command.exitWithError(errors.New("invalid URL"))
}
}
@@ -259,7 +259,7 @@ func (command *Command) configGet() {
}
}
default:
- command.exitWithError(errors.New("Invalid response"))
+ command.exitWithError(errors.New("invalid response"))
}
} else {
command.exitWithError(err)
@@ -314,10 +314,10 @@ func (command *Command) login() {
}
fmt.Println("Logged in.")
default:
- command.exitWithError(errors.New("No token in response"))
+ command.exitWithError(errors.New("no token in response"))
}
default:
- command.exitWithError(errors.New("Invalid response"))
+ command.exitWithError(errors.New("invalid response"))
}
} else {
command.exitWithError(err)
diff --git a/server/controller.go b/server/controller.go
index 6d30c0a..b883b7d 100644
--- a/server/controller.go
+++ b/server/controller.go
@@ -23,7 +23,6 @@ import (
"os"
"os/signal"
"strconv"
- "sync"
"time"
)
@@ -48,7 +47,6 @@ type Controller struct {
Register chan *Client
Unregister chan *Client
Ingest chan *Call
- ingestMutex sync.Mutex
running bool
}
@@ -271,7 +269,7 @@ func (controller *Controller) IngestCall(call *Call) {
}
if system == nil || talkgroup == nil {
- logCall(call, LogLevelInfo, "no matching system/talkgroup")
+ logCall(call, LogLevelWarn, "no matching system/talkgroup")
return
}
@@ -516,7 +514,7 @@ func (controller *Controller) Start() error {
}
go func() {
- c := make(chan os.Signal)
+ c := make(chan os.Signal, 8)
signal.Notify(c, os.Interrupt)
<-c
controller.Terminate()
@@ -536,7 +534,10 @@ func (controller *Controller) Start() error {
if timer != nil {
timer.Stop()
}
+
timer = time.AfterFunc(time.Second, func() {
+ timer = nil
+
controller.LogClientsCount()
if controller.Options.ShowListenersCount {
diff --git a/server/dirwatch.go b/server/dirwatch.go
index 8ff6be0..95c3f1c 100644
--- a/server/dirwatch.go
+++ b/server/dirwatch.go
@@ -21,7 +21,6 @@ import (
"errors"
"fmt"
"io/fs"
- "io/ioutil"
"math"
"mime"
"os"
@@ -38,9 +37,10 @@ import (
)
const (
- DirwatchKindDefault = "default"
- DirwatchKindSdrTrunk = "sdr-trunk"
- DirwatchKindTrunkRecorder = "trunk-recorder"
+ DirwatchTypeDefault = "default"
+ DirwatchTypeDSDPlus = "dsdplus"
+ DirwatchTypeSdrTrunk = "sdr-trunk"
+ DirwatchTypeTrunkRecorder = "trunk-recorder"
)
type Dirwatch struct {
@@ -59,9 +59,19 @@ type Dirwatch struct {
UsePolling bool `json:"usePolling"`
controller *Controller
dirs map[string]bool
+ mutex sync.Mutex
+ timers map[string]*time.Timer
watcher *fsnotify.Watcher
}
+func NewDirwatch() *Dirwatch {
+ return &Dirwatch{
+ dirs: map[string]bool{},
+ mutex: sync.Mutex{},
+ timers: map[string]*time.Timer{},
+ }
+}
+
func (dirwatch *Dirwatch) FromMap(m map[string]any) *Dirwatch {
switch v := m["_id"].(type) {
case float64:
@@ -135,16 +145,18 @@ func (dirwatch *Dirwatch) Ingest(p string) {
var err error
switch dirwatch.Kind {
- case DirwatchKindTrunkRecorder:
+ case DirwatchTypeDSDPlus:
+ err = dirwatch.ingestDSDPlus(p)
+ case DirwatchTypeTrunkRecorder:
err = dirwatch.ingestTrunkRecorder(p)
- case DirwatchKindSdrTrunk:
+ case DirwatchTypeSdrTrunk:
err = dirwatch.ingestSdrTrunk(p)
default:
err = dirwatch.ingestDefault(p)
}
if err != nil {
- dirwatch.controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("dirwatch.ingest: %s, %s", err.Error(), p))
+ dirwatch.controller.Logs.LogEvent(LogLevelWarn, fmt.Sprintf("dirwatch.ingest: %s, %s", err.Error(), p))
}
}
@@ -156,7 +168,11 @@ func (dirwatch *Dirwatch) ingestDefault(p string) error {
switch v := dirwatch.Extension.(type) {
case string:
- ext = fmt.Sprintf(".%s", v)
+ if len(v) > 0 {
+ ext = fmt.Sprintf(".%s", v)
+ } else {
+ ext = ".wav"
+ }
default:
ext = ".wav"
}
@@ -202,7 +218,7 @@ func (dirwatch *Dirwatch) ingestDefault(p string) error {
return err
}
-func (dirwatch *Dirwatch) ingestSdrTrunk(p string) error {
+func (dirwatch *Dirwatch) ingestDSDPlus(p string) error {
var (
err error
ext string
@@ -229,6 +245,48 @@ func (dirwatch *Dirwatch) ingestSdrTrunk(p string) error {
call.AudioType = mime.TypeByExtension(path.Ext(p))
call.Frequency = dirwatch.Frequency
+ switch v := dirwatch.SystemId.(type) {
+ case uint:
+ call.System = v
+ }
+
+ if call.Audio, err = os.ReadFile(p); err != nil {
+ return err
+ }
+
+ if err = ParseDSDPlusMeta(call, p); err != nil {
+ return err
+ }
+
+ if ok, err := call.IsValid(); ok {
+ dirwatch.controller.Ingest <- call
+
+ if dirwatch.DeleteAfter {
+ if err = os.Remove(p); err != nil {
+ return err
+ }
+ }
+
+ } else {
+ return err
+ }
+
+ return nil
+}
+
+func (dirwatch *Dirwatch) ingestSdrTrunk(p string) error {
+ var err error
+
+ if !strings.EqualFold(path.Ext(p), ".mp3") {
+ return nil
+ }
+
+ call := NewCall()
+
+ call.AudioName = filepath.Base(p)
+ call.AudioType = mime.TypeByExtension(path.Ext(p))
+ call.Frequency = dirwatch.Frequency
+
if call.Audio, err = os.ReadFile(p); err != nil {
return err
}
@@ -290,11 +348,11 @@ func (dirwatch *Dirwatch) ingestTrunkRecorder(p string) error {
call.System = v
}
- if call.Audio, err = ioutil.ReadFile(audioName); err != nil {
+ if call.Audio, err = os.ReadFile(audioName); err != nil {
return nil
}
- if b, err = ioutil.ReadFile(p); err != nil {
+ if b, err = os.ReadFile(p); err != nil {
return err
}
@@ -550,15 +608,16 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
}
go func() {
- var timers = sync.Map{}
-
logError := func(err error) {
controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("dirwatch.watcher: %v", err.Error()))
}
newTimer := func(eventName string) *time.Timer {
return time.AfterFunc(delay, func() {
- timers.Delete(eventName)
+ dirwatch.mutex.Lock()
+ defer dirwatch.mutex.Unlock()
+
+ delete(dirwatch.timers, eventName)
if _, err := os.Stat(eventName); err == nil {
dirwatch.Ingest(eventName)
@@ -567,74 +626,71 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
}
defer func() {
- timers.Range(func(k any, t any) bool {
- switch v := t.(type) {
- case *time.Timer:
- v.Stop()
- }
-
- timers.Delete(k)
-
- return true
- })
-
switch v := recover().(type) {
case error:
controller.Logs.LogEvent(LogLevelError, v.Error())
}
+
+ dirwatch.mutex.Lock()
+ defer dirwatch.mutex.Unlock()
+
+ for e, t := range dirwatch.timers {
+ t.Stop()
+ delete(dirwatch.timers, e)
+ }
+
+ if dirwatch.watcher != nil {
+ dirwatch.Start(controller)
+ }
}()
for {
if dirwatch.watcher == nil {
- break
+ return
}
select {
case event, ok := <-dirwatch.watcher.Events:
- if ok {
- switch event.Op {
- case fsnotify.Create:
- if dirwatch.isDir(event.Name) {
- if err := dirwatch.walkDir(event.Name); err != nil {
- logError(err)
- }
+ if !ok {
+ return
+ }
- } else {
- if f, ok := timers.LoadAndDelete(event.Name); ok {
- switch v := f.(type) {
- case *time.Timer:
- v.Stop()
- }
- }
- timers.Store(event.Name, newTimer(event.Name))
+ switch event.Op {
+ case fsnotify.Create:
+ if dirwatch.isDir(event.Name) {
+ if err := dirwatch.walkDir(event.Name); err != nil {
+ logError(err)
}
- case fsnotify.Remove:
- if dirwatch.dirs[event.Name] {
- if err := dirwatch.watcher.Remove(event.Name); err == nil {
- delete(dirwatch.dirs, event.Name)
- } else {
- logError(err)
- }
+ } else {
+ if dirwatch.timers[event.Name] != nil {
+ dirwatch.timers[event.Name].Stop()
}
-
- case fsnotify.Write:
- if f, ok := timers.LoadAndDelete(event.Name); ok {
- switch v := f.(type) {
- case *time.Timer:
- v.Stop()
- }
- }
- timers.Store(event.Name, newTimer(event.Name))
+ dirwatch.timers[event.Name] = newTimer(event.Name)
}
+
+ case fsnotify.Remove:
+ if dirwatch.dirs[event.Name] {
+ if err := dirwatch.watcher.Remove(event.Name); err == nil {
+ delete(dirwatch.dirs, event.Name)
+ } else {
+ logError(err)
+ }
+ }
+
+ case fsnotify.Write:
+ if dirwatch.timers[event.Name] != nil {
+ dirwatch.timers[event.Name].Stop()
+ }
+ dirwatch.timers[event.Name] = newTimer(event.Name)
}
case err, ok := <-dirwatch.watcher.Errors:
if ok {
logError(err)
-
- return
}
+
+ return
}
}
}()
@@ -671,8 +727,9 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
func (dirwatch *Dirwatch) Stop() {
if dirwatch.watcher != nil {
- dirwatch.watcher.Close()
+ w := dirwatch.watcher
dirwatch.watcher = nil
+ w.Close()
}
}
@@ -699,8 +756,7 @@ func (dirwatches *Dirwatches) FromMap(f []any) *Dirwatches {
for _, f := range f {
switch v := f.(type) {
case map[string]any:
- dirwatch := &Dirwatch{}
- dirwatch.FromMap(v)
+ dirwatch := NewDirwatch().FromMap(v)
dirwatches.List = append(dirwatches.List, dirwatch)
}
}
@@ -739,7 +795,7 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
}
for rows.Next() {
- dirwatch := &Dirwatch{}
+ dirwatch := NewDirwatch()
if err = rows.Scan(&id, &delay, &dirwatch.DeleteAfter, &dirwatch.Directory, &dirwatch.Disabled, &extension, &frequency, &mask, &order, &systemId, &talkgroupId, &kind, &dirwatch.UsePolling); err != nil {
break
diff --git a/server/ffmpeg.go b/server/ffmpeg.go
index 17342fd..ce502dc 100644
--- a/server/ffmpeg.go
+++ b/server/ffmpeg.go
@@ -75,7 +75,7 @@ func (ffmpeg *FFMpeg) Convert(call *Call, systems *Systems, tags *Tags, mode uin
if !ffmpeg.warned {
ffmpeg.warned = true
- return errors.New("ffmpeg is not available, no audio conversion will be performed.")
+ return errors.New("ffmpeg is not available, no audio conversion will be performed")
}
return nil
}
diff --git a/server/main.go b/server/main.go
index b565a85..6b725b9 100644
--- a/server/main.go
+++ b/server/main.go
@@ -18,7 +18,7 @@ package main
import (
"crypto/tls"
"fmt"
- "io/ioutil"
+ "io"
"log"
"mime"
"net/http"
@@ -198,7 +198,7 @@ func main() {
TLSConfig: tlsConfig,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
- ErrorLog: log.New(ioutil.Discard, "", 0),
+ ErrorLog: log.New(io.Discard, "", 0),
}
s.SetKeepAlivesEnabled(true)
diff --git a/server/parsers.go b/server/parsers.go
index 129894d..0c169d5 100644
--- a/server/parsers.go
+++ b/server/parsers.go
@@ -21,13 +21,70 @@ import (
"mime"
"mime/multipart"
"path"
+ "path/filepath"
"regexp"
"strconv"
+ "strings"
"time"
"github.com/dhowden/tag"
)
+func ParseDSDPlusMeta(call *Call, fp string) error {
+ dir := filepath.Dir(fp)
+ base := strings.TrimSuffix(filepath.Base(fp), filepath.Ext(fp))
+
+ if d := regexp.MustCompile(`([0-9]+)$`).FindStringSubmatch(dir); len(d) == 2 && len(d[1]) == 8 {
+ if t := regexp.MustCompile(`^([0-9]+)`).FindStringSubmatch(base); len(t) == 2 && len(t[1]) == 6 {
+ if dy, err := strconv.Atoi(d[1][0:4]); err == nil {
+ if dm, err := strconv.Atoi(d[1][4:6]); err == nil {
+ if dd, err := strconv.Atoi(d[1][6:8]); err == nil {
+ if th, err := strconv.Atoi(t[1][0:2]); err == nil {
+ if tm, err := strconv.Atoi(t[1][2:4]); err == nil {
+ if ts, err := strconv.Atoi(t[1][4:6]); err == nil {
+ call.DateTime = time.Date(dy, time.Month(dm), dd, th, tm, ts, 0, time.Now().Location()).UTC()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if s := regexp.MustCompile(`^[0-9]+_[0-9]+_[^_]+_([0-9]+)-([0-9]+)_`).FindStringSubmatch(base); len(s) == 3 {
+ if sys, err := strconv.Atoi(s[1]); err == nil && sys > 0 {
+ call.System = uint(sys)
+ }
+ }
+
+ tu := regexp.MustCompile(`([0-9]+)_([0-9]+)$|([0-9]+)_([0-9]+)\[([^\]]*)\]$`).FindStringSubmatch(base)
+
+ if len(tu[3]) > 0 {
+ tu[1] = tu[3]
+ }
+
+ if len(tu[4]) > 0 {
+ tu[2] = tu[4]
+ }
+
+ if tg, err := strconv.Atoi(tu[1]); err == nil && tg > 0 {
+ call.Talkgroup = uint(tg)
+ if src, err := strconv.Atoi(tu[2]); err == nil && src > 0 {
+ call.Source = uint(src)
+ if len(tu[5]) > 0 && strings.TrimSpace(tu[5]) != strings.TrimSpace(tu[2]) {
+ if b := regexp.MustCompile(`^([\.\-\ ,_]+)$`).MatchString(tu[5]); !b {
+ units := NewUnits()
+ units.Add(uint(src), tu[5])
+ call.units = units
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
func ParseSdrTrunkMeta(call *Call, controller *Controller) error {
var (
s []string
@@ -43,7 +100,7 @@ func ParseSdrTrunkMeta(call *Call, controller *Controller) error {
s = regexp.MustCompile(`^([0-9]+) ?(.*)$`).FindStringSubmatch(m.Artist())
if len(s) >= 2 {
- if i, err = strconv.Atoi(s[1]); err != nil {
+ if i, err = strconv.Atoi(s[1][0:1]); err != nil {
return err
}
if i > 0 {
diff --git a/server/version.go b/server/version.go
index 41df5ed..505ad40 100644
--- a/server/version.go
+++ b/server/version.go
@@ -15,4 +15,4 @@
package main
-const Version = "6.5.3"
+const Version = "6.5.4"