networkwm-js 0.1.0 → 0.1.1

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.
Files changed (73) hide show
  1. package/README.MD +3 -2
  2. package/dist/bytemanip.d.ts.map +1 -1
  3. package/dist/bytemanip.js +4 -0
  4. package/dist/cli/decrypt-mp3.d.ts +3 -0
  5. package/dist/cli/decrypt-mp3.d.ts.map +1 -0
  6. package/dist/cli/decrypt-mp3.js +59 -0
  7. package/dist/cli/decrypt-oma.d.ts +2 -0
  8. package/dist/cli/decrypt-oma.d.ts.map +1 -0
  9. package/dist/cli/decrypt-oma.js +25 -0
  10. package/dist/cli/sign-device.d.ts +2 -0
  11. package/dist/cli/sign-device.d.ts.map +1 -0
  12. package/dist/cli/sign-device.js +30 -0
  13. package/dist/cli/table-file-info.d.ts +2 -0
  14. package/dist/cli/table-file-info.d.ts.map +1 -0
  15. package/dist/cli/table-file-info.js +46 -0
  16. package/dist/cli/tagged-oma-info.d.ts +2 -0
  17. package/dist/cli/tagged-oma-info.d.ts.map +1 -0
  18. package/dist/cli/tagged-oma-info.js +192 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +50 -0
  22. package/dist/codecs.d.ts +13 -0
  23. package/dist/codecs.d.ts.map +1 -0
  24. package/dist/codecs.js +40 -0
  25. package/dist/database-abstraction.d.ts +11 -4
  26. package/dist/database-abstraction.d.ts.map +1 -1
  27. package/dist/database-abstraction.js +84 -27
  28. package/dist/databases.d.ts +10 -1
  29. package/dist/databases.d.ts.map +1 -1
  30. package/dist/databases.js +2 -1
  31. package/dist/derive-mp3-key.d.ts +12 -0
  32. package/dist/derive-mp3-key.d.ts.map +1 -0
  33. package/dist/derive-mp3-key.js +109 -0
  34. package/dist/devices.d.ts +9 -2
  35. package/dist/devices.d.ts.map +1 -1
  36. package/dist/devices.js +70 -2
  37. package/dist/encryption.d.ts +2 -2
  38. package/dist/encryption.d.ts.map +1 -1
  39. package/dist/encryption.js +25 -12
  40. package/dist/filesystem/usb-mass-storage-webusb-filesystem.d.ts +2 -0
  41. package/dist/filesystem/usb-mass-storage-webusb-filesystem.d.ts.map +1 -1
  42. package/dist/filesystem/usb-mass-storage-webusb-filesystem.js +8 -1
  43. package/dist/helpers.d.ts +6 -2
  44. package/dist/helpers.d.ts.map +1 -1
  45. package/dist/helpers.js +9 -8
  46. package/dist/id3.d.ts +7 -0
  47. package/dist/id3.d.ts.map +1 -1
  48. package/dist/id3.js +25 -1
  49. package/dist/init-data.d.ts +25 -14
  50. package/dist/init-data.d.ts.map +1 -1
  51. package/dist/init-data.js +23 -15
  52. package/dist/initialization.d.ts +3 -2
  53. package/dist/initialization.d.ts.map +1 -1
  54. package/dist/initialization.js +14 -4
  55. package/dist/mp3.d.ts +9 -0
  56. package/dist/mp3.d.ts.map +1 -0
  57. package/dist/mp3.js +137 -0
  58. package/dist/tables.d.ts +1 -0
  59. package/dist/tables.d.ts.map +1 -1
  60. package/dist/tables.js +3 -0
  61. package/dist/tagged-oma.d.ts +3 -2
  62. package/dist/tagged-oma.d.ts.map +1 -1
  63. package/dist/tagged-oma.js +72 -33
  64. package/dist/test.d.ts +2 -0
  65. package/dist/test.d.ts.map +1 -0
  66. package/dist/test.js +70 -0
  67. package/dist/utils.d.ts +6 -2
  68. package/dist/utils.d.ts.map +1 -1
  69. package/dist/utils.js +35 -12
  70. package/package.json +8 -4
  71. package/dist/functions.d.ts +0 -12
  72. package/dist/functions.d.ts.map +0 -1
  73. package/dist/functions.js +0 -73
