alphatheta-connect 0.22.0 → 0.23.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/lib/index.d.ts CHANGED
@@ -13,8 +13,8 @@ export { fetchFile } from './nfs';
13
13
  export type { DatabaseAdapter, DatabasePreference, DatabaseType, PlaylistQueryResult, } from 'onelibrary-connect';
14
14
  export { OneLibraryAdapter } from 'onelibrary-connect';
15
15
  export type { Category, DeviceProperty, HistorySession, HotCueBankList, MenuItem, MyTag, SortOption, } from 'onelibrary-connect';
16
- export type { PickDeviceIdOptions } from './virtualcdj/device-id';
17
- export { MAX_DEVICE_ID, pickAvailableDeviceId, REMOTEDB_MAX_DEVICE_ID, } from './virtualcdj/device-id';
16
+ export type { DeviceLike, PickDeviceIdOptions } from './virtualcdj/device-id';
17
+ export { DEFAULT_MIXER_PLAYER_CEILING, MAX_DEVICE_ID, MIXER_PLAYER_CEILING, pickAvailableDeviceId, playerNumberCeiling, REMOTEDB_MAX_DEVICE_ID, } from './virtualcdj/device-id';
18
18
  export type { Logger } from './logger';
19
19
  export { noopLogger } from './logger';
20
20
  export * from './types';
package/lib/index.js CHANGED
@@ -2085,7 +2085,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
2085
2085
  return (mod && mod.__esModule) ? mod : { "default": mod };
2086
2086
  };
2087
2087
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2088
- exports.noopLogger = exports.REMOTEDB_MAX_DEVICE_ID = exports.pickAvailableDeviceId = exports.MAX_DEVICE_ID = exports.OneLibraryAdapter = exports.fetchFile = exports.loadAnlz = exports.isMetadataExtractionSupported = exports.extractMetadataFromDevice = exports.extractFullMetadata = exports.PictureType = exports.isArtworkExtractionSupported = exports.extractArtworkFromDevice = exports.extractArtwork = exports.PositionEmitter = void 0;
2088
+ exports.noopLogger = exports.REMOTEDB_MAX_DEVICE_ID = exports.playerNumberCeiling = exports.pickAvailableDeviceId = exports.MIXER_PLAYER_CEILING = exports.MAX_DEVICE_ID = exports.DEFAULT_MIXER_PLAYER_CEILING = exports.OneLibraryAdapter = exports.fetchFile = exports.loadAnlz = exports.isMetadataExtractionSupported = exports.extractMetadataFromDevice = exports.extractFullMetadata = exports.PictureType = exports.isArtworkExtractionSupported = exports.extractArtworkFromDevice = exports.extractArtwork = exports.PositionEmitter = void 0;
2089
2089
  __exportStar(__webpack_require__(/*! ./entities */ "./src/entities.ts"), exports);
2090
2090
  __exportStar(__webpack_require__(/*! ./mixstatus */ "./src/mixstatus/index.ts"), exports);
2091
2091
  __exportStar(__webpack_require__(/*! ./network */ "./src/network.ts"), exports);
