├── client ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── icons │ │ │ ├── icon-72x72.png │ │ │ ├── icon-96x96.png │ │ │ ├── icon-128x128.png │ │ │ ├── icon-144x144.png │ │ │ ├── icon-152x152.png │ │ │ ├── icon-192x192.png │ │ │ ├── icon-384x384.png │ │ │ └── icon-512x512.png │ │ └── fonts │ │ │ ├── material-icons-v97.woff2 │ │ │ ├── roboto-latin-w300-v29.woff2 │ │ │ ├── roboto-latin-w400-v29.woff2 │ │ │ ├── roboto-latin-w500-v29.woff2 │ │ │ ├── roboto-latin-ext-w300-v29.woff2 │ │ │ ├── roboto-latin-ext-w400-v29.woff2 │ │ │ └── roboto-latin-ext-w500-v29.woff2 │ ├── app │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── shared │ │ │ ├── update │ │ │ │ ├── update.component.scss │ │ │ │ ├── update.component.html │ │ │ │ ├── update.component.ts │ │ │ │ ├── update.module.ts │ │ │ │ └── update.service.ts │ │ │ ├── shared.module.ts │ │ │ └── material │ │ │ │ └── material.module.ts │ │ ├── components │ │ │ └── rdio-scanner │ │ │ │ ├── admin │ │ │ │ ├── login │ │ │ │ │ ├── login.component.scss │ │ │ │ │ ├── login.component.html │ │ │ │ │ └── login.component.ts │ │ │ │ ├── todos │ │ │ │ │ ├── todos.component.scss │ │ │ │ │ ├── todos.component.html │ │ │ │ │ └── todos.component.ts │ │ │ │ ├── tools │ │ │ │ │ ├── import-export-config │ │ │ │ │ │ ├── import-export-config.component.scss │ │ │ │ │ │ ├── import-export-config.component.html │ │ │ │ │ │ └── import-export-config.component.ts │ │ │ │ │ ├── password │ │ │ │ │ │ ├── password.component.scss │ │ │ │ │ │ ├── password.component.html │ │ │ │ │ │ └── password.component.ts │ │ │ │ │ ├── import-units │ │ │ │ │ │ ├── import-units.component.scss │ │ │ │ │ │ ├── import-units.component.html │ │ │ │ │ │ └── import-units.component.ts │ │ │ │ │ ├── import-talkgroups │ │ │ │ │ │ └── import-talkgroups.component.scss │ │ │ │ │ ├── tools.component.ts │ │ │ │ │ └── tools.component.html │ │ │ │ ├── config │ │ │ │ │ ├── tags │ │ │ │ │ │ ├── tags.component.scss │ │ │ │ │ │ ├── tags.component.html │ │ │ │ │ │ └── tags.component.ts │ │ │ │ │ ├── groups │ │ │ │ │ │ ├── groups.component.scss │ │ │ │ │ │ ├── groups.component.html │ │ │ │ │ │ └── groups.component.ts │ │ │ │ │ ├── systems │ │ │ │ │ │ ├── select │ │ │ │ │ │ │ ├── select.component.scss │ │ │ │ │ │ │ └── select.component.html │ │ │ │ │ │ ├── systems.component.html │ │ │ │ │ │ ├── unit │ │ │ │ │ │ │ ├── unit.component.ts │ │ │ │ │ │ │ └── unit.component.html │ │ │ │ │ │ ├── talkgroup │ │ │ │ │ │ │ └── talkgroup.component.ts │ │ │ │ │ │ └── systems.component.ts │ │ │ │ │ ├── options │ │ │ │ │ │ └── options.component.ts │ │ │ │ │ ├── config.component.scss │ │ │ │ │ ├── access │ │ │ │ │ │ └── access.component.ts │ │ │ │ │ └── downstreams │ │ │ │ │ │ └── downstreams.component.ts │ │ │ │ ├── admin.component.scss │ │ │ │ ├── logs │ │ │ │ │ ├── logs.component.scss │ │ │ │ │ └── logs.component.html │ │ │ │ ├── index.ts │ │ │ │ ├── admin.component.ts │ │ │ │ └── admin.component.html │ │ │ │ ├── main │ │ │ │ └── support │ │ │ │ │ ├── support.component.scss │ │ │ │ │ ├── support.component.html │ │ │ │ │ └── support.component.ts │ │ │ │ ├── native │ │ │ │ ├── native.component.scss │ │ │ │ ├── native.component.html │ │ │ │ ├── badges │ │ │ │ │ ├── app-store-badge.component.ts │ │ │ │ │ └── google-play-badge.component.ts │ │ │ │ ├── native.module.ts │ │ │ │ └── native.component.ts │ │ │ │ ├── index.ts │ │ │ │ ├── rdio-scanner.component.scss │ │ │ │ ├── select │ │ │ │ ├── select.component.scss │ │ │ │ ├── select.component.html │ │ │ │ └── select.component.ts │ │ │ │ ├── rdio-scanner.component.html │ │ │ │ ├── rdio-scanner.module.ts │ │ │ │ ├── search │ │ │ │ └── search.component.scss │ │ │ │ └── common.scss │ │ ├── pages │ │ │ └── rdio-scanner │ │ │ │ ├── admin │ │ │ │ ├── admin.component.html │ │ │ │ ├── admin.component.scss │ │ │ │ ├── admin.routes.ts │ │ │ │ ├── admin.component.ts │ │ │ │ └── admin.module.ts │ │ │ │ ├── index.ts │ │ │ │ ├── rdio-scanner.component.ts │ │ │ │ ├── rdio-scanner-main.component.ts │ │ │ │ ├── rdio-scanner.routes.ts │ │ │ │ └── rdio-scanner.module.ts │ │ ├── app.routes.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── favicon.ico │ ├── environments │ │ ├── environment.ts │ │ └── environment.prod.ts │ ├── styles │ │ ├── material-icons.scss │ │ └── roboto-fonts.scss │ ├── index.html │ ├── styles.scss │ ├── proxy.conf.js │ ├── main.ts │ ├── manifest.webmanifest │ └── polyfills.ts ├── .editorconfig ├── tsconfig.app.json ├── tsconfig.spec.json ├── .eslintrc.json ├── .browserslistrc ├── ngsw-config.json ├── .gitignore ├── tsconfig.json └── package.json ├── .github └── FUNDING.yml ├── .gitignore ├── docs ├── images │ ├── admin-login.png │ ├── admin-todos.png │ ├── webapp-led.png │ ├── webapp-main.png │ ├── rdio-scanner.png │ ├── twitter-badge.png │ ├── webapp-search.png │ ├── webapp-select.png │ ├── app-store-badge.png │ ├── webapp-controls.png │ ├── webapp-display.png │ ├── windows-services.png │ ├── google-play-badge.png │ ├── webapp-search-list.png │ ├── webapp-control-avoid.png │ ├── webapp-control-holdtg.png │ ├── webapp-control-pause.png │ ├── webapp-control-replay.png │ ├── webapp-control-search.png │ ├── webapp-control-select.png │ ├── webapp-control-skip.png │ ├── webapp-search-filters.png │ ├── webapp-select-all-off.png │ ├── webapp-select-all-on.png │ ├── webapp-select-groups.png │ ├── webapp-select-system.png │ ├── webapp-control-holdsys.png │ ├── webapp-select-group-off.png │ ├── webapp-select-group-on.png │ ├── webapp-select-system-on.png │ ├── webapp-control-livefeed-on.png │ ├── webapp-select-system-off.png │ ├── webapp-select-group-partial.png │ └── webapp-control-livefeed-partial.png ├── examples │ ├── nginx │ │ ├── README.md │ │ └── nginx.conf │ ├── apache │ │ ├── README.md │ │ └── .htaccess │ ├── rtlsdr-airband │ │ ├── README.md │ │ └── rtl_airband.conf │ ├── iframe │ │ ├── README.md │ │ ├── index.css │ │ └── index.html │ └── trunk-recorder │ │ └── upload-call.sh ├── docker │ └── docker-compose.yml ├── update-from-v5.md ├── api.md └── faq.md ├── server ├── .gitignore ├── version.go ├── webapp.go ├── blacklists.go ├── go.mod ├── message.go ├── daemon.go ├── livefeed.go ├── scheduler.go ├── keypad.go ├── defaults.go └── ffmpeg.go ├── .containerignore ├── Containerfile ├── CONTRIBUTING.md └── COMPILING.md /client/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [chuot] -------------------------------------------------------------------------------- /client/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode 3 | *.token 4 | /build 5 | /dist 6 | -------------------------------------------------------------------------------- /client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/favicon.ico -------------------------------------------------------------------------------- /client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | }; 4 | -------------------------------------------------------------------------------- /docs/images/admin-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/admin-login.png -------------------------------------------------------------------------------- /docs/images/admin-todos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/admin-todos.png -------------------------------------------------------------------------------- /docs/images/webapp-led.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-led.png -------------------------------------------------------------------------------- /docs/images/webapp-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-main.png -------------------------------------------------------------------------------- /client/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | height: 100%; 4 | width: 100%; 5 | } -------------------------------------------------------------------------------- /client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /docs/images/rdio-scanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/rdio-scanner.png -------------------------------------------------------------------------------- /docs/images/twitter-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/twitter-badge.png -------------------------------------------------------------------------------- /docs/images/webapp-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-search.png -------------------------------------------------------------------------------- /docs/images/webapp-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select.png -------------------------------------------------------------------------------- /client/src/app/shared/update/update.component.scss: -------------------------------------------------------------------------------- 1 | .mat-dialog-actions { 2 | justify-content: space-between; 3 | } -------------------------------------------------------------------------------- /docs/images/app-store-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/app-store-badge.png -------------------------------------------------------------------------------- /docs/images/webapp-controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-controls.png -------------------------------------------------------------------------------- /docs/images/webapp-display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-display.png -------------------------------------------------------------------------------- /docs/images/windows-services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/windows-services.png -------------------------------------------------------------------------------- /docs/images/google-play-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/google-play-badge.png -------------------------------------------------------------------------------- /docs/images/webapp-search-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-search-list.png -------------------------------------------------------------------------------- /docs/images/webapp-control-avoid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-avoid.png -------------------------------------------------------------------------------- /docs/images/webapp-control-holdtg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-holdtg.png -------------------------------------------------------------------------------- /docs/images/webapp-control-pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-pause.png -------------------------------------------------------------------------------- /docs/images/webapp-control-replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-replay.png -------------------------------------------------------------------------------- /docs/images/webapp-control-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-search.png -------------------------------------------------------------------------------- /docs/images/webapp-control-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-select.png -------------------------------------------------------------------------------- /docs/images/webapp-control-skip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-skip.png -------------------------------------------------------------------------------- /docs/images/webapp-search-filters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-search-filters.png -------------------------------------------------------------------------------- /docs/images/webapp-select-all-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-all-off.png -------------------------------------------------------------------------------- /docs/images/webapp-select-all-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-all-on.png -------------------------------------------------------------------------------- /docs/images/webapp-select-groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-groups.png -------------------------------------------------------------------------------- /docs/images/webapp-select-system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-system.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-72x72.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-96x96.png -------------------------------------------------------------------------------- /docs/images/webapp-control-holdsys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-holdsys.png -------------------------------------------------------------------------------- /docs/images/webapp-select-group-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-group-off.png -------------------------------------------------------------------------------- /docs/images/webapp-select-group-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-group-on.png -------------------------------------------------------------------------------- /docs/images/webapp-select-system-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-system-on.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-128x128.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-144x144.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-152x152.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-192x192.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-384x384.png -------------------------------------------------------------------------------- /client/src/assets/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/icons/icon-512x512.png -------------------------------------------------------------------------------- /docs/examples/nginx/README.md: -------------------------------------------------------------------------------- 1 | # NGINX 2 | 3 | Simple NGINX configuration that reverse proxy /rdio-scanner path to an internal instance. -------------------------------------------------------------------------------- /docs/images/webapp-control-livefeed-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-livefeed-on.png -------------------------------------------------------------------------------- /docs/images/webapp-select-system-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-system-off.png -------------------------------------------------------------------------------- /docs/images/webapp-select-group-partial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-select-group-partial.png -------------------------------------------------------------------------------- /docs/examples/apache/README.md: -------------------------------------------------------------------------------- 1 | # Apache HTTP server 2 | 3 | Simple Apache HTTP `.htaccess` to reverse proxy to an internal Rdio Scanner instance. -------------------------------------------------------------------------------- /docs/images/webapp-control-livefeed-partial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/docs/images/webapp-control-livefeed-partial.png -------------------------------------------------------------------------------- /client/src/assets/fonts/material-icons-v97.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/fonts/material-icons-v97.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/roboto-latin-w300-v29.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/fonts/roboto-latin-w300-v29.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/roboto-latin-w400-v29.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/fonts/roboto-latin-w400-v29.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/roboto-latin-w500-v29.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/fonts/roboto-latin-w500-v29.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/roboto-latin-ext-w300-v29.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/fonts/roboto-latin-ext-w300-v29.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/roboto-latin-ext-w400-v29.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/fonts/roboto-latin-ext-w400-v29.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/roboto-latin-ext-w500-v29.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuot/rdio-scanner/HEAD/client/src/assets/fonts/roboto-latin-ext-w500-v29.woff2 -------------------------------------------------------------------------------- /client/src/app/components/rdio-scanner/admin/login/login.component.scss: -------------------------------------------------------------------------------- 1 | form > button { 2 | margin-top: 1rem; 3 | } 4 | 5 | .mat-raised-button, 6 | .mat-form-field { 7 | display: block; 8 | } 9 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | /*.db 2 | /*.db-journal 3 | /*.crt 4 | /*.json 5 | /*.key 6 | /*.ini 7 | /*.sqlite 8 | /__debug_bin 9 | /autocert 10 | /rdio-scanner 11 | /server 12 | /webapp/* 13 | !/webapp -------------------------------------------------------------------------------- /client/src/app/pages/rdio-scanner/admin/admin.component.html: -------------------------------------------------------------------------------- 1 |