@@ -3,22 +3,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.updateMetadata = exports.createTaggedEncryptedOMA = void 0;
6
+ exports.decryptOMA = exports.updateMetadata = exports.createTaggedEncryptedOMA = void 0;
7
7
  const crypto_js_wasm_1 = __importDefault(require("@originjs/crypto-js-wasm"));
8
8
  const himd_js_1 = require("himd-js");
9
9
  const utils_1 = require("./utils");
10
10
  const id3_1 = require("./id3");
11
11
  const encryption_1 = require("./encryption");
12
+ const codecs_1 = require("./codecs");
12
13
  const textEncoder = new TextEncoder();
13
14
  const PHONY_CID = new Uint8Array([0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x50, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xA9, 0xC1, 0x6A, 0x81, 0x6A, 0x87, 0xDA, 0xAD, 0x4B, 0xA2, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
14
15
  const EKB1001D_CONTENTS = new Uint8Array([0x45, 0x4B, 0x42, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x39, 0x47, 0xF4, 0x0A, 0x33, 0x65, 0x2F, 0x98, 0x71, 0x73, 0xC3, 0x98, 0x68, 0xC5, 0x23, 0x5B, 0x84, 0x20, 0xC8, 0xCF, 0xFB, 0x0E, 0x7F, 0x4E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x34, 0x85, 0x14, 0x51, 0x45, 0x04, 0x02, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x36, 0xD2, 0x00, 0x38, 0x74, 0x91, 0x51, 0x9D, 0xA7, 0x75, 0x94, 0x70, 0xA0, 0x17, 0x69, 0xDA, 0x69, 0x55, 0xAE, 0xA6, 0x9F, 0x6A, 0x3E, 0x69, 0x18, 0xC7, 0xC6, 0xBB, 0xD7, 0xCC, 0xFB, 0x1B, 0x81, 0x8D, 0xA9, 0x97, 0x90, 0x67, 0x29, 0x5C, 0xB7, 0x55, 0x5A, 0xEC, 0x21, 0x1B, 0x9E, 0xBD, 0xD4, 0x7E, 0xD9, 0x09, 0x79, 0xE0, 0x39, 0xA1, 0xE0, 0x76, 0x68, 0x0D, 0xB8, 0xBF, 0xED, 0xB0, 0xD3, 0x24, 0x26, 0xB8, 0xF7, 0x79, 0x22, 0xBD, 0x46, 0xC9, 0x44, 0x9F, 0xDF, 0x01, 0x74, 0xC0, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0xDB, 0x54, 0x6A, 0xC5, 0xE0, 0x4D, 0x4F, 0xCB, 0xF2, 0x46, 0x3B, 0x01, 0xDE, 0x2C, 0xD0, 0xFB, 0xAF, 0x7A, 0xA7, 0x1E, 0xEF, 0x44, 0x29, 0x05, 0x97, 0x9D, 0xBE, 0xE7, 0x28, 0x4E, 0xA4, 0x53, 0x3A, 0x2F, 0x71, 0xC7, 0xCB, 0x86, 0x58, 0x39]);
15
- function encodeSonyWeirdString(type, data) {
16
- return (0, utils_1.concatUint8Arrays)([
17
- (0, id3_1.encodeUTF16BEStringEA3)(type),
18
- new Uint8Array([0, 0]),
19
- (0, id3_1.encodeUTF16BEStringEA3)(data, false),
20
- ]);
21
- }
16
+ const ULINF_KEYRING_HEADER = new Uint8Array([
17
+ 0x00, 0x28, 0x00, 0x01,
18
+ 0x00, 0x03, 0x00, 0x00,
19
+ 0x00, 0x00, 0x00, 0x00,
20
+ 0x00, 0x01, 0x00, 0x21,
21
+ ]);
22
22
  function createSonyGEOB(geobName, header, kvmap) {
23
23
  // Header:
24
24
  const dataSlices = [
@@ -42,12 +42,7 @@ function createEncryptionHeader(titleInfo, milliseconds) {
42
42
  // In every KEYRING section, the track key is stored as decrypted by the verification key decrypted by the ekbroot
43
43
  const padding = (0, utils_1.createRandomBytes)(8); // What's this???
44
44
  const keyringDataA = (0, utils_1.concatUint8Arrays)([
45
- new Uint8Array([
46
- 0x00, 0x28, 0x00, 0x01,
47
- 0x00, 0x03, 0x00, 0x00,
48
- 0x00, 0x00, 0x00, 0x00,
49
- 0x00, 0x01, 0x00, 0x21,
50
- ]),
45
+ ULINF_KEYRING_HEADER,
51
46
  verificationKey, (0, encryption_1.createTrackKeyForKeyring)(0x00010021, verificationKey, actualTrackKey), padding,
52
47
  new Uint8Array(8).fill(0),
53
48
  ]);
@@ -87,15 +82,7 @@ function createEncryptionHeader(titleInfo, milliseconds) {
87
82
  version: { major: 3, minor: 0 },
88
83
  tags: [
89
84
  { id: "GEOB", contents: firstGEOBContents, flags: 0 },
90
- { id: "TIT2", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.title), flags: 0 },
91
- { id: "TPE1", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.artist), flags: 0 },
92
- { id: "TALB", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.album), flags: 0 },
93
- { id: "TALB", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.album), flags: 0 },
94
- { id: "TCON", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.genre), flags: 0 },
95
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_TPE1S", titleInfo.artist), flags: 0 },
96
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_TRACK", '0'), flags: 0 },
97
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_ALBMS", titleInfo.album), flags: 0 },
98
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_TIT2S", titleInfo.title), flags: 0 },
85
+ ...(0, id3_1.createCommonID3Tags)(titleInfo),
99
86
  { id: "TLEN", contents: (0, id3_1.encodeUTF16BEStringEA3)(milliseconds.toString()), flags: 0 },
100
87
  { id: "GEOB", contents: secondGEOBContents, flags: 0 }, // OMG_BKLSI
101
88
  ]
@@ -103,7 +90,7 @@ function createEncryptionHeader(titleInfo, milliseconds) {
103
90
  return { contents: (0, id3_1.serialize)(id3Info), trackEncryptionKey: actualTrackKey, maclistValue };
104
91
  }
105
92
  function createTaggedEncryptedOMA(rawData, titleInfo, codec) {
106
- const formatHeader = (0, utils_1.createEA3Header)(codec, true);
93
+ const formatHeader = (0, codecs_1.createEA3Header)(codec, 0x0001);
107
94
  const milliseconds = Math.floor(1000 * (0, himd_js_1.getSeconds)(codec, Math.ceil(rawData.length / (0, himd_js_1.getBytesPerFrame)(codec))));
108
95
  const { contents: encHeader, trackEncryptionKey, maclistValue } = createEncryptionHeader(titleInfo, milliseconds);
109
96
  let iv = (0, utils_1.createRandomBytes)(8);
@@ -151,15 +138,7 @@ async function updateMetadata(file, titleInfo) {
151
138
  version: metadata.version,
152
139
  tags: [
153
140
  ulinf,
154
- { id: "TIT2", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.title), flags: 0 },
155
- { id: "TPE1", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.artist), flags: 0 },
156
- { id: "TALB", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.album), flags: 0 },
157
- { id: "TALB", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.album), flags: 0 },
158
- { id: "TCON", contents: (0, id3_1.encodeUTF16BEStringEA3)(titleInfo.genre), flags: 0 },
159
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_TPE1S", titleInfo.artist), flags: 0 },
160
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_TRACK", '0'), flags: 0 },
161
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_ALBMS", titleInfo.album), flags: 0 },
162
- { id: "TXXX", contents: encodeSonyWeirdString("OMG_TIT2S", titleInfo.title), flags: 0 },
141
+ ...(0, id3_1.createCommonID3Tags)(titleInfo),
163
142
  tlen,
