alphatheta-connect 0.25.0 → 0.25.2
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/lib/cli.js +175 -60
- package/lib/cli.js.map +1 -1
- package/lib/db/getMetadata.d.ts +13 -0
- package/lib/index.js +175 -60
- package/lib/index.js.map +1 -1
- package/lib/localdb/index.d.ts +47 -1
- package/lib/remotedb/fields.d.ts +6 -6
- package/package.json +1 -1
package/lib/db/getMetadata.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Track } from "../entities";
|
|
2
2
|
import LocalDatabase from "../localdb";
|
|
3
|
+
import { DatabaseType } from "../localdb/database-adapter";
|
|
3
4
|
import RemoteDatabase from "../remotedb";
|
|
4
5
|
import { Device, DeviceID, MediaSlot, TrackType } from "../types";
|
|
5
6
|
import { TelemetrySpan as Span } from "../utils/telemetry";
|
|
@@ -20,6 +21,12 @@ export interface Options {
|
|
|
20
21
|
* The track id to retrieve metadata for
|
|
21
22
|
*/
|
|
22
23
|
trackId: number;
|
|
24
|
+
/**
|
|
25
|
+
* The track's BPM as the player reports it in its status packet, when known.
|
|
26
|
+
* Used to check that the local database row for `trackId` is really the
|
|
27
|
+
* track the player is showing (see {@link LocalDatabase.findTrack}).
|
|
28
|
+
*/
|
|
29
|
+
trackBPM?: number | null;
|
|
23
30
|
/**
|
|
24
31
|
* The Sentry transaction span
|
|
25
32
|
*/
|
|
@@ -43,9 +50,15 @@ export type LocalMiss =
|
|
|
43
50
|
export type LocalResult = {
|
|
44
51
|
track: Track;
|
|
45
52
|
miss: null;
|
|
53
|
+
/**
|
|
54
|
+
* Set when the slot had to switch to its other database format to
|
|
55
|
+
* answer: the format it is now served from.
|
|
56
|
+
*/
|
|
57
|
+
switchedTo: DatabaseType | null;
|
|
46
58
|
} | {
|
|
47
59
|
track: null;
|
|
48
60
|
miss: LocalMiss;
|
|
61
|
+
switchedTo: null;
|
|
49
62
|
};
|
|
50
63
|
export declare function viaRemote(remote: RemoteDatabase, opts: Required<Options>): Promise<Track<import("../entities").EntityFK.WithRelations> | null>;
|
|
51
64
|
export declare function viaLocal(local: LocalDatabase, device: Device, opts: Required<Options>): Promise<LocalResult>;
|
package/lib/index.js
CHANGED
|
@@ -1268,25 +1268,24 @@ async function viaRemote(remote, opts) {
|
|
|
1268
1268
|
return track;
|
|
1269
1269
|
}
|
|
1270
1270
|
async function viaLocal(local, device, opts) {
|
|
1271
|
-
const { deviceId, trackSlot, trackId } = opts;
|
|
1271
|
+
const { deviceId, trackSlot, trackId, trackBPM } = opts;
|
|
1272
1272
|
if (trackSlot !== types_1.MediaSlot.USB && trackSlot !== types_1.MediaSlot.SD) {
|
|
1273
1273
|
throw new Error('Expected USB or SD slot for local database query');
|
|
1274
1274
|
}
|
|
1275
|
-
const
|
|
1276
|
-
if (adapter === null) {
|
|
1277
|
-
return { track: null, miss: 'no-database' };
|
|
1275
|
+
const lookup = await local.findTrack(deviceId, trackSlot, trackId, { trackBPM });
|
|
1276
|
+
if (lookup.adapter === null) {
|
|
1277
|
+
return { track: null, miss: 'no-database', switchedTo: null };
|
|
1278
1278
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
return { track: null, miss: 'track-absent' };
|
|
1279
|
+
if (lookup.track === null) {
|
|
1280
|
+
return { track: null, miss: 'track-absent', switchedTo: null };
|
|
1282
1281
|
}
|
|
1283
|
-
const anlz = await (0, rekordbox_1.loadAnlz)(
|
|
1282
|
+
const anlz = await (0, rekordbox_1.loadAnlz)(lookup.track, 'DAT', (0, utils_1.anlzLoader)({ device, slot: trackSlot }));
|
|
1284
1283
|
const track = {
|
|
1285
|
-
...
|
|
1284
|
+
...lookup.track,
|
|
1286
1285
|
beatGrid: anlz.beatGrid,
|
|
1287
1286
|
waveformHd: null,
|
|
1288
1287
|
};
|
|
1289
|
-
return { track, miss: null };
|
|
1288
|
+
return { track, miss: null, switchedTo: lookup.switchedTo };
|
|
1290
1289
|
}
|
|
1291
1290
|
|
|
1292
1291
|
|
|
@@ -1610,6 +1609,7 @@ class Database {
|
|
|
1610
1609
|
* Retrieve metadata for a track on a specific device slot.
|
|
1611
1610
|
*/
|
|
1612
1611
|
async getMetadata(opts) {
|
|
1612
|
+
var _a;
|
|
1613
1613
|
const { deviceId, trackType, trackSlot, span } = opts;
|
|
1614
1614
|
const tx = span
|
|
1615
1615
|
? span.startChild({ op: 'dbGetMetadata' })
|
|
@@ -1617,7 +1617,7 @@ class Database {
|
|
|
1617
1617
|
tx.setTag('deviceId', deviceId.toString());
|
|
1618
1618
|
tx.setTag('trackType', (0, utils_1.getTrackTypeName)(trackType));
|
|
1619
1619
|
tx.setTag('trackSlot', (0, utils_1.getSlotName)(trackSlot));
|
|
1620
|
-
const callOpts = { ...opts, span: tx };
|
|
1620
|
+
const callOpts = { ...opts, trackBPM: (_a = opts.trackBPM) !== null && _a !== void 0 ? _a : null, span: tx };
|
|
1621
1621
|
const device = await __classPrivateFieldGet(this, _Database_deviceManager, "f").getDeviceEnsured(deviceId);
|
|
1622
1622
|
if (device === null) {
|
|
1623
1623
|
return null;
|
|
@@ -1630,6 +1630,12 @@ class Database {
|
|
|
1630
1630
|
if (strategy === LookupStrategy.Local) {
|
|
1631
1631
|
const local = await GetMetadata.viaLocal(__classPrivateFieldGet(this, _Database_localDatabase, "f"), device, callOpts);
|
|
1632
1632
|
track = local.track;
|
|
1633
|
+
if (local.switchedTo !== null) {
|
|
1634
|
+
__classPrivateFieldGet(this, _Database_logger, "f").info(`Device ${deviceId} ${(0, utils_1.getSlotName)(trackSlot)} is now read from the ` +
|
|
1635
|
+
`${local.switchedTo === 'pdb' ? 'legacy PDB' : 'OneLibrary'} database: ` +
|
|
1636
|
+
`it is the one that holds track ${opts.trackId} as the player reports it ` +
|
|
1637
|
+
`(NP3-399)`);
|
|
1638
|
+
}
|
|
1633
1639
|
// A local miss used to end the lookup, so the DJ's track silently never
|
|
1634
1640
|
// reached the overlay for the rest of the set (NP3-361). Say what was
|
|
1635
1641
|
// missed, then give the CDJ's own database a chance to answer.
|
|
@@ -2220,7 +2226,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
2220
2226
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
2221
2227
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
2222
2228
|
};
|
|
2223
|
-
var _LocalDatabase_hostDevice, _LocalDatabase_deviceManager, _LocalDatabase_statusEmitter, _LocalDatabase_emitter, _LocalDatabase_slotLocks, _LocalDatabase_dbs, _LocalDatabase_preference, _LocalDatabase_handleDeviceRemoved, _LocalDatabase_fetchFileWithFallback, _LocalDatabase_tryLoadOneLibrary, _LocalDatabase_loadPdbDatabase, _LocalDatabase_hydrateDatabase;
|
|
2229
|
+
var _LocalDatabase_instances, _LocalDatabase_hostDevice, _LocalDatabase_deviceManager, _LocalDatabase_statusEmitter, _LocalDatabase_emitter, _LocalDatabase_slotLocks, _LocalDatabase_dbs, _LocalDatabase_preference, _LocalDatabase_handleDeviceRemoved, _LocalDatabase_closeLoaded, _LocalDatabase_fetchFileWithFallback, _LocalDatabase_tryLoadOneLibrary, _LocalDatabase_loadPdbDatabase, _LocalDatabase_hydrateDatabase, _LocalDatabase_loadAlternate, _LocalDatabase_getItem;
|
|
2224
2230
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
2225
2231
|
const async_mutex_1 = __webpack_require__(/*! async-mutex */ "async-mutex");
|
|
2226
2232
|
const onelibrary_connect_1 = __webpack_require__(/*! onelibrary-connect */ "onelibrary-connect");
|
|
@@ -2236,6 +2242,18 @@ const utils_1 = __webpack_require__(/*! src/utils */ "./src/utils/index.ts");
|
|
|
2236
2242
|
const Telemetry = __importStar(__webpack_require__(/*! src/utils/telemetry */ "./src/utils/telemetry.ts"));
|
|
2237
2243
|
const orm_1 = __webpack_require__(/*! ./orm */ "./src/localdb/orm.ts");
|
|
2238
2244
|
const rekordbox_1 = __webpack_require__(/*! ./rekordbox */ "./src/localdb/rekordbox.ts");
|
|
2245
|
+
/**
|
|
2246
|
+
* A row is only trusted when the player's reported BPM agrees with it. Either
|
|
2247
|
+
* side missing (unanalysed track, or a player that reports no BPM) is
|
|
2248
|
+
* inconclusive and counts as agreement.
|
|
2249
|
+
*/
|
|
2250
|
+
const trackAgreesWithPlayer = (track, hint) => {
|
|
2251
|
+
const reported = hint.trackBPM;
|
|
2252
|
+
if (reported === null || reported === undefined || !track.tempo) {
|
|
2253
|
+
return true;
|
|
2254
|
+
}
|
|
2255
|
+
return Math.abs(track.tempo - reported) < 0.05;
|
|
2256
|
+
};
|
|
2239
2257
|
/**
|
|
2240
2258
|
* Compute the identifier for media device in a CDJ. This is used to determine
|
|
2241
2259
|
* if we have already hydrated the device or not into our local database.
|
|
@@ -2262,6 +2280,7 @@ const getMediaId = (info) => {
|
|
|
2262
2280
|
*/
|
|
2263
2281
|
class LocalDatabase {
|
|
2264
2282
|
constructor(hostDevice, deviceManager, statusEmitter, preference = 'auto') {
|
|
2283
|
+
_LocalDatabase_instances.add(this);
|
|
2265
2284
|
_LocalDatabase_hostDevice.set(this, void 0);
|
|
2266
2285
|
_LocalDatabase_deviceManager.set(this, void 0);
|
|
2267
2286
|
_LocalDatabase_statusEmitter.set(this, void 0);
|
|
@@ -2293,19 +2312,25 @@ class LocalDatabase {
|
|
|
2293
2312
|
_LocalDatabase_handleDeviceRemoved.set(this, (device) => {
|
|
2294
2313
|
const db = __classPrivateFieldGet(this, _LocalDatabase_dbs, "f").find(db => db.media.deviceId === device.id);
|
|
2295
2314
|
if (db) {
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
try {
|
|
2300
|
-
fs.unlinkSync(db.tempFile);
|
|
2301
|
-
}
|
|
2302
|
-
catch {
|
|
2303
|
-
// Ignore cleanup errors
|
|
2304
|
-
}
|
|
2315
|
+
__classPrivateFieldGet(this, _LocalDatabase_closeLoaded, "f").call(this, db);
|
|
2316
|
+
if (db.alternate) {
|
|
2317
|
+
__classPrivateFieldGet(this, _LocalDatabase_closeLoaded, "f").call(this, db.alternate);
|
|
2305
2318
|
}
|
|
2306
2319
|
}
|
|
2307
2320
|
__classPrivateFieldSet(this, _LocalDatabase_dbs, __classPrivateFieldGet(this, _LocalDatabase_dbs, "f").filter(db => db.media.deviceId !== device.id), "f");
|
|
2308
2321
|
});
|
|
2322
|
+
_LocalDatabase_closeLoaded.set(this, (loaded) => {
|
|
2323
|
+
loaded.adapter.close();
|
|
2324
|
+
// Clean up temp file if it exists (OneLibrary databases)
|
|
2325
|
+
if (loaded.tempFile) {
|
|
2326
|
+
try {
|
|
2327
|
+
fs.unlinkSync(loaded.tempFile);
|
|
2328
|
+
}
|
|
2329
|
+
catch {
|
|
2330
|
+
// Ignore cleanup errors
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2309
2334
|
/**
|
|
2310
2335
|
* Helper to fetch a file from device, trying both dotted and non-dotted paths
|
|
2311
2336
|
*/
|
|
@@ -2412,11 +2437,54 @@ class LocalDatabase {
|
|
|
2412
2437
|
}
|
|
2413
2438
|
}
|
|
2414
2439
|
__classPrivateFieldGet(this, _LocalDatabase_emitter, "f").emit('hydrationDone', { device, slot });
|
|
2415
|
-
const db = {
|
|
2440
|
+
const db = {
|
|
2441
|
+
adapter,
|
|
2442
|
+
media,
|
|
2443
|
+
device,
|
|
2444
|
+
slot,
|
|
2445
|
+
id: getMediaId(media),
|
|
2446
|
+
tempFile,
|
|
2447
|
+
alternateLock: new async_mutex_1.Mutex(),
|
|
2448
|
+
};
|
|
2416
2449
|
__classPrivateFieldGet(this, _LocalDatabase_dbs, "f").push(db);
|
|
2417
2450
|
tx.finish();
|
|
2418
2451
|
return db;
|
|
2419
2452
|
});
|
|
2453
|
+
/**
|
|
2454
|
+
* Loads the database format the slot is *not* currently served from, so a
|
|
2455
|
+
* lookup can be checked against it. Only meaningful under the 'auto'
|
|
2456
|
+
* preference: a forced format has no alternate. The result (or its absence)
|
|
2457
|
+
* is remembered so the media is never downloaded twice.
|
|
2458
|
+
*/
|
|
2459
|
+
_LocalDatabase_loadAlternate.set(this, (db) => db.alternateLock.runExclusive(async () => {
|
|
2460
|
+
if (db.alternate !== undefined) {
|
|
2461
|
+
return db.alternate;
|
|
2462
|
+
}
|
|
2463
|
+
if (__classPrivateFieldGet(this, _LocalDatabase_preference, "f") !== 'auto') {
|
|
2464
|
+
db.alternate = null;
|
|
2465
|
+
return null;
|
|
2466
|
+
}
|
|
2467
|
+
const tx = Telemetry.startTransaction({ name: 'hydrateAlternateDatabase' });
|
|
2468
|
+
tx.setTag('slot', (0, utils_1.getSlotName)(db.media.slot));
|
|
2469
|
+
tx.setTag('activeDbType', db.adapter.type);
|
|
2470
|
+
try {
|
|
2471
|
+
if (db.adapter.type === 'oneLibrary') {
|
|
2472
|
+
const adapter = await __classPrivateFieldGet(this, _LocalDatabase_loadPdbDatabase, "f").call(this, db.device, db.slot, tx);
|
|
2473
|
+
db.alternate = { adapter };
|
|
2474
|
+
tx.setTag('dbType', 'pdb');
|
|
2475
|
+
}
|
|
2476
|
+
else {
|
|
2477
|
+
db.alternate = await __classPrivateFieldGet(this, _LocalDatabase_tryLoadOneLibrary, "f").call(this, db.device, db.slot, tx);
|
|
2478
|
+
tx.setTag('dbType', db.alternate ? 'oneLibrary' : 'none');
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
catch {
|
|
2482
|
+
// The media simply has no such file (or it could not be read).
|
|
2483
|
+
db.alternate = null;
|
|
2484
|
+
}
|
|
2485
|
+
tx.finish();
|
|
2486
|
+
return db.alternate;
|
|
2487
|
+
}));
|
|
2420
2488
|
__classPrivateFieldSet(this, _LocalDatabase_hostDevice, hostDevice, "f");
|
|
2421
2489
|
__classPrivateFieldSet(this, _LocalDatabase_deviceManager, deviceManager, "f");
|
|
2422
2490
|
__classPrivateFieldSet(this, _LocalDatabase_statusEmitter, statusEmitter, "f");
|
|
@@ -2441,6 +2509,45 @@ class LocalDatabase {
|
|
|
2441
2509
|
disconnectForDevice(device) {
|
|
2442
2510
|
__classPrivateFieldGet(this, _LocalDatabase_handleDeviceRemoved, "f").call(this, device);
|
|
2443
2511
|
}
|
|
2512
|
+
/**
|
|
2513
|
+
* Looks a track up in the databases of a device slot, checking the answer
|
|
2514
|
+
* against what the player reports.
|
|
2515
|
+
*
|
|
2516
|
+
* A Device Library Plus export carries both `exportLibrary.db` and the
|
|
2517
|
+
* legacy `export.pdb`, and their track IDs are different number spaces. A
|
|
2518
|
+
* player that reads one while we loaded the other resolves most IDs to a
|
|
2519
|
+
* different track and some to nothing at all (NP3-399). So when the active
|
|
2520
|
+
* database has no such row, or its row's BPM is not the BPM the player is
|
|
2521
|
+
* showing, the other format is loaded and asked. If it agrees with the
|
|
2522
|
+
* player, the slot switches to it for every later lookup — artwork,
|
|
2523
|
+
* analysis and the next track all follow the database the player is using.
|
|
2524
|
+
*
|
|
2525
|
+
* When neither database can be confirmed, the active database's row (if any)
|
|
2526
|
+
* is returned as before.
|
|
2527
|
+
*/
|
|
2528
|
+
async findTrack(deviceId, slot, trackId, hint = {}) {
|
|
2529
|
+
const db = await __classPrivateFieldGet(this, _LocalDatabase_instances, "m", _LocalDatabase_getItem).call(this, deviceId, slot);
|
|
2530
|
+
if (db === null) {
|
|
2531
|
+
return { adapter: null, track: null, switchedTo: null };
|
|
2532
|
+
}
|
|
2533
|
+
const active = db.adapter.findTrack(trackId);
|
|
2534
|
+
if (active !== null && trackAgreesWithPlayer(active, hint)) {
|
|
2535
|
+
return { adapter: db.adapter, track: active, switchedTo: null };
|
|
2536
|
+
}
|
|
2537
|
+
const alternate = await __classPrivateFieldGet(this, _LocalDatabase_loadAlternate, "f").call(this, db);
|
|
2538
|
+
if (alternate !== null) {
|
|
2539
|
+
const other = alternate.adapter.findTrack(trackId);
|
|
2540
|
+
if (other !== null && trackAgreesWithPlayer(other, hint)) {
|
|
2541
|
+
db.alternate = { adapter: db.adapter, tempFile: db.tempFile };
|
|
2542
|
+
db.adapter = alternate.adapter;
|
|
2543
|
+
db.tempFile = alternate.tempFile;
|
|
2544
|
+
return { adapter: db.adapter, track: other, switchedTo: db.adapter.type };
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
return active === null
|
|
2548
|
+
? { adapter: db.adapter, track: null, switchedTo: null }
|
|
2549
|
+
: { adapter: db.adapter, track: active, switchedTo: null };
|
|
2550
|
+
}
|
|
2444
2551
|
/**
|
|
2445
2552
|
* Gets the database adapter for the media metadata in the provided device slot.
|
|
2446
2553
|
*
|
|
@@ -2451,43 +2558,8 @@ class LocalDatabase {
|
|
|
2451
2558
|
*/
|
|
2452
2559
|
async get(deviceId, slot) {
|
|
2453
2560
|
var _a;
|
|
2454
|
-
const
|
|
2455
|
-
|
|
2456
|
-
const device = __classPrivateFieldGet(this, _LocalDatabase_deviceManager, "f").devices.get(deviceId);
|
|
2457
|
-
if (device === undefined) {
|
|
2458
|
-
return null;
|
|
2459
|
-
}
|
|
2460
|
-
if (device.type !== types_1.DeviceType.CDJ ||
|
|
2461
|
-
device.id < constants_1.MIN_CDJ_DEVICE_ID ||
|
|
2462
|
-
device.id > constants_1.MAX_CDJ_DEVICE_ID) {
|
|
2463
|
-
return null;
|
|
2464
|
-
}
|
|
2465
|
-
let media;
|
|
2466
|
-
try {
|
|
2467
|
-
media = await __classPrivateFieldGet(this, _LocalDatabase_statusEmitter, "f").queryMediaSlot({
|
|
2468
|
-
hostDevice: __classPrivateFieldGet(this, _LocalDatabase_hostDevice, "f"),
|
|
2469
|
-
device,
|
|
2470
|
-
slot,
|
|
2471
|
-
});
|
|
2472
|
-
}
|
|
2473
|
-
catch {
|
|
2474
|
-
// Timeout or other error - treat as no media
|
|
2475
|
-
return null;
|
|
2476
|
-
}
|
|
2477
|
-
if (media.tracksType !== types_1.TrackType.RB) {
|
|
2478
|
-
return null;
|
|
2479
|
-
}
|
|
2480
|
-
const id = getMediaId(media);
|
|
2481
|
-
// Acquire a lock for this device slot that will not release until we've
|
|
2482
|
-
// guaranteed the existence of the database.
|
|
2483
|
-
const db = await lock.runExclusive(() => {
|
|
2484
|
-
const cached = __classPrivateFieldGet(this, _LocalDatabase_dbs, "f").find(db => db.id === id);
|
|
2485
|
-
if (cached) {
|
|
2486
|
-
return cached;
|
|
2487
|
-
}
|
|
2488
|
-
return __classPrivateFieldGet(this, _LocalDatabase_hydrateDatabase, "f").call(this, device, slot, media);
|
|
2489
|
-
});
|
|
2490
|
-
return db.adapter;
|
|
2561
|
+
const db = await __classPrivateFieldGet(this, _LocalDatabase_instances, "m", _LocalDatabase_getItem).call(this, deviceId, slot);
|
|
2562
|
+
return (_a = db === null || db === void 0 ? void 0 : db.adapter) !== null && _a !== void 0 ? _a : null;
|
|
2491
2563
|
}
|
|
2492
2564
|
/**
|
|
2493
2565
|
* Get the database type for an already-loaded device slot.
|
|
@@ -2513,7 +2585,50 @@ class LocalDatabase {
|
|
|
2513
2585
|
await Promise.all(loaders);
|
|
2514
2586
|
}
|
|
2515
2587
|
}
|
|
2516
|
-
_LocalDatabase_hostDevice = new WeakMap(), _LocalDatabase_deviceManager = new WeakMap(), _LocalDatabase_statusEmitter = new WeakMap(), _LocalDatabase_emitter = new WeakMap(), _LocalDatabase_slotLocks = new WeakMap(), _LocalDatabase_dbs = new WeakMap(), _LocalDatabase_preference = new WeakMap(), _LocalDatabase_handleDeviceRemoved = new WeakMap(), _LocalDatabase_fetchFileWithFallback = new WeakMap(), _LocalDatabase_tryLoadOneLibrary = new WeakMap(), _LocalDatabase_loadPdbDatabase = new WeakMap(), _LocalDatabase_hydrateDatabase = new WeakMap()
|
|
2588
|
+
_LocalDatabase_hostDevice = new WeakMap(), _LocalDatabase_deviceManager = new WeakMap(), _LocalDatabase_statusEmitter = new WeakMap(), _LocalDatabase_emitter = new WeakMap(), _LocalDatabase_slotLocks = new WeakMap(), _LocalDatabase_dbs = new WeakMap(), _LocalDatabase_preference = new WeakMap(), _LocalDatabase_handleDeviceRemoved = new WeakMap(), _LocalDatabase_closeLoaded = new WeakMap(), _LocalDatabase_fetchFileWithFallback = new WeakMap(), _LocalDatabase_tryLoadOneLibrary = new WeakMap(), _LocalDatabase_loadPdbDatabase = new WeakMap(), _LocalDatabase_hydrateDatabase = new WeakMap(), _LocalDatabase_loadAlternate = new WeakMap(), _LocalDatabase_instances = new WeakSet(), _LocalDatabase_getItem =
|
|
2589
|
+
/**
|
|
2590
|
+
* The loaded database entry for a device slot, hydrating it first if needed.
|
|
2591
|
+
*/
|
|
2592
|
+
async function _LocalDatabase_getItem(deviceId, slot) {
|
|
2593
|
+
var _a;
|
|
2594
|
+
const lockKey = `${deviceId}-${slot}`;
|
|
2595
|
+
const lock = (_a = __classPrivateFieldGet(this, _LocalDatabase_slotLocks, "f").get(lockKey)) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _LocalDatabase_slotLocks, "f").set(lockKey, new async_mutex_1.Mutex()).get(lockKey);
|
|
2596
|
+
const device = __classPrivateFieldGet(this, _LocalDatabase_deviceManager, "f").devices.get(deviceId);
|
|
2597
|
+
if (device === undefined) {
|
|
2598
|
+
return null;
|
|
2599
|
+
}
|
|
2600
|
+
if (device.type !== types_1.DeviceType.CDJ ||
|
|
2601
|
+
device.id < constants_1.MIN_CDJ_DEVICE_ID ||
|
|
2602
|
+
device.id > constants_1.MAX_CDJ_DEVICE_ID) {
|
|
2603
|
+
return null;
|
|
2604
|
+
}
|
|
2605
|
+
let media;
|
|
2606
|
+
try {
|
|
2607
|
+
media = await __classPrivateFieldGet(this, _LocalDatabase_statusEmitter, "f").queryMediaSlot({
|
|
2608
|
+
hostDevice: __classPrivateFieldGet(this, _LocalDatabase_hostDevice, "f"),
|
|
2609
|
+
device,
|
|
2610
|
+
slot,
|
|
2611
|
+
});
|
|
2612
|
+
}
|
|
2613
|
+
catch {
|
|
2614
|
+
// Timeout or other error - treat as no media
|
|
2615
|
+
return null;
|
|
2616
|
+
}
|
|
2617
|
+
if (media.tracksType !== types_1.TrackType.RB) {
|
|
2618
|
+
return null;
|
|
2619
|
+
}
|
|
2620
|
+
const id = getMediaId(media);
|
|
2621
|
+
// Acquire a lock for this device slot that will not release until we've
|
|
2622
|
+
// guaranteed the existence of the database.
|
|
2623
|
+
const db = await lock.runExclusive(() => {
|
|
2624
|
+
const cached = __classPrivateFieldGet(this, _LocalDatabase_dbs, "f").find(db => db.id === id);
|
|
2625
|
+
if (cached) {
|
|
2626
|
+
return cached;
|
|
2627
|
+
}
|
|
2628
|
+
return __classPrivateFieldGet(this, _LocalDatabase_hydrateDatabase, "f").call(this, device, slot, media);
|
|
2629
|
+
});
|
|
2630
|
+
return db;
|
|
2631
|
+
};
|
|
2517
2632
|
exports["default"] = LocalDatabase;
|
|
2518
2633
|
|
|
2519
2634
|
|