-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.js
121 lines (105 loc) · 2.76 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
const fs = require("fs");
const pathType = require("path-type");
// List of crate tags in hex
const crateStart = Buffer.from([
0x00,
0x53,
0x00,
0x65,
0x00,
0x72,
0x00,
0x61,
0x00,
0x74,
0x00,
0x6f
]), // Serato
osrt = Buffer.from([0x6f, 0x73, 0x72, 0x74]),
columnSortEnd = Buffer.from([0x00, 0x00, 0x00, 0x01, 0x00]),
tvcn = Buffer.from([0x74, 0x76, 0x63, 0x6e]),
brev = Buffer.from([0x62, 0x72, 0x65, 0x76]),
ovct = Buffer.from([0x6f, 0x76, 0x63, 0x74]),
tvcw = Buffer.from([0x74, 0x76, 0x63, 0x77]),
otrk = Buffer.from([0x70, 0x74, 0x72, 0x6b]),
ptrk = Buffer.from([0x70, 0x74, 0x72, 0x6b]);
const processColumns = crateFile => {
var pointer = crateFile.indexOf(ovct) + 16; // Advance to the start of the data of first column
var columnEnd = crateFile.indexOf(tvcw, pointer); // Get position of first column ending
let columns = [];
while (true) {
// Get column name
let column = crateFile
.slice(pointer, columnEnd)
.swap16()
.toString("utf16le");
columns.push(column);
// Advance to next position of column name
pointer = crateFile.indexOf(ovct, columnEnd);
if (pointer == -1) {
break;
}
pointer += 16;
columnEnd = crateFile.indexOf(tvcw, pointer);
}
return columns;
};
const processSongs = crateFile => {
var pointer = crateFile.indexOf(ptrk) + 8; // Advance to start of song info
var songEnd = crateFile.indexOf(otrk, pointer) - 8; // Get end of first song
let songs = [];
while (true) {
// Get song name
let song = crateFile
.slice(pointer, songEnd)
.swap16()
.toString("utf16le");
songs.push(song);
// Advance to start of next song
pointer = crateFile.indexOf(ptrk, songEnd);
if (pointer == -1) {
break;
}
pointer += 8;
// Advance to end of next song
songEnd = crateFile.indexOf(otrk, pointer);
if (songEnd == -1) {
songEnd = crateFile.length;
} else {
songEnd = crateFile.indexOf(otrk, pointer) - 8;
}
}
return songs;
};
module.exports = fp => {
return pathType.file(fp).then(isFile => {
var crate = {};
if (isFile) {
let crateFile = fs.readFileSync(fp);
if (crateFile.indexOf(crateStart) === -1) {
// File is not a Serato crate
throw "File is not a Serato crate.";
}
crate.columns = processColumns(crateFile);
crate.songs = processSongs(crateFile);
return crate;
} else {
throw "Path is a directory or can't be found.";
}
});
};
module.exports.sync = fp => {
if (pathType.fileSync(fp)) {
let crate = {};
let crateFile = fs.readFileSync(fp);
if (crateFile.indexOf(crateStart) === -1) {
// File is not a Serato crate
throw "File is not a Serato crate.";
}
crate.columns = processColumns(crateFile);
crate.songs = processSongs(crateFile);
return crate;
} else {
throw "Path is a directory or can't be found.";
}
};