@amoshydra/davison 0.0.4 → 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/README.md +29 -20
- package/dist-server/config.js +2 -0
- package/dist-server/index.js +4 -1
- package/dist-server/services/webdav.js +17 -4
- package/package.json +3 -3
- package/vite.config.ts +9 -0
package/README.md
CHANGED
|
@@ -74,13 +74,22 @@ services:
|
|
|
74
74
|
|
|
75
75
|
### WebDAV
|
|
76
76
|
|
|
77
|
-
The WebDAV server is available at `/webdav` (e.g., `http
|
|
77
|
+
The WebDAV server is available at `/webdav` (e.g., `http://<your-server-ip>:4534/webdav/`). It mirrors your music folder structure.
|
|
78
|
+
|
|
79
|
+
#### Authentication
|
|
80
|
+
|
|
81
|
+
Disabled by default. To require Basic authentication, set the `DAVISON_WEBDAV_USER` and `DAVISON_WEBDAV_PASS` environment variables:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
DAVISON_WEBDAV_USER=davison DAVISON_WEBDAV_PASS="your-password" npx davison --path /music
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Environment variables are recommended over CLI flags because they do not appear in process listings (`ps aux`) or shell history. When authentication is enabled, the server logs `WebDAV auth enabled for user "<username>"` on startup.
|
|
78
88
|
|
|
79
89
|
To use with Music Assistant:
|
|
80
90
|
1. Add a **WebDAV** provider
|
|
81
91
|
2. URL: `http://<your-server-ip>:4534/webdav/`
|
|
82
|
-
3.
|
|
83
|
-
4. Content type: `music`
|
|
92
|
+
3. Username/Password: set them if you configured auth, leave blank otherwise
|
|
84
93
|
|
|
85
94
|
### Sonos
|
|
86
95
|
|
|
@@ -101,30 +110,30 @@ The dev server hot-reloads on file changes.
|
|
|
101
110
|
|
|
102
111
|
```
|
|
103
112
|
┌──────────────────────┐
|
|
104
|
-
│ Web Browser
|
|
105
|
-
│ (React + Vite)
|
|
113
|
+
│ Web Browser │
|
|
114
|
+
│ (React + Vite) │
|
|
106
115
|
└──────────┬───────────┘
|
|
107
116
|
│ HTTP (port 4534)
|
|
108
117
|
┌──────────▼───────────┐
|
|
109
|
-
│ Express Server
|
|
110
|
-
│ ┌─────────────────┐
|
|
111
|
-
│ │ REST API (/api) │
|
|
112
|
-
│ │ Queue Manager │
|
|
113
|
-
│ │ Sonos Controller│
|
|
114
|
-
│ │ Playlist Store │
|
|
115
|
-
│ ├─────────────────┤
|
|
116
|
-
│ │ WebDAV (/webdav)│
|
|
117
|
-
│ │ (Nephele VFS) │
|
|
118
|
-
│ └─────────────────┘
|
|
118
|
+
│ Express Server │
|
|
119
|
+
│ ┌─────────────────┐ │
|
|
120
|
+
│ │ REST API (/api) │ │
|
|
121
|
+
│ │ Queue Manager │ │
|
|
122
|
+
│ │ Sonos Controller│ │
|
|
123
|
+
│ │ Playlist Store │ │
|
|
124
|
+
│ ├─────────────────┤ │
|
|
125
|
+
│ │ WebDAV (/webdav)│ │
|
|
126
|
+
│ │ (Nephele VFS) │ │
|
|
127
|
+
│ └─────────────────┘ │
|
|
119
128
|
└──────────┬───────────┘
|
|
120
129
|
│
|
|
121
130
|
┌───────────────────┼───────────────────┐
|
|
122
131
|
│ │ │
|
|
123
|
-
┌──────▼──────┐
|
|
124
|
-
│
|
|
125
|
-
│
|
|
126
|
-
│
|
|
127
|
-
└─────────────┘
|
|
132
|
+
┌──────▼──────┐ ┌──────▼──────┐ ┌───────▼──────┐
|
|
133
|
+
│ Sonos │ │ Music Files │ │ Music │
|
|
134
|
+
│ Speakers │ │ (on disk) │ │ Assistant │
|
|
135
|
+
│ (UPnP/HTTP) │ │ │ │ (via WebDAV) │
|
|
136
|
+
└─────────────┘ └─────────────┘ └──────────────┘
|
|
128
137
|
```
|
|
129
138
|
|
|
130
139
|
## License
|
package/dist-server/config.js
CHANGED
|
@@ -19,6 +19,8 @@ export const config = {
|
|
|
19
19
|
port: 4534,
|
|
20
20
|
host: detectLanIp(),
|
|
21
21
|
musicPaths: [],
|
|
22
|
+
webdavUser: '',
|
|
23
|
+
webdavPass: '',
|
|
22
24
|
dataDir: path.resolve(import.meta.dirname, '..', 'data'),
|
|
23
25
|
playlistsFile: path.resolve(import.meta.dirname, '..', 'data', 'playlists.json'),
|
|
24
26
|
};
|
package/dist-server/index.js
CHANGED
|
@@ -18,10 +18,13 @@ program
|
|
|
18
18
|
.option('--host <address>', 'Server LAN address (auto-detected if omitted)')
|
|
19
19
|
.parse(process.argv);
|
|
20
20
|
const options = program.opts();
|
|
21
|
-
config.port = parseInt(options.port, 10) ||
|
|
21
|
+
config.port = parseInt(options.port, 10) || 4534;
|
|
22
22
|
if (options.host)
|
|
23
23
|
config.host = options.host;
|
|
24
24
|
config.musicPaths = options.path || [];
|
|
25
|
+
// WebDAV credentials from environment (not CLI — avoids ps leak)
|
|
26
|
+
config.webdavUser = process.env.DAVISON_WEBDAV_USER || '';
|
|
27
|
+
config.webdavPass = process.env.DAVISON_WEBDAV_PASS || '';
|
|
25
28
|
// Resolve relative paths against original cwd before main() may chdir
|
|
26
29
|
const originalCwd = process.cwd();
|
|
27
30
|
config.musicPaths = config.musicPaths.map((p) => isAbsolute(p) ? p : resolve(originalCwd, p));
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import createServer from 'nephele';
|
|
2
|
-
import { ResourceNotFoundError, BadGatewayError, ForbiddenError } from 'nephele/dist/Errors/index.js';
|
|
2
|
+
import { ResourceNotFoundError, BadGatewayError, ForbiddenError, UnauthorizedError } from 'nephele/dist/Errors/index.js';
|
|
3
3
|
import { createReadStream } from 'node:fs';
|
|
4
4
|
import { stat } from 'node:fs/promises';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { getMusicLibrary } from './music-discovery.js';
|
|
7
|
+
import { config } from '../config.js';
|
|
7
8
|
import os from 'node:os';
|
|
8
9
|
import mime from 'mime';
|
|
9
10
|
function buildDirs(tracks) {
|
|
@@ -369,13 +370,25 @@ export function initWebdav() {
|
|
|
369
370
|
const tracks = getMusicLibrary();
|
|
370
371
|
const tree = buildDirs(tracks);
|
|
371
372
|
const adapter = new VirtualAdapter(tree);
|
|
372
|
-
|
|
373
|
-
|
|
373
|
+
if (config.webdavUser) {
|
|
374
|
+
console.log(`WebDAV auth enabled for user "${config.webdavUser}"`);
|
|
375
|
+
}
|
|
376
|
+
class WebdavAuth {
|
|
377
|
+
async authenticate(request) {
|
|
378
|
+
if (config.webdavUser) {
|
|
379
|
+
const auth = request.headers.authorization || '';
|
|
380
|
+
const expected = 'Basic ' + Buffer.from(`${config.webdavUser}:${config.webdavPass}`).toString('base64');
|
|
381
|
+
if (auth !== expected) {
|
|
382
|
+
throw new UnauthorizedError();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return { username: config.webdavUser || 'davison' };
|
|
386
|
+
}
|
|
374
387
|
async cleanAuthentication() { }
|
|
375
388
|
}
|
|
376
389
|
_webdavApp = createServer({
|
|
377
390
|
adapter: adapter,
|
|
378
|
-
authenticator: new
|
|
391
|
+
authenticator: new WebdavAuth(),
|
|
379
392
|
});
|
|
380
393
|
return _webdavApp;
|
|
381
394
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amoshydra/davison",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "WebDAV music server + Sonos controller. npx @amoshydra/davison --path /music",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"patches/",
|
|
24
24
|
"package.json",
|
|
25
25
|
"README.md",
|
|
26
|
-
"LICENSE"
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"vite.config.ts"
|
|
27
28
|
],
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"commander": "^12.1.0",
|
|
@@ -32,7 +33,6 @@
|
|
|
32
33
|
"music-metadata": "^10.6.0",
|
|
33
34
|
"nephele": "1.0.0-alpha.67",
|
|
34
35
|
"sonos": "^1.14.3",
|
|
35
|
-
"uuid": "^10.0.0",
|
|
36
36
|
"vite-express": "^0.22.1"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|