@@ -2109,8 +2109,11 @@ Object.defineProperty(exports, "fetchFile", ({ enumerable: true, get: function (
2109
2109
  var onelibrary_connect_1 = __webpack_require__(/*! onelibrary-connect */ "onelibrary-connect");
2110
2110
  Object.defineProperty(exports, "OneLibraryAdapter", ({ enumerable: true, get: function () { return onelibrary_connect_1.OneLibraryAdapter; } }));
2111
2111
  var device_id_1 = __webpack_require__(/*! ./virtualcdj/device-id */ "./src/virtualcdj/device-id.ts");
2112
+ Object.defineProperty(exports, "DEFAULT_MIXER_PLAYER_CEILING", ({ enumerable: true, get: function () { return device_id_1.DEFAULT_MIXER_PLAYER_CEILING; } }));
2112
2113
  Object.defineProperty(exports, "MAX_DEVICE_ID", ({ enumerable: true, get: function () { return device_id_1.MAX_DEVICE_ID; } }));
2114
+ Object.defineProperty(exports, "MIXER_PLAYER_CEILING", ({ enumerable: true, get: function () { return device_id_1.MIXER_PLAYER_CEILING; } }));
2113
2115
  Object.defineProperty(exports, "pickAvailableDeviceId", ({ enumerable: true, get: function () { return device_id_1.pickAvailableDeviceId; } }));
2116
+ Object.defineProperty(exports, "playerNumberCeiling", ({ enumerable: true, get: function () { return device_id_1.playerNumberCeiling; } }));
2114
2117
  Object.defineProperty(exports, "REMOTEDB_MAX_DEVICE_ID", ({ enumerable: true, get: function () { return device_id_1.REMOTEDB_MAX_DEVICE_ID; } }));
2115
2118
  var logger_1 = __webpack_require__(/*! ./logger */ "./src/logger.ts");
2116
2119
  Object.defineProperty(exports, "noopLogger", ({ enumerable: true, get: function () { return logger_1.noopLogger; } }));
@@ -12948,7 +12951,8 @@ function udpClose(conn) {
12948
12951
  "use strict";
12949
12952
 
12950
12953
  Object.defineProperty(exports, "__esModule", ({ value: true }));
12951
- exports.MAX_DEVICE_ID = exports.REMOTEDB_MAX_DEVICE_ID = void 0;
12954
+ exports.DEFAULT_MIXER_PLAYER_CEILING = exports.MIXER_PLAYER_CEILING = exports.MAX_DEVICE_ID = exports.REMOTEDB_MAX_DEVICE_ID = void 0;
12955
+ exports.playerNumberCeiling = playerNumberCeiling;
12952
12956
  exports.pickAvailableDeviceId = pickAvailableDeviceId;
12953
12957
  /**
12954
12958
  * The highest device ID a CDJ will answer remotedb queries from.
@@ -12961,6 +12965,100 @@ exports.REMOTEDB_MAX_DEVICE_ID = 6;
12961
12965
  * The highest device ID the prolink protocol allows.
12962
12966
  */
12963
12967
  exports.MAX_DEVICE_ID = 32;
12968
+ /**
12969
+ * `DeviceType.Mixer`, inlined so this module stays free of runtime imports —
12970
+ * it is re-exported into consumers' test environments, where pulling in the
12971
+ * whole type module (and its ip-address dependency) is dead weight.
12972
+ */
12973
+ const MIXER_DEVICE_TYPE = 0x03;
12974
+ /**
12975
+ * How many player numbers each mixer can hand out.
12976
+ *
12977
+ * Players take their number from the mixer channel they are plugged into, so
12978
+ * an N-channel mixer only ever produces players 1..N — and N+1 is the lowest
12979
+ * number that no player on that rig can claim.
12980
+ *
12981
+ * These are physical channel counts, deliberately NOT the `channelCount` in
12982
+ * the app's own capability table, which caps the DJM-V10 at 4 for its mixer
12983
+ * signal model. Capping here would put us on player 5 of a 6-channel rig,
12984
+ * which is the collision this table exists to avoid.
12985
+ */
12986
+ exports.MIXER_PLAYER_CEILING = {
12987
+ // 6-channel flagships — no player number in 1-6 is safe on these
12988
+ 'DJM-V10': 6,
12989
+ 'DJM-V10-LF': 6,
12990
+ // 4-channel
12991
+ 'DJM-A9': 4,
12992
+ 'DJM-900NXS2': 4,
12993
+ 'DJM-900NXS': 4,
12994
+ 'DJM-900SRT': 4,
12995
+ 'DJM-850': 4,
12996
+ 'DJM-800': 4,
12997
+ 'DJM-750MK2': 4,
12998
+ 'DJM-750': 4,
12999
+ 'DJM-TOUR1': 4,
13000
+ 'DJM-2000NXS': 4,
13001
+ 'DJM-2000': 4,
13002
+ EUPHONIA: 4,
13003
+ // 3-channel (2026)
13004
+ 'DJM-V5': 3,
13005
+ // 2-channel
13006
+ 'DJM-450': 2,
13007
+ 'DJM-350': 2,
13008
+ 'DJM-250MK2': 2,
13009
+ // All-in-ones: their built-in players occupy numbers too, so the ceiling is
13010
+ // however many decks the unit announces rather than its mixer channel count
13011
+ 'XDJ-XZ': 4,
13012
+ 'XDJ-AZ': 4,
13013
+ 'XDJ-RX3': 2,
13014
+ 'XDJ-RX2': 2,
13015
+ 'XDJ-RX': 2,
13016
+ 'XDJ-AN': 2,
13017
+ 'OPUS-QUAD': 4,
13018
+ };
13019
+ /**
13020
+ * What to assume about a mixer whose model we do not recognise.
13021
+ *
13022
+ * Four is both the most common layout and the choice that keeps remotedb
13023
+ * metadata working: assuming six would push us to player 7 on every mixer
13024
+ * released after this table was written, silently losing metadata for
13025
+ * unanalyzed and streaming tracks. A six-channel unit we failed to recognise
13026
+ * may later claim the number we took, which the announcer's conflict handling
13027
+ * resolves by moving us.
13028
+ */
13029
+ exports.DEFAULT_MIXER_PLAYER_CEILING = 4;
13030
+ /**
13031
+ * The highest player number the discovered gear can hand out, or undefined
13032
+ * when nothing on the network implies one.
13033
+ *
13034
+ * Undefined means we have no mixer to reason from — players may have been
13035
+ * numbered by hand anywhere in 1-6, and there is no better guess available.
13036
+ */
13037
+ function playerNumberCeiling(devices) {
13038
+ let ceiling;
13039
+ for (const device of devices) {
13040
+ const known = exports.MIXER_PLAYER_CEILING[device.name.trim().toUpperCase()];
13041
+ const value = known !== null && known !== void 0 ? known : (device.type === MIXER_DEVICE_TYPE ? exports.DEFAULT_MIXER_PLAYER_CEILING : undefined);
13042
+ if (value !== undefined && (ceiling === undefined || value > ceiling)) {
13043
+ ceiling = value;
13044
+ }
13045
+ }
13046
+ return ceiling;
13047
+ }
13048
+ const descending = (from, to) => {
13049
+ const ids = [];
13050
+ for (let id = from; id >= to; id--) {
13051
+ ids.push(id);
13052
+ }
13053
+ return ids;
13054
+ };
13055
+ const ascending = (from, to) => {
13056
+ const ids = [];
13057
+ for (let id = from; id <= to; id++) {
13058
+ ids.push(id);
13059
+ }
13060
+ return ids;
13061
+ };
12964
13062
  /**
12965
13063
  * Pick a device ID that no device on the network is currently using.
12966
13064
  *
@@ -12971,20 +13069,22 @@ exports.MAX_DEVICE_ID = 32;
12971
13069
  * Returns null when every ID from 1 to 32 is occupied, in which case there is
12972
13070
  * no safe ID and the caller must not join the network.
12973
13071
  */
12974
- function pickAvailableDeviceId(usedIds, { preferRemoteDb = false } = {}) {
13072
+ function pickAvailableDeviceId(usedIds, { preferRemoteDb = false, playerCeiling } = {}) {
12975
13073
  var _a;
12976
13074
  const used = new Set(usedIds);
12977
- const remoteDbRange = [];
12978
- for (let id = exports.REMOTEDB_MAX_DEVICE_ID; id >= 1; id--) {
12979
- remoteDbRange.push(id);
12980
- }
12981
- const highRange = [];
12982
- for (let id = exports.REMOTEDB_MAX_DEVICE_ID + 1; id <= exports.MAX_DEVICE_ID; id++) {
12983
- highRange.push(id);
12984
- }
13075
+ const aboveThePlayers = playerCeiling === undefined
13076
+ ? descending(exports.REMOTEDB_MAX_DEVICE_ID, 1)
13077
+ : ascending(playerCeiling + 1, exports.REMOTEDB_MAX_DEVICE_ID);
13078
+ const outsideRemoteDb = ascending(exports.REMOTEDB_MAX_DEVICE_ID + 1, exports.MAX_DEVICE_ID);
13079
+ // Numbers a player on this rig could be assigned. Last resort: better to
13080
+ // contend for a slot than not to join at all, and the announcer moves us if
13081
+ // the player that owns it shows up.
13082
+ const amongThePlayers = playerCeiling === undefined
13083
+ ? []
13084
+ : descending(Math.min(playerCeiling, exports.REMOTEDB_MAX_DEVICE_ID), 1);
12985
13085
  const search = preferRemoteDb
12986
- ? [...remoteDbRange, ...highRange]
12987
- : [...highRange, ...remoteDbRange];
13086
+ ? [...aboveThePlayers, ...outsideRemoteDb, ...amongThePlayers]
13087
+ : [...outsideRemoteDb, ...aboveThePlayers, ...amongThePlayers];
12988
13088
  return (_a = search.find(id => !used.has(id))) !== null && _a !== void 0 ? _a : null;
12989
13089
  }
12990
13090
 
@@ -13418,9 +13518,14 @@ _Announcer_announceSocket = new WeakMap(), _Announcer_deviceManager = new WeakMa
13418
13518
  // Stay in whichever range we were already in. Dropping out of 1-6 would
13419
13519
  // silently lose remotedb metadata for unanalyzed and streaming tracks, so
13420
13520
  // a conflict on player 5 looks for another free player number first.
13421
- const usedIds = [...__classPrivateFieldGet(this, _Announcer_deviceManager, "f").devices.values()].map(d => d.id);
13422
- const newId = (0, device_id_1.pickAvailableDeviceId)(usedIds, {
13521
+ //
13522
+ // The mixer decides which of those numbers are actually safe: a player can
13523
+ // only be assigned a number its mixer has a channel for, so anything above
13524
+ // that is out of reach of the rig that just contested us.
13525
+ const devices = [...__classPrivateFieldGet(this, _Announcer_deviceManager, "f").devices.values()];
13526
+ const newId = (0, device_id_1.pickAvailableDeviceId)(devices.map(d => d.id), {
13423
13527
  preferRemoteDb: __classPrivateFieldGet(this, _Announcer_vcdj, "f").id <= device_id_1.REMOTEDB_MAX_DEVICE_ID,
13528
+ playerCeiling: (0, device_id_1.playerNumberCeiling)(devices),
13424
13529
  });
13425
13530
  if (newId === null) {
13426
13531
  __classPrivateFieldGet(this, _Announcer_logger, "f").error('No available device IDs. All 32 slots are occupied.');