164
143
  bklsi,
165
144
  ]
@@ -173,3 +152,63 @@ async function updateMetadata(file, titleInfo) {
173
152
  await file.write(new Uint8Array(zeroOutDifference).fill(0));
174
153
  }
175
154
  exports.updateMetadata = updateMetadata;
155
+ function decryptOMA(omaFile) {
156
+ var _a;
157
+ const OMA_METADATA_HEADER = textEncoder.encode("ea3");
158
+ if (!(0, utils_1.arrayEq)(OMA_METADATA_HEADER, omaFile.subarray(0, 3))) {
159
+ throw new Error("Not a valid OMA file");
160
+ }
161
+ const metaHeaderSize = 10 + (0, id3_1.readSynchsafeInt32)(new DataView(omaFile.buffer), 6)[0];
162
+ const metadata = (0, id3_1.parse)(omaFile.subarray(0, metaHeaderSize));
163
+ const textDecoder = new TextDecoder();
164
+ const ulinf = (_a = findInMetadata(metadata, "OMG_ULINF", true)) === null || _a === void 0 ? void 0 : _a.contents;
165
+ let dataOffset = 10 + 'OMG_ULINF'.length * 2 + 2;
166
+ let keyringContents = null;
167
+ if (!ulinf)
168
+ throw new Error("No ULINF GEOB found!");
169
+ while ((dataOffset + 16) < ulinf.length) {
170
+ let name = textDecoder.decode(ulinf.subarray(dataOffset, dataOffset + 12)).trim();
171
+ let chunkLen = ulinf[dataOffset + 13];
172
+ let chunkCount = ulinf[dataOffset + 15];
173
+ if (name.includes("\x00")) {
174
+ name = name.substring(0, name.indexOf("\x00"));
175
+ }
176
+ if (name !== 'KEYRING') {
177
+ dataOffset += 16 + (chunkCount * chunkLen);
178
+ continue;
179
+ }
180
+ keyringContents = ulinf.subarray(dataOffset + 16, dataOffset + 16 + (chunkCount * chunkLen));
181
+ break;
182
+ }
183
+ if (!keyringContents)
184
+ throw new Error("Cannot find KEYRING in ULINF!");
185
+ if (!(0, utils_1.arrayEq)(ULINF_KEYRING_HEADER, keyringContents.subarray(0, ULINF_KEYRING_HEADER.length)))
186
+ throw new Error("Invalid ULINF KEYRING header");
187
+ const encryptedVerificationKey = keyringContents.slice(16, 16 + 8);
188
+ const encryptedTrackKey = keyringContents.slice(24, 24 + 8);
189
+ const decryptedTrackKey = (0, encryption_1.createTrackKeyFromKeyring)(0x00010021, encryptedVerificationKey, encryptedTrackKey);
190
+ // We have the key now. Recreate the headers and form the final file.
191
+ // Strip all DRM tags:
192
+ metadata.tags = metadata.tags.filter(e => e.id !== "GEOB");
193
+ const newMetaHeader = (0, id3_1.serialize)(metadata);
194
+ const newFormatHeader = omaFile.slice(metaHeaderSize, metaHeaderSize + 96);
195
+ // Set encryption type to 0xFFFF (unencrypted)
196
+ newFormatHeader[6] = 0xFF;
197
+ newFormatHeader[7] = 0xFF;
198
+ // Retrieve IV from the header
199
+ const iv = newFormatHeader.slice(96 - 8);
200
+ // ...and destroy it
201
+ newFormatHeader.fill(0, 96 - 8);
202
+ // Finally, decrypt all the audio
203
+ const rawData = omaFile.subarray(metaHeaderSize + 96);
204
+ const keyWa = crypto_js_wasm_1.default.lib.WordArray.create(decryptedTrackKey);
205
+ const ivWa = crypto_js_wasm_1.default.lib.WordArray.create(iv);
206
+ const blockWa = crypto_js_wasm_1.default.lib.CipherParams.create({
207
+ ciphertext: crypto_js_wasm_1.default.lib.WordArray.create(rawData)
208
+ });
209
+ const allData = crypto_js_wasm_1.default.DES.decrypt(blockWa, keyWa, { mode: crypto_js_wasm_1.default.mode.CBC, iv: ivWa });
210
+ const decryptedAudio = (0, utils_1.wordArrayToByteArray)(allData, rawData.length);
211
+ // And merge all into the final OMA.
212
+ return (0, utils_1.concatUint8Arrays)([newMetaHeader, newFormatHeader, decryptedAudio]);
213
+ }
214
+ exports.decryptOMA = decryptOMA;
package/dist/test.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../src/test.ts"],"names":[],"mappings":""}
package/dist/test.js ADDED
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const codecs_1 = require("./codecs");
4
+ // (async () => {
5
+ // const data = new Uint8Array(fs.readFileSync("/ram/10000001.OMA"));
6
+ // const id3 = parse(data);
7
+ // console.log(id3);
8
+ // for(let tag of id3.tags) {
9
+ // fs.writeFileSync(`/ram/tag-${tag.id}`, tag.contents);
10
+ // }
11
+ // })();
12
+ // import { } from 'himd-js';
13
+ // import { createEA3Header } from './utils';
14
+ // (async () => {
15
+ // const header = createEA3Header({ })
16
+ // })
17
+ // const data = new Uint8Array(fs.readFileSync("/ram/10000007.OMA"));
18
+ // let trackKey;
19
+ // console.log(trackKey = deriveMP3TrackKey(data, console.log));
20
+ // console.log(deriveDeviceKey(trackKey, 0x07));
21
+ (async () => {
22
+ // const device = await openNewDeviceNode();
23
+ // initCrypto();
24
+ // importKeys(new Uint8Array(nfs.readFileSync("EKBROOTS.DES")));
25
+ // if(!device) {
26
+ // console.log("No device");
27
+ // return;
28
+ // }
29
+ // console.log(`Connected to ${device.definition.name}`);
30
+ // const fs = await createNWJSFS(device);
31
+ // const database = await DatabaseAbstraction.create(fs, device.definition);
32
+ // const session = new UMSCNWJSSession(fs.driver, fs);
33
+ // await session.performAuthorization();
34
+ // const trackNames = (JSON.parse(nfs.readFileSync("/mnt/NAS/Code/ALT_SS_STAGE/Putting the 9 hour mix on the MD/titlesv2/tracknames.json").toString()) as [string, string][]).map(e => e[1]);
35
+ // const BASE_LOC = "/mnt/NAS/Code/ALT_SS_STAGE/Putting the 9 hour mix on the MD/tracks/";
36
+ // for(let i = 1; i<180; i++){
37
+ // let file = `${BASE_LOC}/${i + 1}.wav`;
38
+ // const contents = new Uint8Array(nfs.readFileSync(file)).subarray(76);
39
+ // await uploadTrack(database, session, {
40
+ // album: "The Ultimate S3RL Tribute Mix 2023",
41
+ // artist: "S3RL",
42
+ // genre: "Happy Hardcore",
43
+ // title: trackNames[i],
44
+ // trackDuration: -1,
45
+ // trackNumber: -1,
46
+ // }, generateCodecInfo("AT3", HiMDKBPSToFrameSize.atrac3[66]), contents, console.log);
47
+ // console.log(`Finished uploading ${i + 1} / 180`);
48
+ // }
49
+ // await session.finalizeSession();
50
+ // await database.flushUpdates();
51
+ // await fs.fatfs!.flushMetadataChanges();
52
+ // console.log(await fs.list("/OMGAUDIO"));
53
+ // const session = new UMSCNWJSSession(fs.driver, fs);
54
+ // await session.performAuthorization();
55
+ // await database.uploadTrack({
56
+ // album: 'Singles',
57
+ // artist: 'cy4ne',
58
+ // genre: 'Scenecore',
59
+ // title: 'solace',
60
+ // trackNumber: -1,
61
+ // }, generateCodecInfo('A3+', HiMDKBPSToFrameSize.atrac3plus[256]), new Uint8Array(nfs.readFileSync("/ram/solace.raw.at3p")), session);
62
+ // await session.finalizeSession();
63
+ // await database.flushUpdates();
64
+ // await fs.fatfs!.flushMetadataChanges();
65
+ const nwCodec = {
66
+ codecId: codecs_1.NWCodec.MP3,
67
+ codecInfo: new Uint8Array([0x80, 0xdd, 0x10]),
68
+ };
69
+ console.log((0, codecs_1.getKBPS)(nwCodec));
70
+ })().then(() => process.exit(0));
package/dist/utils.d.ts CHANGED
@@ -1,9 +1,13 @@
1
- import { CodecInfo } from 'himd-js';
2
1
  export declare function assert(condition: boolean, message?: string): void;