Rdio Scanner server v{{version}}

2 |
3 | 4 | 5 | 6 |
-------------------------------------------------------------------------------- /.containerignore: -------------------------------------------------------------------------------- 1 | client/.angular/cache 2 | client/node_modules 3 | server/*.db 4 | server/*.crt 5 | server/*.json 6 | server/*.key 7 | server/*.ini 8 | server/*.sqlite 9 | server/__debug_bin 10 | server/autocert 11 | server/server -------------------------------------------------------------------------------- /client/src/app/components/rdio-scanner/admin/todos/todos.component.scss: -------------------------------------------------------------------------------- 1 | .info { 2 | color: green; 3 | } 4 | 5 | .warn { 6 | color: orange; 7 | } 8 | 9 | .todo { 10 | text-overflow: unset; 11 | white-space: normal; 12 | } -------------------------------------------------------------------------------- /client/src/app/components/rdio-scanner/admin/tools/import-export-config/import-export-config.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | > div { 3 | align-items: center; 4 | display: flex; 5 | flex-direction: row; 6 | justify-content: space-between; 7 | } 8 | } -------------------------------------------------------------------------------- /docs/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | server: 5 | environment: 6 | - TZ=America/Toronto 7 | image: docker.io/chuot/rdio-scanner:latest 8 | ports: 9 | - "3000:3000" 10 | volumes: 11 | - /home/radio/rdio-scanner:/app/data:z -------------------------------------------------------------------------------- /client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /client/src/app/components/rdio-scanner/admin/tools/password/password.component.scss: -------------------------------------------------------------------------------- 1 | :host > form { 2 | display: flex; 3 | flex-direction: column; 4 | 5 | > div { 6 | display: flex; 7 | flex-direction: row; 8 | justify-content: space-between; 9 | } 10 | 11 | .mat-form-field { 12 | margin-bottom: 1rem; 13 | } 14 | } -------------------------------------------------------------------------------- /client/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /client/src/app/shared/update/update.component.html: -------------------------------------------------------------------------------- 1 |

New version available

2 |
A new version of this webapp is available. Would you like to reload the page?
3 |
4 | 5 | 6 |
-------------------------------------------------------------------------------- /client/src/app/components/rdio-scanner/admin/config/tags/tags.component.scss: -------------------------------------------------------------------------------- 1 | .tags { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | justify-content: space-between; 6 | 7 | > div { 8 | align-items: center; 9 | display: flex; 10 | flex-direction: row; 11 | margin-right: 0.5rem; 12 | } 13 | } 14 | 15 | @media (max-width: 719px) { 16 | .tags > div { 17 | flex: 100%; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /client/src/app/components/rdio-scanner/admin/config/groups/groups.component.scss: -------------------------------------------------------------------------------- 1 | .groups { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | justify-content: space-between; 6 | 7 | > div { 8 | align-items: center; 9 | display: flex; 10 | flex-direction: row; 11 | margin-right: 0.5rem; 12 | } 13 | } 14 | 15 | @media (max-width: 719px) { 16 | .groups > div { 17 | flex: 100%; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /docs/examples/apache/.htaccess: -------------------------------------------------------------------------------- 1 | # Create a rdio-scanner subfolder under the DOCUMENT_ROOT and put this file in it. 2 | # Don't forget to change 127.0.0.1:3000 to the internal IP of your Rdio Scanner instance. 3 | 4 | DirectoryIndex index.html 5 | 6 | RewriteEngine on 7 | 8 | RewriteCond %{HTTP:CONNECTION} ^upgrade$ [NC,OR] 9 | RewriteCond %{HTTP:UPGRADE} ^websocket$ [NC] 10 | RewriteRule ^/?(.*)$ ws://127.0.0.1:3000/$1 [P,L] 11 | RewriteRule ^/?(.*)$ http://127.0.0.1:3000/$1 [P,L] -------------------------------------------------------------------------------- /client/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended" 9 | ], 10 | "parser": "@typescript-eslint/parser", 11 | "parserOptions": { 12 | "ecmaVersion": 12, 13 | "sourceType": "module" 14 | }, 15 | "plugins": [ 16 | "@typescript-eslint" 17 | ], 18 | "rules": { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/examples/rtlsdr-airband/README.md: -------------------------------------------------------------------------------- 1 | # RTLSDR-Airband 2 | 3 | Here's an example with RTLSDR-Airband: 4 | 5 | ## RTLSDR-Airband's configuration 6 | 7 | See the `rtl_airband.conf` file for an example. 8 | 9 | ## Rdio Scanner's configuration 10 | 11 | In you Rdio Scanner dirwatch configuration, use those parameters: 12 | 13 | - Directory: `/tmp/radio/Laurentides` 14 | - Extension: `mp3` 15 | - Type: `Default` 16 | - System: _choose the appropriate one_ 17 | - Mask: `laurentides_#DATE_#TIME_#TGHZ` 18 | -------------------------------------------------------------------------------- /docs/examples/iframe/README.md: -------------------------------------------------------------------------------- 1 | # IFRAME example 2 | 3 | It may be useful for some installations to have a section with information or instructions so that users can read and better understand what it is about. 4 | 5 | Here is an example of a web page that embeds an Rdio Scanner instance in an ` 19 | 20 |
21 |

Instructions

22 |

Phasellus finibus porta leo quis semper. Vivamus nec ornare lectus. Maecenas sit amet convallis 23 | libero. Fusce finibus est nec iaculis facilisis. Praesent non urna neque. Donec aliquet suscipit 24 | tellus id luctus. Fusce eget semper nisi. Duis vel ultrices risus. Nulla et ex nec nisi sodales 25 | rutrum quis nec diam. Nullam sit amet faucibus arcu. Vestibulum aliquam facilisis auctor. Nunc id 26 | massa sit amet risus malesuada maximus.

27 |

Donec euismod commodo massa in mattis. Curabitur sed gravida nulla, nec hendrerit lorem. In eget arcu 28 | et nisi sagittis facilisis vitae ac purus. Aliquam porttitor blandit venenatis. Aliquam a nisl elit. 29 | Aenean sed diam sagittis, sagittis massa sed, tempus est. Morbi dapibus diam ligula, ut posuere 30 | justo luctus sit amet. Quisque consequat tincidunt vulputate. Fusce tristique bibendum risus, id 31 | bibendum urna cursus sed. Donec commodo in tellus ac consequat.

32 |

Proin a massa quis ipsum dapibus scelerisque. Duis semper gravida nunc, vitae interdum risus molestie 33 | molestie. Vivamus suscipit urna quis lectus pulvinar, non pulvinar sapien porttitor. Nunc purus 34 | libero, tincidunt ut egestas et, porta nec sapien. Nunc eleifend porttitor finibus. Mauris tempor 35 | massa id ex mattis, in vehicula nisi auctor. Morbi porttitor, arcu ac tincidunt lobortis, mauris 36 | neque rutrum purus, non congue lorem dolor vitae mi. Quisque in turpis est. Mauris varius elit urna, 37 | ut luctus eros dignissim in. Proin nec velit quis orci tempor rutrum. Vestibulum pharetra ipsum 38 | turpis, at fermentum sem commodo ut.

39 |

Proin venenatis, nunc at hendrerit sagittis, velit nunc cursus nibh, quis interdum est augue in nibh. 40 | Nullam ultricies lacus ac arcu mollis, eu porttitor velit malesuada. Sed ut aliquam ex. Praesent 41 | faucibus lectus id porttitor sodales. Mauris ornare id dui ut ornare. Nunc volutpat euismod 42 | pellentesque. Mauris nulla enim, facilisis non lorem quis, ultrices pretium est. In laoreet leo quis 43 | viverra finibus. Curabitur quis lorem iaculis, imperdiet leo vitae, molestie turpis. Vestibulum 44 | rutrum risus nec erat posuere rhoncus interdum a nulla. Mauris vitae commodo enim. Donec nec mi sed 45 | ipsum maximus vehicula tristique non erat. Proin pulvinar, sem vitae semper volutpat, metus enim 46 | pulvinar neque, eget suscipit arcu tortor scelerisque nisi. Etiam risus est, dictum eget pretium 47 | vitae, consectetur id purus.

48 |
49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /server/ffmpeg.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2019-2022 Chrystian Huot 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see 15 | 16 | package main 17 | 18 | import ( 19 | "bytes" 20 | "errors" 21 | "fmt" 22 | "os/exec" 23 | "path" 24 | "regexp" 25 | "strconv" 26 | "strings" 27 | ) 28 | 29 | type FFMpeg struct { 30 | available bool 31 | version43 bool 32 | warned bool 33 | } 34 | 35 | func NewFFMpeg() *FFMpeg { 36 | ffmpeg := &FFMpeg{} 37 | 38 | stdout := bytes.NewBuffer([]byte(nil)) 39 | 40 | cmd := exec.Command("ffmpeg", "-version") 41 | cmd.Stdout = stdout 42 | 43 | if err := cmd.Run(); err == nil { 44 | ffmpeg.available = true 45 | 46 | if l, err := stdout.ReadString('\n'); err == nil { 47 | s := regexp.MustCompile(`.*ffmpeg version .{0,1}([0-9])\.([0-9])\.[0-9].*`).ReplaceAllString(strings.TrimSuffix(l, "\n"), "$1.$2") 48 | v := strings.Split(s, ".") 49 | if len(v) > 1 { 50 | if major, err := strconv.Atoi(v[0]); err == nil { 51 | if minor, err := strconv.Atoi(v[1]); err == nil { 52 | if major > 4 || (major == 4 && minor >= 3) { 53 | ffmpeg.version43 = true 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | return ffmpeg 62 | } 63 | 64 | func (ffmpeg *FFMpeg) Convert(call *Call, systems *Systems, tags *Tags, mode uint) error { 65 | var ( 66 | args = []string{"-i", "-"} 67 | err error 68 | ) 69 | 70 | if mode == AUDIO_CONVERSION_DISABLED { 71 | return nil 72 | } 73 | 74 | if !ffmpeg.available { 75 | if !ffmpeg.warned { 76 | ffmpeg.warned = true 77 | 78 | return errors.New("ffmpeg is not available, no audio conversion will be performed") 79 | } 80 | return nil 81 | } 82 | 83 | if system, ok := systems.GetSystem(call.System); ok { 84 | if talkgroup, ok := system.Talkgroups.GetTalkgroup(call.Talkgroup); ok { 85 | if tag, ok := tags.GetTag(talkgroup.TagId); ok { 86 | args = append(args, 87 | "-metadata", fmt.Sprintf("album=%v", talkgroup.Label), 88 | "-metadata", fmt.Sprintf("artist=%v", system.Label), 89 | "-metadata", fmt.Sprintf("date=%v", call.DateTime), 90 | "-metadata", fmt.Sprintf("genre=%v", tag), 91 | "-metadata", fmt.Sprintf("title=%v", talkgroup.Name), 92 | ) 93 | } 94 | } 95 | } 96 | 97 | if ffmpeg.version43 { 98 | if mode == AUDIO_CONVERSION_ENABLED_NORM { 99 | args = append(args, "-af", "apad=whole_dur=3s,loudnorm") 100 | } else if mode == AUDIO_CONVERSION_ENABLED_LOUD_NORM { 101 | args = append(args, "-af", "apad=whole_dur=3s,loudnorm=I=-16:TP=-1.5:LRA=11") 102 | } 103 | } 104 | 105 | args = append(args, "-c:a", "aac", "-b:a", "32k", "-movflags", "frag_keyframe+empty_moov", "-f", "ipod", "-") 106 | 107 | cmd := exec.Command("ffmpeg", args...) 108 | cmd.Stdin = bytes.NewReader(call.Audio) 109 | 110 | stdout := bytes.NewBuffer([]byte(nil)) 111 | cmd.Stdout = stdout 112 | 113 | stderr := bytes.NewBuffer([]byte(nil)) 114 | cmd.Stderr = stderr 115 | 116 | if err = cmd.Run(); err == nil { 117 | call.Audio = stdout.Bytes() 118 | call.AudioType = "audio/mp4" 119 | 120 | switch v := call.AudioName.(type) { 121 | case string: 122 | call.AudioName = fmt.Sprintf("%v.m4a", strings.TrimSuffix(v, path.Ext((v)))) 123 | } 124 | 125 | } else { 126 | fmt.Println(stderr.String()) 127 | } 128 | 129 | return nil 130 | } 131 | --------------------------------------------------------------------------------