@marineyachtradar/signalk-playback-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -0
- package/build.js +248 -0
- package/package.json +46 -0
- package/plugin/index.js +557 -0
- package/plugin/mrr-reader.js +315 -0
- package/plugin/public/assets/MaYaRa_RED.png +0 -0
- package/plugin/public/index.html +10 -0
- package/plugin/public/playback.html +572 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MarineYachtRadar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# MaYaRa Radar Playback Plugin for SignalK
|
|
2
|
+
|
|
3
|
+
A SignalK plugin for playing back `.mrr` radar recordings through the SignalK Radar API.
|
|
4
|
+
|
|
5
|
+
## What This Plugin Does
|
|
6
|
+
|
|
7
|
+
This plugin allows you to play pre-recorded radar data (`.mrr` files) through SignalK's Radar API. During playback, the recording appears as a virtual radar that any SignalK radar consumer can connect to and display.
|
|
8
|
+
|
|
9
|
+
**Use cases:**
|
|
10
|
+
- Test and develop SignalK radar display applications without live radar hardware
|
|
11
|
+
- Demo radar functionality at exhibitions or presentations
|
|
12
|
+
- Debug radar rendering code with consistent, repeatable data
|
|
13
|
+
- Share interesting radar captures with other developers
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Install from the **SignalK App Store**:
|
|
18
|
+
|
|
19
|
+
1. Open your SignalK server web interface
|
|
20
|
+
2. Go to **Appstore** > **Available**
|
|
21
|
+
3. Search for "MaYaRa Radar Playback"
|
|
22
|
+
4. Click **Install**
|
|
23
|
+
5. Restart SignalK when prompted
|
|
24
|
+
|
|
25
|
+
## Getting Started
|
|
26
|
+
|
|
27
|
+
### 1. Access the Playback Interface
|
|
28
|
+
|
|
29
|
+
After installation, navigate to:
|
|
30
|
+
```
|
|
31
|
+
http://your-signalk-server:3000/plugins/@marineyachtradar/signalk-playback-plugin/playback.html
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or find it in SignalK's **Webapps** menu.
|
|
35
|
+
|
|
36
|
+
### 2. Upload a Recording
|
|
37
|
+
|
|
38
|
+
You can upload `.mrr` or `.mrr.gz` files:
|
|
39
|
+
- **Drag and drop** a file onto the upload zone
|
|
40
|
+
- Or **click** the upload zone to browse for a file
|
|
41
|
+
|
|
42
|
+
Recordings are stored on the SignalK server and persist across restarts.
|
|
43
|
+
|
|
44
|
+
### 3. Load and Play
|
|
45
|
+
|
|
46
|
+
1. Select a recording from the list
|
|
47
|
+
2. Click **Load** to prepare it for playback
|
|
48
|
+
3. Click **Play** to start playback
|
|
49
|
+
4. Use **Pause** and **Stop** as needed
|
|
50
|
+
5. Enable **Loop** to repeat the recording continuously
|
|
51
|
+
|
|
52
|
+
### 4. View the Radar
|
|
53
|
+
|
|
54
|
+
Click **View Radar** to open the radar display. This shows the playback radar using the built-in viewer.
|
|
55
|
+
|
|
56
|
+
## Viewing with Other Clients
|
|
57
|
+
|
|
58
|
+
During playback, the recording registers as a virtual radar in SignalK. The radar ID follows the pattern `playback-{filename}`.
|
|
59
|
+
|
|
60
|
+
### Using mayara-server-signalk-plugin
|
|
61
|
+
|
|
62
|
+
If you have the **mayara-server-signalk-plugin** installed (the main MaYaRa radar plugin), you can also view playback recordings through its interface:
|
|
63
|
+
|
|
64
|
+
1. Start playback in this plugin
|
|
65
|
+
2. Open the mayara-server-signalk-plugin's radar viewer
|
|
66
|
+
3. The playback radar will appear in the radar list
|
|
67
|
+
4. Select it to view the recording with full MaYaRa GUI features
|
|
68
|
+
|
|
69
|
+
### Using Other SignalK Radar Consumers
|
|
70
|
+
|
|
71
|
+
Any application that implements the SignalK Radar API can display the playback:
|
|
72
|
+
- The radar appears at `/signalk/v2/api/vessels/self/radars/playback-{filename}`
|
|
73
|
+
- Spoke data streams via SignalK's binary WebSocket
|
|
74
|
+
|
|
75
|
+
## Obtaining Recording Files
|
|
76
|
+
|
|
77
|
+
Recording files (`.mrr`) are created by **mayara-server** when connected to a live radar:
|
|
78
|
+
|
|
79
|
+
1. Run mayara-server with a radar connected
|
|
80
|
+
2. Open the recordings page at `http://localhost:6502/recordings.html`
|
|
81
|
+
3. Select a radar and click **Start Recording**
|
|
82
|
+
4. Click **Stop Recording** when done
|
|
83
|
+
5. Download the recording as `.mrr.gz` (compressed)
|
|
84
|
+
6. Upload to this SignalK plugin
|
|
85
|
+
|
|
86
|
+
## File Format
|
|
87
|
+
|
|
88
|
+
- `.mrr` - MaYaRa Radar Recording (uncompressed)
|
|
89
|
+
- `.mrr.gz` - Gzip-compressed recording (~95% smaller for transfer)
|
|
90
|
+
|
|
91
|
+
Both formats are supported for upload. Files are stored uncompressed on the server for fast playback.
|
|
92
|
+
|
|
93
|
+
## Troubleshooting
|
|
94
|
+
|
|
95
|
+
**Recording won't load:**
|
|
96
|
+
- Check the SignalK server logs for errors
|
|
97
|
+
- Ensure the file is a valid `.mrr` or `.mrr.gz` file
|
|
98
|
+
- Verify the file wasn't corrupted during transfer
|
|
99
|
+
|
|
100
|
+
**No radar appears in SignalK:**
|
|
101
|
+
- Make sure playback is started (not just loaded)
|
|
102
|
+
- Refresh the radar consumer application
|
|
103
|
+
- Check that SignalK's Radar API is enabled
|
|
104
|
+
|
|
105
|
+
**Playback stutters:**
|
|
106
|
+
- This can happen on slower systems with large recordings
|
|
107
|
+
- Try using recordings with fewer spokes per revolution
|
|
108
|
+
|
|
109
|
+
## Technical Details
|
|
110
|
+
|
|
111
|
+
This plugin:
|
|
112
|
+
- Reads `.mrr` files directly (no mayara-server required)
|
|
113
|
+
- Registers as a RadarProvider via SignalK's Radar API
|
|
114
|
+
- Emits spoke frames through SignalK's `binaryStreamManager`
|
|
115
|
+
- Plays back frames at their original recorded timing
|
|
116
|
+
- Sets power status to "transmit" so GUI shows radar as active (not STANDBY)
|
|
117
|
+
- Pre-loads all frames for accurate timing
|
|
118
|
+
- Auto-stops current playback when loading a different file
|
|
119
|
+
|
|
120
|
+
## Development
|
|
121
|
+
|
|
122
|
+
Build options:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Build with GUI from npm (default)
|
|
126
|
+
node build.js
|
|
127
|
+
|
|
128
|
+
# Build with local mayara-gui (for development)
|
|
129
|
+
node build.js --local-gui
|
|
130
|
+
|
|
131
|
+
# Create tarball for manual install (includes public/)
|
|
132
|
+
node build.js --local-gui --pack
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The `--local-gui` option copies GUI files from the sibling `../mayara-gui` directory instead of from npm.
|
|
136
|
+
|
|
137
|
+
The `--pack` option creates a `.tgz` tarball with `public/` included (normally excluded by `.npmignore`). Install with:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm install /path/to/marineyachtradar-signalk-playback-plugin-0.1.0.tgz
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Related Projects
|
|
144
|
+
|
|
145
|
+
- **[mayara-server](https://github.com/MaYaRa-Marine/mayara-server)** - Standalone radar server (creates recordings)
|
|
146
|
+
- **[mayara-server-signalk-plugin](https://github.com/MaYaRa-Marine/mayara-server-signalk-plugin)** - SignalK plugin for live radar (connects to mayara-server)
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT License - See [LICENSE](LICENSE) for details.
|
package/build.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build script for mayara-server-signalk-playbackrecordings-plugin
|
|
4
|
+
*
|
|
5
|
+
* Copies @marineyachtradar/mayara-gui from npm to public/
|
|
6
|
+
* The plugin adds its own playback.html for file upload/control.
|
|
7
|
+
*
|
|
8
|
+
* Usage: node build.js [options]
|
|
9
|
+
* --local-gui Use local mayara-gui instead of npm (for development)
|
|
10
|
+
* --pack Create a .tgz tarball with public/ included (for manual install)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs')
|
|
14
|
+
const path = require('path')
|
|
15
|
+
const { execSync } = require('child_process')
|
|
16
|
+
|
|
17
|
+
const args = process.argv.slice(2)
|
|
18
|
+
const useLocalGui = args.includes('--local-gui')
|
|
19
|
+
const createPack = args.includes('--pack')
|
|
20
|
+
|
|
21
|
+
const scriptDir = __dirname
|
|
22
|
+
const publicDest = path.join(scriptDir, 'public')
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Recursively copy directory contents
|
|
26
|
+
*/
|
|
27
|
+
function copyDir(src, dest) {
|
|
28
|
+
if (!fs.existsSync(src)) {
|
|
29
|
+
console.error(`Source directory not found: ${src}`)
|
|
30
|
+
process.exit(1)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (fs.existsSync(dest)) {
|
|
34
|
+
fs.rmSync(dest, { recursive: true })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
38
|
+
|
|
39
|
+
const entries = fs.readdirSync(src, { withFileTypes: true })
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
const srcPath = path.join(src, entry.name)
|
|
42
|
+
const destPath = path.join(dest, entry.name)
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
copyDir(srcPath, destPath)
|
|
45
|
+
} else {
|
|
46
|
+
fs.copyFileSync(srcPath, destPath)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Copy GUI from npm package
|
|
53
|
+
*/
|
|
54
|
+
function setupGuiFromNpm() {
|
|
55
|
+
console.log('Copying GUI from node_modules...\n')
|
|
56
|
+
|
|
57
|
+
const guiSource = path.join(scriptDir, 'node_modules', '@marineyachtradar', 'mayara-gui')
|
|
58
|
+
|
|
59
|
+
if (!fs.existsSync(guiSource)) {
|
|
60
|
+
console.error('Error: @marineyachtradar/mayara-gui not found in node_modules')
|
|
61
|
+
console.error('Make sure it is listed in package.json dependencies')
|
|
62
|
+
process.exit(1)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (fs.existsSync(publicDest)) {
|
|
66
|
+
fs.rmSync(publicDest, { recursive: true })
|
|
67
|
+
}
|
|
68
|
+
fs.mkdirSync(publicDest, { recursive: true })
|
|
69
|
+
|
|
70
|
+
// Copy GUI files (exclude package.json, node_modules, etc.)
|
|
71
|
+
const guiPatterns = [
|
|
72
|
+
{ ext: '.html' },
|
|
73
|
+
{ ext: '.js' },
|
|
74
|
+
{ ext: '.css' },
|
|
75
|
+
{ ext: '.ico' },
|
|
76
|
+
{ ext: '.svg' },
|
|
77
|
+
{ dir: 'assets' },
|
|
78
|
+
{ dir: 'proto' },
|
|
79
|
+
{ dir: 'protobuf' }
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
// Exclude recordings.html since we have our own playback UI
|
|
83
|
+
const excludeFiles = ['recordings.html', 'recordings.js', 'recordings.css']
|
|
84
|
+
|
|
85
|
+
const entries = fs.readdirSync(guiSource, { withFileTypes: true })
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
if (excludeFiles.includes(entry.name)) continue
|
|
88
|
+
|
|
89
|
+
const srcPath = path.join(guiSource, entry.name)
|
|
90
|
+
const destPath = path.join(publicDest, entry.name)
|
|
91
|
+
|
|
92
|
+
if (entry.isDirectory()) {
|
|
93
|
+
if (guiPatterns.some(p => p.dir === entry.name)) {
|
|
94
|
+
copyDir(srcPath, destPath)
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
if (guiPatterns.some(p => p.ext && entry.name.endsWith(p.ext))) {
|
|
98
|
+
fs.copyFileSync(srcPath, destPath)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Copy our custom files from plugin/public/ (overrides GUI files)
|
|
104
|
+
const pluginPublic = path.join(scriptDir, 'plugin', 'public')
|
|
105
|
+
if (fs.existsSync(pluginPublic)) {
|
|
106
|
+
const customEntries = fs.readdirSync(pluginPublic, { withFileTypes: true })
|
|
107
|
+
let customCount = 0
|
|
108
|
+
for (const entry of customEntries) {
|
|
109
|
+
const srcPath = path.join(pluginPublic, entry.name)
|
|
110
|
+
const destPath = path.join(publicDest, entry.name)
|
|
111
|
+
if (entry.isDirectory()) {
|
|
112
|
+
copyDir(srcPath, destPath)
|
|
113
|
+
customCount++
|
|
114
|
+
} else {
|
|
115
|
+
fs.copyFileSync(srcPath, destPath)
|
|
116
|
+
customCount++
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
console.log(`Added ${customCount} custom files from plugin/public/`)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const fileCount = fs.readdirSync(publicDest, { recursive: true }).length
|
|
123
|
+
console.log(`Copied ${fileCount} GUI files to public/\n`)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Copy GUI from local sibling directory (for development)
|
|
128
|
+
*/
|
|
129
|
+
function setupGuiFromLocal() {
|
|
130
|
+
const localGuiPath = path.join(scriptDir, '..', 'mayara-gui')
|
|
131
|
+
console.log(`Copying GUI from local ${localGuiPath}...\n`)
|
|
132
|
+
|
|
133
|
+
if (fs.existsSync(publicDest)) {
|
|
134
|
+
fs.rmSync(publicDest, { recursive: true })
|
|
135
|
+
}
|
|
136
|
+
fs.mkdirSync(publicDest, { recursive: true })
|
|
137
|
+
|
|
138
|
+
const guiPatterns = [
|
|
139
|
+
{ ext: '.html' },
|
|
140
|
+
{ ext: '.js' },
|
|
141
|
+
{ ext: '.css' },
|
|
142
|
+
{ ext: '.ico' },
|
|
143
|
+
{ ext: '.svg' },
|
|
144
|
+
{ dir: 'assets' },
|
|
145
|
+
{ dir: 'proto' },
|
|
146
|
+
{ dir: 'protobuf' }
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
// Exclude recordings files since we have our own playback UI
|
|
150
|
+
const excludeFiles = ['recordings.html', 'recordings.js', 'recordings.css']
|
|
151
|
+
|
|
152
|
+
const entries = fs.readdirSync(localGuiPath, { withFileTypes: true })
|
|
153
|
+
for (const entry of entries) {
|
|
154
|
+
if (excludeFiles.includes(entry.name)) continue
|
|
155
|
+
|
|
156
|
+
const srcPath = path.join(localGuiPath, entry.name)
|
|
157
|
+
const destPath = path.join(publicDest, entry.name)
|
|
158
|
+
|
|
159
|
+
if (entry.isDirectory()) {
|
|
160
|
+
if (guiPatterns.some(p => p.dir === entry.name)) {
|
|
161
|
+
copyDir(srcPath, destPath)
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
if (guiPatterns.some(p => p.ext && entry.name.endsWith(p.ext))) {
|
|
165
|
+
fs.copyFileSync(srcPath, destPath)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Copy our custom files from plugin/public/ (overrides GUI files)
|
|
171
|
+
const pluginPublic = path.join(scriptDir, 'plugin', 'public')
|
|
172
|
+
if (fs.existsSync(pluginPublic)) {
|
|
173
|
+
const customEntries = fs.readdirSync(pluginPublic, { withFileTypes: true })
|
|
174
|
+
let customCount = 0
|
|
175
|
+
for (const entry of customEntries) {
|
|
176
|
+
const srcPath = path.join(pluginPublic, entry.name)
|
|
177
|
+
const destPath = path.join(publicDest, entry.name)
|
|
178
|
+
if (entry.isDirectory()) {
|
|
179
|
+
copyDir(srcPath, destPath)
|
|
180
|
+
customCount++
|
|
181
|
+
} else {
|
|
182
|
+
fs.copyFileSync(srcPath, destPath)
|
|
183
|
+
customCount++
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
console.log(`Added ${customCount} custom files from plugin/public/`)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const fileCount = fs.readdirSync(publicDest, { recursive: true }).length
|
|
190
|
+
console.log(`Copied ${fileCount} files from local mayara-gui/ to public/\n`)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function main() {
|
|
194
|
+
console.log('=== MaYaRa SignalK Playback Plugin Build ===\n')
|
|
195
|
+
|
|
196
|
+
// Skip build if public/ already exists with content (installed from --pack tarball)
|
|
197
|
+
// This prevents postinstall from failing when mayara-gui isn't in node_modules
|
|
198
|
+
if (fs.existsSync(publicDest) && !useLocalGui && !createPack) {
|
|
199
|
+
const files = fs.readdirSync(publicDest)
|
|
200
|
+
if (files.length > 0) {
|
|
201
|
+
console.log(`public/ already exists with ${files.length} files (installed from tarball)`)
|
|
202
|
+
console.log('Skipping build.\n')
|
|
203
|
+
console.log('=== Build complete ===')
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (useLocalGui) {
|
|
209
|
+
setupGuiFromLocal()
|
|
210
|
+
} else {
|
|
211
|
+
setupGuiFromNpm()
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Create tarball if --pack flag is set
|
|
215
|
+
if (createPack) {
|
|
216
|
+
console.log('Creating tarball with public/ included...\n')
|
|
217
|
+
|
|
218
|
+
// Temporarily remove public/ from .npmignore
|
|
219
|
+
const npmignorePath = path.join(scriptDir, '.npmignore')
|
|
220
|
+
const npmignoreContent = fs.readFileSync(npmignorePath, 'utf8')
|
|
221
|
+
const npmignoreWithoutPublic = npmignoreContent.replace(/^public\/\n?/m, '')
|
|
222
|
+
fs.writeFileSync(npmignorePath, npmignoreWithoutPublic)
|
|
223
|
+
|
|
224
|
+
// Also temporarily add public/ to files in package.json
|
|
225
|
+
const pkgPath = path.join(scriptDir, 'package.json')
|
|
226
|
+
const pkgContent = fs.readFileSync(pkgPath, 'utf8')
|
|
227
|
+
const pkg = JSON.parse(pkgContent)
|
|
228
|
+
const originalFiles = [...pkg.files]
|
|
229
|
+
pkg.files.push('public/**/*')
|
|
230
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
// Run npm pack
|
|
234
|
+
execSync('npm pack', { stdio: 'inherit', cwd: scriptDir })
|
|
235
|
+
console.log('\nTarball created successfully!')
|
|
236
|
+
} finally {
|
|
237
|
+
// Restore .npmignore
|
|
238
|
+
fs.writeFileSync(npmignorePath, npmignoreContent)
|
|
239
|
+
// Restore package.json
|
|
240
|
+
pkg.files = originalFiles
|
|
241
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
console.log('\n=== Build complete ===')
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
main()
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@marineyachtradar/signalk-playback-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MaYaRa Radar Playback - Play .mrr radar recordings through SignalK Radar API (Developer Tool)",
|
|
5
|
+
"main": "plugin/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "node build.js",
|
|
8
|
+
"postinstall": "node build.js",
|
|
9
|
+
"test": "echo \"No tests yet\" && exit 0"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"signalk-node-server-plugin",
|
|
13
|
+
"signalk-webapp",
|
|
14
|
+
"signalk-category-instruments",
|
|
15
|
+
"radar",
|
|
16
|
+
"marine",
|
|
17
|
+
"mayara",
|
|
18
|
+
"playback",
|
|
19
|
+
"recording"
|
|
20
|
+
],
|
|
21
|
+
"signalk": {
|
|
22
|
+
"displayName": "MaYaRa Radar Playback",
|
|
23
|
+
"appIcon": "assets/MaYaRa_RED.png",
|
|
24
|
+
"webapp": {
|
|
25
|
+
"name": "MaYaRa Radar Playback",
|
|
26
|
+
"description": "Play .mrr radar recordings for testing SignalK Radar API consumers",
|
|
27
|
+
"location": "/plugins/@marineyachtradar/signalk-playback-plugin/"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"plugin/**/*",
|
|
32
|
+
"build.js"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"signalk": ">=2.0.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@marineyachtradar/mayara-gui": "^0.6.0"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/MarineYachtRadar/mayara-server-signalk-playbackrecordings-plugin"
|
|
43
|
+
},
|
|
44
|
+
"author": "MarineYachtRadar Contributors",
|
|
45
|
+
"license": "Apache-2.0"
|
|
46
|
+
}
|