3
2
  export declare function join(...paths: string[]): string;
4
3
  export declare function concatUint8Arrays(args: Uint8Array[]): Uint8Array;
5
- export declare function createEA3Header({ codecId, codecInfo }: CodecInfo, encrypted?: boolean): Uint8Array;
6
4
  export declare function wordArrayToByteArray(wordArray: any, length?: number): Uint8Array;
7
5
  export declare function createRandomBytes(length?: number): Uint8Array;
8
6
  export declare function arrayEq<T>(a: ArrayLike<T>, b: ArrayLike<T>): boolean;
7
+ export declare function hexDump(logger: (e: string) => void, data: Uint8Array, truncate?: boolean): void;
8
+ export declare class Logger {
9
+ preffix: string;
10
+ bumpIndent(i: number): void;
11
+ log(...data: string[]): void;
12
+ }
9
13
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,wBAAgB,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,QAM1D;AAED,wBAAgB,IAAI,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,UAEtC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,cAcnD;AAED,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,SAAS,UAAQ,cASnF;AAmBD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,GAAE,MAA2B,cAavF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,SAAI,cAM3C;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,WAM1D"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,QAM1D;AAED,wBAAgB,IAAI,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,UAEtC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,cAcnD;AAmBD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,GAAE,MAA2B,cAavF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,SAAI,cAM3C;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,WAM1D;AAGD,wBAAgB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,UAAO,QAarF;AAED,qBAAa,MAAM;IACf,OAAO,SAAM;IACb,UAAU,CAAC,CAAC,EAAE,MAAM;IAQpB,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;CAGxB"}
package/dist/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.arrayEq = exports.createRandomBytes = exports.wordArrayToByteArray = exports.createEA3Header = exports.concatUint8Arrays = exports.join = exports.assert = void 0;
3
+ exports.Logger = exports.hexDump = exports.arrayEq = exports.createRandomBytes = exports.wordArrayToByteArray = exports.concatUint8Arrays = exports.join = exports.assert = void 0;
4
4
  function assert(condition, message) {
5
5
  if (condition) {
6
6
  return;
@@ -27,17 +27,6 @@ function concatUint8Arrays(args) {
27
27
  return res;
28
28
  }
29
29
  exports.concatUint8Arrays = concatUint8Arrays;
30
- function createEA3Header({ codecId, codecInfo }, encrypted = false) {
31
- const headerSize = 96;
32
- const header = new Uint8Array(headerSize);
33
- header.set(new Uint8Array([0x45, 0x41, 0x33, 0x01, 0x00, 0x60, encrypted ? 0x00 : 0xff, encrypted ? 0x01 : 0xff, 0x00, 0x00, 0x00, 0x00]));
34
- header[32] = codecId;
35
- header[33] = codecInfo[0];
36
- header[34] = codecInfo[1];
37
- header[35] = codecInfo[2];
38
- return header;
39
- }
40
- exports.createEA3Header = createEA3Header;
41
30
  function wordToByteArray(word, length, littleEndian = false) {
42
31
  let ba = [], xFF = 0xff;
43
32
  let actualLength = length;
@@ -88,3 +77,37 @@ function arrayEq(a, b) {
88
77
  return true;
89
78
  }
90
79
  exports.arrayEq = arrayEq;
80
+ const textDecoder = new TextDecoder();
81
+ function hexDump(logger, data, truncate = true) {
82
+ if (data.length === 0)
83
+ logger("<None>");
84
+ let rows = Math.ceil(data.length / 16), truncated = false;
85
+ if (truncate && rows > 20) {
86
+ rows = 20;
87
+ truncated = true;
88
+ }
89
+ for (let row = 0; row < rows; row++) {
90
+ const rowData = data.subarray(row * 16, (row + 1) * 16);
91
+ logger(`${(row * 16).toString(16).padStart(4, '0')}:\t${Array.from(rowData).map(e => e.toString(16).padStart(2, '0')).join(' ')}\t${textDecoder.decode(rowData.map(e => e > 0x20 && e < 0x7F ? e : 46))}`);
92
+ }
93
+ if (truncated)
94
+ logger("<truncated>");
95
+ }
96
+ exports.hexDump = hexDump;
97
+ class Logger {
98
+ constructor() {
99
+ this.preffix = "";
100
+ }
101
+ bumpIndent(i) {
102
+ if (i < 0) {
103
+ this.preffix = this.preffix.substring(0, this.preffix.length + i * 4);
104
+ }
105
+ else {
106
+ this.preffix = this.preffix + " ".repeat(4 * i);
107
+ }
108
+ }
109
+ log(...data) {
110
+ console.log(this.preffix + data.join(' '));
111
+ }
112
+ }
113
+ exports.Logger = Logger;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "networkwm-js",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A library which lets you manage tracks and metadata on Sony Network Walkmen.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -21,6 +21,9 @@
21
21
  "files": [
22
22
  "dist"
23
23
  ],
24
+ "bin": {
25
+ "nwjs": "dist/cli.js"
26
+ },
24
27
  "bugs": {
25
28
  "url": "https://github.com/asivery/networkwm-js/issues"
26
29
  },
@@ -28,16 +31,17 @@
28
31
  "devDependencies": {
29
32
  "@types/node": "^18.11.9",
30
33
  "prettier": "^2.8.8",
34
+ "ts-node": "^10.9.2",
31
35
  "typescript": "^4.8.4"
32
36
  },
33
37
  "dependencies": {
34
38
  "@originjs/crypto-js-wasm": "github:asivery/crypto-js-wasm",
35
39
  "async-mutex": "^0.4.0",
36
- "himd-js": "^0.2.0-alpha.5",
40
+ "himd-js": "^0.2.0",
37
41
  "mp3-parser": "^0.3.0",
38
42
  "node-id3": "^0.2.5",
39
- "node-mass-storage": "^0.2.0",
40
- "nufatfs": "^0.1.5",
43
+ "node-mass-storage": "^0.2.2",
44
+ "nufatfs": "^0.1.8",
41
45
  "usb": "^2.4.1"
42
46
  }
43
47
  }
@@ -1,12 +0,0 @@
1
- import { CodecInfo } from "himd-js";
2
- import { WebUSBDevice } from "usb";
3
- import { TrackMetadata } from "./databases";
4
- import { UMSCNWJSFilesystem, UMSCNWJSSession } from "./filesystem";
5
- import { DatabaseAbstraction } from "./database-abstraction";
6
- export declare function uploadTrack(database: DatabaseAbstraction, session: UMSCNWJSSession, trackInfo: TrackMetadata, codec: CodecInfo, rawData: Uint8Array, callback?: (done: number, outOf: number) => void): Promise<void>;
7
- export declare function createNWJSFS(webUsbDevice: WebUSBDevice, bypassCoherencyChecks: boolean): Promise<UMSCNWJSFilesystem>;
8
- export declare function openNewDeviceNode(): Promise<{
9
- dev: WebUSBDevice;
10
- name: string;
11
- } | null>;
12
- //# sourceMappingURL=functions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,YAAY,EAAa,MAAM,KAAK,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAInE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAO7D,wBAAsB,WAAW,CAC7B,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,UAAU,EACnB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,iBA2BnD;AAED,wBAAsB,YAAY,CAAC,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,OAAO,+BAO5F;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC;IAAE,GAAG,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA2B7F"}
package/dist/functions.js DELETED
@@ -1,73 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.openNewDeviceNode = exports.createNWJSFS = exports.uploadTrack = void 0;
4
- const usb_1 = require("usb");
5
- const filesystem_1 = require("./filesystem");
6
- const tagged_oma_1 = require("./tagged-oma");
7
- const utils_1 = require("./utils");
8
- const devices_1 = require("./devices");
9
- const initialization_1 = require("./initialization");
10
- function resolvePathFromGlobalIndex(globalTrackIndex) {
11
- return (0, utils_1.join)('OMGAUDIO', '10F00', '1000' + globalTrackIndex.toString(16).padStart(4, '0').toUpperCase() + '.OMA');
12
- }
13
- async function uploadTrack(database, session, trackInfo, codec, rawData, callback) {
14
- // Step 1 - Create the encrypted OMA which will later be written to the device's storage
15
- const encryptedOMA = (0, tagged_oma_1.createTaggedEncryptedOMA)(rawData, trackInfo, codec);
16
- // Step 2 - write track to the database
17
- const globalTrackIndex = database.addNewTrack({
18
- ...trackInfo,
19
- trackDuration: encryptedOMA.duration,
20
- }, codec);
21
- // Step 3 - write track to the filesystem
22
- const fh = await database.database.filesystem.open(resolvePathFromGlobalIndex(globalTrackIndex), 'rw');
23
- const data = encryptedOMA.data;
24
- let remaining = data.length;
25
- let i = 0;
26
- callback === null || callback === void 0 ? void 0 : callback(i, data.length);
27
- while (remaining) {
28
- const toWrite = Math.min(2048, remaining);
29
- await fh.write(data.slice(i, i + toWrite));
30
- i += toWrite;
31
- remaining -= toWrite;
32
- callback === null || callback === void 0 ? void 0 : callback(i, data.length);
33
- }
34
- await fh.close();
35
- // Step 4 - write MAC
36
- session.writeTrackMac(globalTrackIndex - 1, encryptedOMA.maclistValue);
37
- }
38
- exports.uploadTrack = uploadTrack;
39
- async function createNWJSFS(webUsbDevice, bypassCoherencyChecks) {
40
- // Connect into the HiMD codebase
41
- const fs = new filesystem_1.UMSCNWJSFilesystem(webUsbDevice);
42
- await fs.init();
43
- await (0, initialization_1.initializeIfNeeded)(fs);
44
- return fs;
45
- }
46
- exports.createNWJSFS = createNWJSFS;
47
- async function openNewDeviceNode() {
48
- let legacyDevice, devName = null;
49
- for (let dev of devices_1.DeviceIds) {
50
- legacyDevice = (0, usb_1.findByIds)(dev.vendorId, dev.productId);
51
- if (legacyDevice) {
52
- devName = dev.name;
53
- break;
54
- }
55
- }
56
- if (!legacyDevice) {
57
- return null;
58
- }
59
- legacyDevice.open();
60
- await new Promise(res => legacyDevice.reset(res));
61
- const iface = legacyDevice.interface(0);
62
- try {
63
- if (iface.isKernelDriverActive())
64
- iface.detachKernelDriver();
65
- }
66
- catch (ex) {
67
- // console.log("Couldn't detach the kernel driver. Expected on Windows.");
68
- }
69
- const webUsbDevice = (await usb_1.WebUSBDevice.createInstance(legacyDevice));
70
- await webUsbDevice.open();
71
- return { dev: webUsbDevice, name: devName };
72
- }
73
- exports.openNewDeviceNode = openNewDeviceNode;