stagelinq 1.0.4 → 1.0.7
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/Databases/Databases.ts +4 -1
- package/Databases/DbConnection.ts +7 -3
- package/cli/index.ts +67 -39
- package/devices/Player.ts +22 -3
- package/devices/PlayerMessageQueue.ts +2 -1
- package/network/NetworkDevice.ts +19 -4
- package/network/StageLinqDevices.ts +65 -22
- package/package.json +1 -1
- package/types/index.ts +1 -1
- package/types/{database.ts → models/Track.ts} +0 -0
- package/types/models/index.ts +1 -0
- package/utils/index.ts +1 -0
- package/albumArt/index.ts +0 -2
- package/albumArt/maybeDownloadFiles.ts +0 -34
package/Databases/Databases.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConnectionInfo, Source } from '../types';
|
|
2
2
|
import { EventEmitter } from 'stream';
|
|
3
3
|
import { FileTransfer } from '../services';
|
|
4
|
-
import { getTempFilePath } from '../
|
|
4
|
+
import { getTempFilePath } from '../utils';
|
|
5
5
|
import { Logger } from '../LogEmitter';
|
|
6
6
|
import { NetworkDevice } from '../network';
|
|
7
7
|
import * as fs from 'fs';
|
|
@@ -64,6 +64,9 @@ export class Databases extends EventEmitter {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
getDbPath(dbSourceName?: string) {
|
|
67
|
+
if (!this.sources.size)
|
|
68
|
+
throw new Error(`No data sources have been downloaded`);
|
|
69
|
+
|
|
67
70
|
if (!dbSourceName || !this.sources.has(dbSourceName)) {
|
|
68
71
|
|
|
69
72
|
// Hack: Denon will save metadata on streaming files but only on an
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Database = require('better-sqlite3');
|
|
2
|
+
import { Track } from '../types';
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
export class DbConnection {
|
|
@@ -31,12 +32,15 @@ export class DbConnection {
|
|
|
31
32
|
* @param trackPath Path of track on the source's filesystem.
|
|
32
33
|
* @returns
|
|
33
34
|
*/
|
|
34
|
-
getTrackInfo(trackPath: string) {
|
|
35
|
+
getTrackInfo(trackPath: string): Track {
|
|
36
|
+
let result: Track[];
|
|
35
37
|
if (/streaming:\/\//.test(trackPath)) {
|
|
36
|
-
|
|
38
|
+
result = this.querySource('SELECT * FROM Track WHERE uri = (?) LIMIT 1', trackPath);
|
|
37
39
|
} else {
|
|
38
|
-
|
|
40
|
+
result = this.querySource('SELECT * FROM Track WHERE path = (?) LIMIT 1', trackPath);
|
|
39
41
|
}
|
|
42
|
+
if (!result) throw new Error(`Could not find track: ${trackPath} in database.`);
|
|
43
|
+
return result[0];
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
close() {
|
package/cli/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActingAsDevice } from '../types';
|
|
1
|
+
import { ActingAsDevice, PlayerStatus } from '../types';
|
|
2
2
|
import { DbConnection } from "../Databases";
|
|
3
3
|
import { sleep } from '../utils/sleep';
|
|
4
4
|
import { StageLinq } from '../StageLinq';
|
|
@@ -10,7 +10,46 @@ require('console-stamp')(console, {
|
|
|
10
10
|
format: ':date(HH:MM:ss) :label',
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Get track information for latest playing song.
|
|
15
|
+
*
|
|
16
|
+
* @param stageLinq Instance of StageLinq.
|
|
17
|
+
* @param status Player to get track info from.
|
|
18
|
+
* @returns Track info
|
|
19
|
+
*/
|
|
20
|
+
function getTrackInfo(stageLinq: StageLinq, status: PlayerStatus) {
|
|
21
|
+
try {
|
|
22
|
+
const dbPath = stageLinq.databases.getDbPath(status.dbSourceName)
|
|
23
|
+
const connection = new DbConnection(dbPath);
|
|
24
|
+
const result = connection.getTrackInfo(status.trackPath);
|
|
25
|
+
connection.close();
|
|
26
|
+
console.log('Database entry:', result);
|
|
27
|
+
return result;
|
|
28
|
+
} catch(e) {
|
|
29
|
+
console.error(e);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Download the currently playing song from the media.
|
|
35
|
+
*
|
|
36
|
+
* @param stageLinq Instance of StageLinq.
|
|
37
|
+
* @param status Player to download the current song from.
|
|
38
|
+
* @param dest Path to save file to.
|
|
39
|
+
*/
|
|
40
|
+
async function downloadFile(stageLinq: StageLinq, status: PlayerStatus, dest: string) {
|
|
41
|
+
try {
|
|
42
|
+
const data = await stageLinq.devices.downloadFile(status.deviceId, status.trackPathAbsolute);
|
|
43
|
+
if (data) {
|
|
44
|
+
fs.writeFileSync(dest, Buffer.from(data));
|
|
45
|
+
console.log(`Downloaded ${status.trackPathAbsolute} to ${dest}`);
|
|
46
|
+
}
|
|
47
|
+
} catch(e) {
|
|
48
|
+
console.error(`Could not download ${status.trackPathAbsolute}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function main() {
|
|
14
53
|
|
|
15
54
|
console.log('Starting CLI');
|
|
16
55
|
|
|
@@ -18,7 +57,7 @@ require('console-stamp')(console, {
|
|
|
18
57
|
|
|
19
58
|
// If set to true, download the source DBs in a temporary location.
|
|
20
59
|
// (default: true)
|
|
21
|
-
downloadDbSources:
|
|
60
|
+
downloadDbSources: false,
|
|
22
61
|
|
|
23
62
|
// Max number of attempts to connect to a StageLinq device.
|
|
24
63
|
// (default: 3)
|
|
@@ -56,20 +95,23 @@ require('console-stamp')(console, {
|
|
|
56
95
|
stageLinq.devices.on('connected', async (connectionInfo) => {
|
|
57
96
|
console.log(`Successfully connected to ${connectionInfo.software.name}`);
|
|
58
97
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
98
|
+
if (stageLinq.options.downloadDbSources) {
|
|
99
|
+
// Fires when the database source starts downloading.
|
|
100
|
+
stageLinq.databases.on('dbDownloading', (sourceName, dbPath) => {
|
|
101
|
+
console.log(`Downloading ${sourceName} to ${dbPath}`);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Fires while the database source is being read
|
|
105
|
+
stageLinq.databases.on('dbProgress', (sourceName, total, bytes, percent) => {
|
|
106
|
+
console.debug(`Reading ${sourceName}: ${bytes}/${total} (${Math.ceil(percent)}%)`);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Fires when the database source has been read and saved to a temporary path.
|
|
110
|
+
stageLinq.databases.on('dbDownloaded', (sourceName, dbPath) => {
|
|
111
|
+
console.log(`Database (${sourceName}) has been downloaded to ${dbPath}`);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
68
114
|
|
|
69
|
-
// Fires when the database source has been read and saved to a temporary path.
|
|
70
|
-
stageLinq.databases.on('dbDownloaded', (sourceName, dbPath) => {
|
|
71
|
-
console.log(`Database (${sourceName}) has been downloaded to ${dbPath}`);
|
|
72
|
-
});
|
|
73
115
|
});
|
|
74
116
|
|
|
75
117
|
// Fires when StageLinq and all devices are ready to use.
|
|
@@ -83,30 +125,11 @@ require('console-stamp')(console, {
|
|
|
83
125
|
// Example of how to connect to the database using this library's
|
|
84
126
|
// implementation of BetterSqlite3 to get additional information.
|
|
85
127
|
if (stageLinq.options.downloadDbSources) {
|
|
86
|
-
|
|
87
|
-
const dbPath = stageLinq.databases.getDbPath(status.dbSourceName)
|
|
88
|
-
const connection = new DbConnection(dbPath);
|
|
89
|
-
const result = connection.getTrackInfo(status.trackPath);
|
|
90
|
-
connection.close();
|
|
91
|
-
console.log('Database entry:', result);
|
|
92
|
-
} catch(e) {
|
|
93
|
-
console.error(e);
|
|
94
|
-
}
|
|
128
|
+
getTrackInfo(stageLinq, status);
|
|
95
129
|
}
|
|
96
130
|
|
|
97
131
|
// Example of how to download the actual track from the media.
|
|
98
|
-
|
|
99
|
-
const tempfile = path.resolve(os.tmpdir(), 'media');
|
|
100
|
-
const data = await stageLinq.devices.downloadFile(status.deviceId, status.trackPathAbsolute);
|
|
101
|
-
if (data) {
|
|
102
|
-
fs.writeFileSync(tempfile, Buffer.from(data));
|
|
103
|
-
console.log(`Downloaded ${status.trackPathAbsolute} to ${tempfile}`);
|
|
104
|
-
}
|
|
105
|
-
} catch(e) {
|
|
106
|
-
console.error(`Could not download ${status.trackPathAbsolute}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
console.log('New track loaded:', status);
|
|
132
|
+
await downloadFile(stageLinq, status, path.resolve(os.tmpdir(), 'media'));
|
|
110
133
|
});
|
|
111
134
|
|
|
112
135
|
// Fires when a track has started playing.
|
|
@@ -125,9 +148,12 @@ require('console-stamp')(console, {
|
|
|
125
148
|
|
|
126
149
|
// Fires when the state of a device has changed.
|
|
127
150
|
stageLinq.devices.on('stateChanged', (status) => {
|
|
128
|
-
console.log(`
|
|
151
|
+
console.log(`Updating state [${status.deck}]`, status)
|
|
129
152
|
});
|
|
130
153
|
|
|
154
|
+
/////////////////////////////////////////////////////////////////////////
|
|
155
|
+
// CLI
|
|
156
|
+
|
|
131
157
|
let returnCode = 0;
|
|
132
158
|
try {
|
|
133
159
|
process.on('SIGINT', async function () {
|
|
@@ -156,4 +182,6 @@ require('console-stamp')(console, {
|
|
|
156
182
|
|
|
157
183
|
await stageLinq.disconnect();
|
|
158
184
|
process.exit(returnCode);
|
|
159
|
-
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
main();
|
package/devices/Player.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
import { PlayerLayerState, PlayerStatus, ServiceMessage } from '../types';
|
|
3
3
|
import { PlayerMessageQueue } from './PlayerMessageQueue';
|
|
4
4
|
import { StateData, StateMap } from '../services';
|
|
5
|
+
import { Logger } from '../LogEmitter';
|
|
5
6
|
|
|
6
7
|
export declare interface Player {
|
|
7
8
|
on(event: 'trackLoaded', listener: (status: PlayerStatus) => void): this;
|
|
@@ -48,6 +49,7 @@ export class Player extends EventEmitter {
|
|
|
48
49
|
private masterTempo: number; // Current master tempo BPM
|
|
49
50
|
private masterStatus: boolean; // If this device has the matser tempo
|
|
50
51
|
private decks: Map<string, PlayerLayerState> = new Map();
|
|
52
|
+
private lastTrackNetworkPath: Map<string, string> = new Map();
|
|
51
53
|
private queue: {[layer: string]: PlayerMessageQueue} = {};
|
|
52
54
|
private deviceId: string;
|
|
53
55
|
|
|
@@ -132,13 +134,30 @@ export class Player extends EventEmitter {
|
|
|
132
134
|
* @param data
|
|
133
135
|
*/
|
|
134
136
|
private handleUpdate(data: PlayerLayerState) {
|
|
137
|
+
Logger.debug(`data: ${JSON.stringify(data, null, 2)}`);
|
|
138
|
+
|
|
135
139
|
const layer = data.layer;
|
|
136
|
-
|
|
140
|
+
|
|
141
|
+
// A new song my be loading onto a layer but not yet fully downloaded.
|
|
142
|
+
// For example streaming a song from Beatport Link.
|
|
143
|
+
let isNewTrack = true;
|
|
144
|
+
const lastTrackNetworkPath = this.lastTrackNetworkPath.get(layer);
|
|
145
|
+
if (lastTrackNetworkPath && data.trackNetworkPath) {
|
|
146
|
+
if (data.trackNetworkPath === lastTrackNetworkPath) {
|
|
147
|
+
isNewTrack = false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
this.lastTrackNetworkPath.set(layer, data.trackNetworkPath);
|
|
151
|
+
|
|
152
|
+
// This will be true once a song has been fully downloaded / loaded.
|
|
153
|
+
const isSongLoaded = data.hasOwnProperty('songLoaded');
|
|
137
154
|
|
|
138
155
|
// If a new song is loaded drop all the previous track data.
|
|
139
|
-
if (
|
|
156
|
+
if (isNewTrack && isSongLoaded) {
|
|
157
|
+
Logger.debug(`Replacing state ${layer}`);
|
|
140
158
|
this.decks.set(layer, data);
|
|
141
159
|
} else {
|
|
160
|
+
Logger.debug(`Updating state ${layer}`);
|
|
142
161
|
this.decks.set(layer, { ...this.decks.get(layer), ...data });
|
|
143
162
|
}
|
|
144
163
|
|
|
@@ -172,7 +191,7 @@ export class Player extends EventEmitter {
|
|
|
172
191
|
}
|
|
173
192
|
|
|
174
193
|
// If a song is loaded and we have a location emit the trackLoaded event.
|
|
175
|
-
if (currentState.trackNetworkPath)
|
|
194
|
+
if (isSongLoaded && currentState.trackNetworkPath)
|
|
176
195
|
this.emit('trackLoaded', currentState);
|
|
177
196
|
|
|
178
197
|
// If the song is actually playing emit the nowPlaying event.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { PlayerLayerState } from '../types';
|
|
2
2
|
|
|
3
3
|
// How long to wait for all the messages to come in before firing the callback.
|
|
4
|
-
|
|
4
|
+
// It seems that anything less than 1 second is too fast.
|
|
5
|
+
export const UPDATE_RATE_MS = 1500;
|
|
5
6
|
|
|
6
7
|
export type DataQueueCallback = (data: PlayerLayerState) => void;
|
|
7
8
|
|
package/network/NetworkDevice.ts
CHANGED
|
@@ -81,13 +81,18 @@ export class NetworkDevice {
|
|
|
81
81
|
const ctx = new ReadContext(p_message.buffer, false);
|
|
82
82
|
while (ctx.isEOF() === false) {
|
|
83
83
|
const id = ctx.readUInt32();
|
|
84
|
-
//
|
|
85
|
-
ctx.seek(16);
|
|
84
|
+
// const deviceToken = ctx.read(16);
|
|
85
|
+
ctx.seek(16);
|
|
86
86
|
switch (id) {
|
|
87
87
|
case MessageId.TimeStamp:
|
|
88
|
-
ctx.seek(16);
|
|
88
|
+
ctx.seek(16);
|
|
89
|
+
// const secondToken = ctx.read(16); // should be 00..
|
|
90
|
+
// we _shouldn't_ be receiving anything but blank tokens in the 2nd field
|
|
91
|
+
// assert(secondToken.every((x) => x === 0));
|
|
92
|
+
|
|
89
93
|
// Time Alive is in nanoseconds; convert back to seconds
|
|
90
94
|
this.timeAlive = Number(ctx.readUInt64() / (1000n * 1000n * 1000n));
|
|
95
|
+
// this.sendTimeStampMsg(deviceToken, Tokens.SoundSwitch);
|
|
91
96
|
break;
|
|
92
97
|
case MessageId.ServicesAnnouncement:
|
|
93
98
|
const service = ctx.readNetworkStringUTF16();
|
|
@@ -99,7 +104,6 @@ export class NetworkDevice {
|
|
|
99
104
|
break;
|
|
100
105
|
default:
|
|
101
106
|
assert.fail(`NetworkDevice Unhandled message id '${id}'`);
|
|
102
|
-
break;
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
}
|
|
@@ -284,4 +288,15 @@ export class NetworkDevice {
|
|
|
284
288
|
}
|
|
285
289
|
});
|
|
286
290
|
}
|
|
291
|
+
|
|
292
|
+
// private async sendTimeStampMsg(deviceToken: Uint8Array, userToken: Uint8Array, timeAlive?: bigint) {
|
|
293
|
+
// const ctx = new WriteContext();
|
|
294
|
+
// ctx.writeUInt32(MessageId.TimeStamp);
|
|
295
|
+
// ctx.write(deviceToken);
|
|
296
|
+
// ctx.write(userToken);
|
|
297
|
+
// const timeAliveNumber:bigint = (!!timeAlive) ? timeAlive : 0n;
|
|
298
|
+
// ctx.writeUInt64(timeAliveNumber);
|
|
299
|
+
// const written = await this.connection.write(ctx.getBuffer());
|
|
300
|
+
// assert(written === ctx.tell());
|
|
301
|
+
// }
|
|
287
302
|
}
|
|
@@ -29,8 +29,6 @@ export declare interface StageLinqDevices {
|
|
|
29
29
|
|
|
30
30
|
//////////////////////////////////////////////////////////////////////////////
|
|
31
31
|
|
|
32
|
-
// TODO: Refactor device, listener, and player into something more nicer.
|
|
33
|
-
|
|
34
32
|
/**
|
|
35
33
|
* Handle connecting and disconnecting from discovered devices on the
|
|
36
34
|
* StageLinq network.
|
|
@@ -95,17 +93,39 @@ export class StageLinqDevices extends EventEmitter {
|
|
|
95
93
|
/**
|
|
96
94
|
* Waits for all devices to be connected with databases downloaded
|
|
97
95
|
* then connects to the StateMap.
|
|
96
|
+
*
|
|
97
|
+
* Explained:
|
|
98
|
+
*
|
|
99
|
+
* Why wait for all devices? Because a race condition exists when using the
|
|
100
|
+
* database methods.
|
|
101
|
+
*
|
|
102
|
+
* If there are two SC6000 players on the network both will be sending
|
|
103
|
+
* broadcast packets and so their StateMap can be initialized at any time
|
|
104
|
+
* in any order.
|
|
105
|
+
*
|
|
106
|
+
* Assume you have player 1 and player 2 linked. Player 2 has a track that
|
|
107
|
+
* is loaded from a USB drive plugged into player 1. Player 2 will be
|
|
108
|
+
* ready before Player 1 because Player 1 will still be downloading a large
|
|
109
|
+
* database. The race condition is if you try to read from the database on
|
|
110
|
+
* the track that is plugged into Player 1 that isn't ready yet.
|
|
111
|
+
*
|
|
112
|
+
* This method prevents that by waiting for both players to connect and
|
|
113
|
+
* have their databases loaded before initializing the StateMap.
|
|
114
|
+
*
|
|
98
115
|
*/
|
|
99
116
|
private waitForAllDevices() {
|
|
100
117
|
Logger.log('Start watching for devices ...');
|
|
101
118
|
this.deviceWatchTimeout = setInterval(async () => {
|
|
102
119
|
// Check if any devices are still connecting.
|
|
103
120
|
const values = Array.from(this.discoveryStatus.values());
|
|
104
|
-
const foundDevices = values.length
|
|
121
|
+
const foundDevices = values.length >= 1;
|
|
105
122
|
const allConnected = !values.includes(ConnectionStatus.CONNECTING);
|
|
123
|
+
const entries = Array.from(this.discoveryStatus.entries());
|
|
124
|
+
Logger.debug(`Waiting devices: ${JSON.stringify(entries)}`);
|
|
106
125
|
|
|
107
126
|
if (foundDevices && allConnected) {
|
|
108
127
|
Logger.log('All devices found!');
|
|
128
|
+
Logger.debug(`Devices found: ${values.length} ${JSON.stringify(entries)}`);
|
|
109
129
|
clearInterval(this.deviceWatchTimeout);
|
|
110
130
|
for (const cb of this.stateMapCallback) {
|
|
111
131
|
this.setupStateMap(cb.connectionInfo, cb.networkDevice);
|
|
@@ -124,15 +144,42 @@ export class StageLinqDevices extends EventEmitter {
|
|
|
124
144
|
* @returns
|
|
125
145
|
*/
|
|
126
146
|
private async connectToDevice(connectionInfo: ConnectionInfo) {
|
|
147
|
+
|
|
148
|
+
// Mark this device as connecting.
|
|
127
149
|
this.discoveryStatus.set(this.deviceId(connectionInfo), ConnectionStatus.CONNECTING);
|
|
150
|
+
|
|
128
151
|
let attempt = 1;
|
|
129
152
|
while (attempt < this.options.maxRetries) {
|
|
130
153
|
try {
|
|
154
|
+
|
|
155
|
+
// Connect to the device.
|
|
131
156
|
Logger.info(`Connecting to ${this.deviceId(connectionInfo)}. ` +
|
|
132
157
|
`Attempt ${attempt}/${this.options.maxRetries}`);
|
|
133
|
-
|
|
158
|
+
const networkDevice = new NetworkDevice(connectionInfo);
|
|
159
|
+
await networkDevice.connect();
|
|
160
|
+
|
|
161
|
+
// Setup file transfer service
|
|
162
|
+
await this.setupFileTransferService(networkDevice, connectionInfo);
|
|
163
|
+
|
|
164
|
+
// Download the database
|
|
165
|
+
if (this.options.downloadDbSources) {
|
|
166
|
+
await this.downloadDatabase(networkDevice, connectionInfo);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Setup other services that should be initialized before StateMap here.
|
|
170
|
+
|
|
171
|
+
// StateMap will be initialized after all devices have completed
|
|
172
|
+
// this method. In other words, StateMap will initialize
|
|
173
|
+
// after all entries in this.discoveryStatus return
|
|
174
|
+
// ConnectionStatus.CONNECTED
|
|
175
|
+
|
|
176
|
+
// Append to the list of states we need to setup later.
|
|
177
|
+
this.stateMapCallback.push({ connectionInfo, networkDevice });
|
|
178
|
+
|
|
179
|
+
// Mark this device as connected.
|
|
134
180
|
this.discoveryStatus.set(this.deviceId(connectionInfo), ConnectionStatus.CONNECTED);
|
|
135
181
|
this.emit('connected', connectionInfo);
|
|
182
|
+
|
|
136
183
|
return; // Don't forget to return!
|
|
137
184
|
} catch(e) {
|
|
138
185
|
|
|
@@ -148,32 +195,27 @@ export class StageLinqDevices extends EventEmitter {
|
|
|
148
195
|
throw new Error(`Could not connect to ${this.deviceId(connectionInfo)}`);
|
|
149
196
|
}
|
|
150
197
|
|
|
151
|
-
|
|
152
|
-
* Download databases from the device.
|
|
153
|
-
*
|
|
154
|
-
* @param connectionInfo Connection info
|
|
155
|
-
* @returns
|
|
156
|
-
*/
|
|
157
|
-
private async downloadDatabase(connectionInfo: ConnectionInfo) {
|
|
158
|
-
const networkDevice = new NetworkDevice(connectionInfo);
|
|
159
|
-
await networkDevice.connect();
|
|
160
|
-
|
|
198
|
+
private async setupFileTransferService(networkDevice: NetworkDevice, connectionInfo: ConnectionInfo) {
|
|
161
199
|
const sourceId = this.sourceId(connectionInfo);
|
|
162
|
-
Logger.info(`
|
|
200
|
+
Logger.info(`Starting file transfer for ${this.deviceId(connectionInfo)}`);
|
|
163
201
|
const fileTransfer = await networkDevice.connectToService(FileTransfer);
|
|
164
202
|
|
|
165
203
|
this.devices.set(`net://${sourceId}`, {
|
|
166
204
|
networkDevice: networkDevice,
|
|
167
205
|
fileTransferService: fileTransfer
|
|
168
206
|
});
|
|
207
|
+
}
|
|
169
208
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Download databases from the device.
|
|
211
|
+
*
|
|
212
|
+
* @param connectionInfo Connection info
|
|
213
|
+
* @returns
|
|
214
|
+
*/
|
|
215
|
+
private async downloadDatabase(networkDevice: NetworkDevice, connectionInfo: ConnectionInfo) {
|
|
216
|
+
const sources = await this.databases.downloadSourcesFromDevice(connectionInfo, networkDevice);
|
|
217
|
+
Logger.debug(`Database sources: ${sources.join(', ')}`);
|
|
218
|
+
Logger.debug(`Database download complete for ${connectionInfo.source}`);
|
|
177
219
|
}
|
|
178
220
|
|
|
179
221
|
private sourceId(connectionInfo: ConnectionInfo) {
|
|
@@ -183,6 +225,7 @@ export class StageLinqDevices extends EventEmitter {
|
|
|
183
225
|
|
|
184
226
|
/**
|
|
185
227
|
* Setup stateMap.
|
|
228
|
+
*
|
|
186
229
|
* @param connectionInfo Connection info
|
|
187
230
|
* @param networkDevice Network device
|
|
188
231
|
*/
|
package/package.json
CHANGED
package/types/index.ts
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './track';
|
package/utils/index.ts
CHANGED
package/albumArt/index.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { NetworkDevice } from '../network';
|
|
2
|
-
import { FileTransfer } from '../services';
|
|
3
|
-
import { getTempFilePath } from "../utils/getTempFilePath";
|
|
4
|
-
import { strict as assert } from 'assert';
|
|
5
|
-
import * as fs from 'fs';
|
|
6
|
-
import minimist = require('minimist');
|
|
7
|
-
import { Logger } from '../LogEmitter';
|
|
8
|
-
|
|
9
|
-
export async function maybeDownloadFiles(controller: NetworkDevice) {
|
|
10
|
-
const args = minimist(process.argv.slice(2));
|
|
11
|
-
if (!args.disableFileTransfer) {
|
|
12
|
-
const ftx = await controller.connectToService(FileTransfer);
|
|
13
|
-
assert(ftx);
|
|
14
|
-
const sources = await ftx.getSources();
|
|
15
|
-
{
|
|
16
|
-
const sync = !args.skipsync;
|
|
17
|
-
for (const source of sources) {
|
|
18
|
-
const dbPath = getTempFilePath(source.database.location);
|
|
19
|
-
// FIXME: Move all this away from main
|
|
20
|
-
if (sync) {
|
|
21
|
-
const file = await ftx.getFile(source.database.location);
|
|
22
|
-
fs.writeFileSync(dbPath, file);
|
|
23
|
-
Logger.info(`downloaded: '${source.database.location}' and stored in '${dbPath}'`);
|
|
24
|
-
}
|
|
25
|
-
await controller.addSource(source.name, dbPath, getTempFilePath(`${source.name}/Album Art/`));
|
|
26
|
-
|
|
27
|
-
if (sync) {
|
|
28
|
-
await controller.dumpAlbumArt(source.name);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
ftx.disconnect();
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|