stagelinq 1.0.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/.gitattributes +2 -0
- package/.prettierignore +7 -0
- package/.prettierrc.js +10 -0
- package/.vscode/launch.json +40 -0
- package/.vscode/tasks.json +24 -0
- package/Databases/Databases.ts +69 -0
- package/Databases/DbConnection.ts +42 -0
- package/Databases/index.ts +2 -0
- package/LICENSE +674 -0
- package/LogEmitter/index.ts +51 -0
- package/README.md +83 -0
- package/StageLinq/index.ts +58 -0
- package/TODO.md +5 -0
- package/albumArt/index.ts +2 -0
- package/albumArt/maybeDownloadFiles.ts +34 -0
- package/cli/index.ts +142 -0
- package/devices/Player.ts +182 -0
- package/devices/PlayerMessageQueue.ts +62 -0
- package/index.ts +5 -0
- package/network/NetworkDevice.ts +287 -0
- package/network/StageLinqDevices.ts +215 -0
- package/network/StageLinqListener.ts +50 -0
- package/network/announce.ts +133 -0
- package/network/index.ts +4 -0
- package/package.json +31 -0
- package/services/FileTransfer.ts +298 -0
- package/services/Service.ts +144 -0
- package/services/StateMap.ts +170 -0
- package/services/index.ts +3 -0
- package/stagelinq.code-workspace +16 -0
- package/tsconfig.json +13 -0
- package/types/common.ts +240 -0
- package/types/database.ts +50 -0
- package/types/index.ts +53 -0
- package/types/player.ts +41 -0
- package/types/tokens.ts +39 -0
- package/utils/Context.ts +45 -0
- package/utils/ReadContext.ts +114 -0
- package/utils/WriteContext.ts +105 -0
- package/utils/getTempFilePath.ts +23 -0
- package/utils/hex.ts +62 -0
- package/utils/index.ts +6 -0
- package/utils/log.ts +0 -0
- package/utils/sleep.ts +3 -0
- package/utils/tcp.ts +17 -0
package/.gitattributes
ADDED
package/.prettierignore
ADDED
package/.prettierrc.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"type": "node",
|
|
9
|
+
"request": "launch",
|
|
10
|
+
"name": "Launch JS",
|
|
11
|
+
"program": "${workspaceFolder}/dist/cli.js",
|
|
12
|
+
"internalConsoleOptions": "openOnSessionStart",
|
|
13
|
+
"sourceMaps": true,
|
|
14
|
+
"smartStep": true,
|
|
15
|
+
"outputCapture": "std",
|
|
16
|
+
"skipFiles": [
|
|
17
|
+
"${workspaceFolder}/node_modules/**/*.js",
|
|
18
|
+
"${workspaceFolder}/lib/**/*.js",
|
|
19
|
+
"<node_internals>/**/*.js"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"type": "node",
|
|
24
|
+
"request": "launch",
|
|
25
|
+
"name": "Launch TS",
|
|
26
|
+
"program": "${workspaceFolder}/cli/index.ts",
|
|
27
|
+
"preLaunchTask": "tsc: build - tsconfig.json",
|
|
28
|
+
"internalConsoleOptions": "openOnSessionStart",
|
|
29
|
+
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
|
30
|
+
"sourceMaps": true,
|
|
31
|
+
"smartStep": true,
|
|
32
|
+
"outputCapture": "std",
|
|
33
|
+
"skipFiles": [
|
|
34
|
+
"${workspaceFolder}/node_modules/**/*.js",
|
|
35
|
+
"${workspaceFolder}/lib/**/*.js",
|
|
36
|
+
"<node_internals>/**/*.js"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "2.0.0",
|
|
3
|
+
"tasks": [
|
|
4
|
+
{
|
|
5
|
+
"type": "typescript",
|
|
6
|
+
"tsconfig": "tsconfig.json",
|
|
7
|
+
"option": "watch",
|
|
8
|
+
"presentation": {
|
|
9
|
+
"echo": true,
|
|
10
|
+
"reveal": "silent",
|
|
11
|
+
"focus": false,
|
|
12
|
+
"panel": "shared"
|
|
13
|
+
},
|
|
14
|
+
"isBackground": true,
|
|
15
|
+
"runOptions": { "runOn": "folderOpen" },
|
|
16
|
+
"problemMatcher": ["$tsc-watch"],
|
|
17
|
+
"group": {
|
|
18
|
+
"kind": "build",
|
|
19
|
+
"isDefault": true
|
|
20
|
+
},
|
|
21
|
+
"label": "tsc: watch - tsconfig.json"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { EventEmitter } from 'stream';
|
|
2
|
+
import { FileTransfer } from '../services';
|
|
3
|
+
import { getTempFilePath } from '../albumArt';
|
|
4
|
+
import { NetworkDevice } from '../network';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import { Logger } from '../LogEmitter';
|
|
7
|
+
import { ConnectionInfo, Source } from '../types';
|
|
8
|
+
|
|
9
|
+
export declare interface Databases {
|
|
10
|
+
on(event: 'dbDownloaded', listener: (sourceName: string, dbPath: string) => void): this;
|
|
11
|
+
on(event: 'dbDownloading', listener: (sourceName: string, dbPath: string) => void): this;
|
|
12
|
+
on(event: 'dbProgress', listener: (sourceName: string, total: number, bytesDownloaded: number, percentComplete: number) => void): this;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class Databases extends EventEmitter {
|
|
16
|
+
|
|
17
|
+
sources: Map<string, string> = new Map();
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async downloadSourcesFromDevice(connectionInfo: ConnectionInfo, networkDevice: NetworkDevice) {
|
|
24
|
+
const service = await networkDevice.connectToService(FileTransfer);
|
|
25
|
+
const sources = await service.getSources();
|
|
26
|
+
const output: string[] = [];
|
|
27
|
+
for (const source of sources) {
|
|
28
|
+
const dbConnectionName = `${connectionInfo.address}_${connectionInfo.port}_${source.name}`;
|
|
29
|
+
if (this.sources.has(dbConnectionName)) {
|
|
30
|
+
Logger.debug(`Already seen ${source} on ${connectionInfo.address}:${connectionInfo.port}`);
|
|
31
|
+
} else {
|
|
32
|
+
await this.downloadDb(dbConnectionName, service, source);
|
|
33
|
+
output.push(dbConnectionName);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return output;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Download databases from this network source.
|
|
41
|
+
*/
|
|
42
|
+
async downloadDb(sourceId: string, service: FileTransfer, source: Source) {
|
|
43
|
+
const dbPath = getTempFilePath(`${sourceId}/m.db`);
|
|
44
|
+
|
|
45
|
+
// Read database from source
|
|
46
|
+
Logger.debug(`Reading database ${sourceId}`);
|
|
47
|
+
this.emit('dbDownloading', sourceId, dbPath);
|
|
48
|
+
|
|
49
|
+
service.on('fileTransferProgress', (progress) => {
|
|
50
|
+
this.emit('dbProgress', sourceId, progress.total, progress.bytesDownloaded, progress.percentComplete);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Save database to a file
|
|
54
|
+
const file = await service.getFile(source.database.location);
|
|
55
|
+
Logger.debug(`Saving ${sourceId} to ${dbPath}`);
|
|
56
|
+
fs.writeFileSync(dbPath, Buffer.from(file));
|
|
57
|
+
this.sources.set(sourceId, dbPath);
|
|
58
|
+
|
|
59
|
+
Logger.debug(`Downloaded ${sourceId} to ${dbPath}`);
|
|
60
|
+
this.emit('dbDownloaded', sourceId, dbPath);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getDbPath(dbSourceName: string) {
|
|
64
|
+
if (!this.sources.has(dbSourceName))
|
|
65
|
+
throw new Error(`Database name ${dbSourceName} does not exist`);
|
|
66
|
+
return this.sources.get(dbSourceName);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Database = require('better-sqlite3');
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export class DbConnection {
|
|
5
|
+
|
|
6
|
+
private db: Database.Database;
|
|
7
|
+
private dbPath: string;
|
|
8
|
+
|
|
9
|
+
constructor(dbPath: string) {
|
|
10
|
+
this.dbPath = dbPath;
|
|
11
|
+
console.debug(`Opening ${this.dbPath}`);
|
|
12
|
+
this.db = new Database(this.dbPath);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Execute a SQL query.
|
|
17
|
+
*
|
|
18
|
+
* @param query SQL query to execute
|
|
19
|
+
* @param params Parameters for BetterSqlite3 result.all.
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
22
|
+
querySource<T>(query: string, ...params: any[]): T[] {
|
|
23
|
+
console.debug(`Querying ${this.dbPath}: `);
|
|
24
|
+
const result = this.db.prepare(query);
|
|
25
|
+
return result.all(params);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Return track's DB entry.
|
|
30
|
+
*
|
|
31
|
+
* @param trackPath Path of track on the source's filesystem.
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
getTrackInfo(trackPath: string) {
|
|
35
|
+
return this.querySource(`SELECT * FROM Track WHERE path = '${trackPath}'`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
close() {
|
|
39
|
+
console.debug(`Closing ${this.dbPath}`);
|
|
40
|
+
this.db.close();
|
|
41
|
+
}
|
|
42
|
+
}
|