@maxmellon/cue-parser 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 MaxMEllon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,374 @@
1
+ # CUE Parser
2
+
3
+ A TypeScript library for parsing CUE sheet files according to the [CUE Sheet specification](https://wyday.com/cuesharp/specification.php).
4
+
5
+ 🌐 **[Live Demo](https://melocil.de/cue-parser/)** - Try the CUE parser online!
6
+
7
+ ## Features
8
+
9
+ - šŸŽµ Complete CUE sheet parsing support
10
+ - šŸ“ TypeScript type definitions
11
+ - ā±ļø MSF (Minutes:Seconds:Frames) time format utilities
12
+ - 🚨 Comprehensive error handling and validation
13
+ - šŸ“Š Detailed parse results with errors and warnings
14
+ - šŸŽÆ Support for all standard CUE sheet commands
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install cue-parser
20
+ ```
21
+
22
+ ## CLI Usage
23
+
24
+ After installation, you can use the `cue-parser` command directly:
25
+
26
+ ```bash
27
+ # Parse and display a CUE file
28
+ cue-parser album.cue
29
+
30
+ # Output as JSON
31
+ cue-parser album.cue --json
32
+
33
+ # Output as CUE sheet format
34
+ cue-parser album.cue --cue
35
+
36
+ # Output minimal CUE sheet
37
+ cue-parser album.cue --cue --minimal
38
+
39
+ # Validate only (no output)
40
+ cue-parser album.cue --validate
41
+
42
+ # Show parsing statistics
43
+ cue-parser album.cue --stats
44
+
45
+ # Quiet mode (errors only)
46
+ cue-parser album.cue --quiet
47
+
48
+ # Show help
49
+ cue-parser --help
50
+
51
+ # Show version
52
+ cue-parser --version
53
+ ```
54
+
55
+ ### CLI Options
56
+
57
+ - `-h, --help` - Show help message
58
+ - `-v, --version` - Show version
59
+ - `-j, --json` - Output as JSON
60
+ - `-c, --cue` - Output as CUE sheet format
61
+ - `--minimal` - Output minimal CUE sheet (use with --cue)
62
+ - `-q, --quiet` - Only show errors
63
+ - `--validate` - Only validate, don't output parsed content
64
+ - `--stats` - Show parsing statistics
65
+
66
+ ### CLI Examples
67
+
68
+ **Basic parsing:**
69
+ ```bash
70
+ $ cue-parser album.cue
71
+
72
+ šŸ“€ CUE Sheet Information
73
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
74
+ Title: My Album
75
+ Artist: My Artist
76
+ Catalog: 1234567890123
77
+
78
+ šŸŽµ Tracks (3)
79
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
80
+
81
+ [01] Track One
82
+ Mode: AUDIO
83
+ File: audio.wav (WAVE)
84
+ Indexes:
85
+ 01: 00:00:00 (0.00s)
86
+ ```
87
+
88
+ **JSON output:**
89
+ ```bash
90
+ $ cue-parser album.cue --json
91
+ {
92
+ "global": {
93
+ "title": "My Album",
94
+ "performer": "My Artist"
95
+ },
96
+ "tracks": [...]
97
+ }
98
+ ```
99
+
100
+ **CUE format output:**
101
+ ```bash
102
+ $ cue-parser album.cue --cue
103
+ TITLE "My Album"
104
+ PERFORMER "My Artist"
105
+
106
+ FILE "audio.wav" WAVE
107
+ TRACK 01 AUDIO
108
+ TITLE "Track One"
109
+ INDEX 01 00:00:00
110
+ ```
111
+
112
+ **Minimal CUE format:**
113
+ ```bash
114
+ $ cue-parser album.cue --cue --minimal
115
+ TITLE "My Album"
116
+ PERFORMER "My Artist"
117
+ FILE "audio.wav" WAVE
118
+ TRACK 01 AUDIO
119
+ TITLE "Track One"
120
+ INDEX 01 00:00:00
121
+ ```
122
+
123
+ **Validation with statistics:**
124
+ ```bash
125
+ $ cue-parser album.cue --validate --stats
126
+
127
+ āœ… Validation successful
128
+
129
+ šŸ“Š Parsing Statistics
130
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
131
+ āœ… Successfully parsed
132
+ Tracks: 3
133
+ Indexes: 5
134
+ Files referenced: 2
135
+ ```
136
+
137
+ ## Library Usage
138
+
139
+ ### Basic Parsing
140
+
141
+ ```typescript
142
+ import { parseCueSheet } from 'cue-parser';
143
+
144
+ const cueContent = `
145
+ TITLE "Example Album"
146
+ PERFORMER "Example Artist"
147
+ FILE "audio.wav" WAVE
148
+ TRACK 01 AUDIO
149
+ TITLE "Track 1"
150
+ INDEX 01 00:00:00
151
+ `;
152
+
153
+ const result = parseCueSheet(cueContent);
154
+
155
+ if (result.cueSheet) {
156
+ console.log(result.cueSheet.global.title); // "Example Album"
157
+ console.log(result.cueSheet.tracks[0].title); // "Track 1"
158
+ } else {
159
+ console.error('Parse errors:', result.errors);
160
+ }
161
+ ```
162
+
163
+ ### Using the Parser Class
164
+
165
+ ```typescript
166
+ import { CueParser } from 'cue-parser';
167
+
168
+ const parser = new CueParser();
169
+ const result = parser.parse(cueContent);
170
+
171
+ // Check for errors and warnings
172
+ if (result.errors.length > 0) {
173
+ result.errors.forEach(error => {
174
+ console.error(`Line ${error.line}: ${error.message}`);
175
+ });
176
+ }
177
+
178
+ if (result.warnings.length > 0) {
179
+ result.warnings.forEach(warning => {
180
+ console.warn(`Line ${warning.line}: ${warning.message}`);
181
+ });
182
+ }
183
+ ```
184
+
185
+ ### Working with MSF Time Format
186
+
187
+ ```typescript
188
+ import { parseHMSTime, formatHMSTime, hmsToSeconds } from 'cue-parser';
189
+
190
+ // Parse MSF time string
191
+ const time = parseHMSTime('1:30:45'); // { hour: 1, minute: 30, second: 45 }
192
+
193
+ // Format MSF time back to string
194
+ const timeStr = formatHMSTime(time); // "01:30:45"
195
+
196
+ // Convert to seconds
197
+ const totalSeconds = hmsToSeconds(time); // 5445 seconds
198
+ ```
199
+
200
+ ### Serializing CUE Sheets
201
+
202
+ ```typescript
203
+ import { parseCueSheet, serializeCueSheet, formatCueSheet, createMinimalCueSheet } from 'cue-parser';
204
+
205
+ const result = parseCueSheet(cueContent);
206
+
207
+ if (result.cueSheet) {
208
+ // Basic serialization
209
+ const cueString = serializeCueSheet(result.cueSheet);
210
+
211
+ // Formatted with spacing
212
+ const formatted = formatCueSheet(result.cueSheet, { trackSpacing: true });
213
+
214
+ // Minimal version (essential fields only)
215
+ const minimal = createMinimalCueSheet(result.cueSheet);
216
+
217
+ console.log(cueString);
218
+ }
219
+ ```
220
+
221
+ ## Supported CUE Sheet Commands
222
+
223
+ ### Global Commands
224
+ - `CATALOG` - Sets the catalog number of the CD
225
+ - `CDTEXTFILE` - Sets an external file for CD-TEXT data
226
+ - `TITLE` - Title of the album
227
+ - `PERFORMER` - Name(s) of the performer(s)
228
+ - `SONGWRITER` - Name(s) of the songwriter(s)
229
+ - `COMPOSER` - Name(s) of the composer(s)
230
+ - `ARRANGER` - Name(s) of the arranger(s)
231
+ - `MESSAGE` - Message from the content provider and/or artist
232
+ - `DISC_ID` - Disc identification information
233
+ - `GENRE` - Genre identification
234
+ - `UPC_EAN` - UPC/EAN code of the album
235
+ - `REM` - Comment lines
236
+
237
+ ### Track Commands
238
+ - `FILE` - Sets a new input file
239
+ - `TRACK` - Starts a new track
240
+ - `INDEX` - Sets a track index
241
+ - `PREGAP` - Sets track pregap
242
+ - `POSTGAP` - Sets track postgap
243
+ - `FLAGS` - Sets track flags (PRE, DCP, 4CH, SCMS)
244
+ - `ISRC` - Sets track ISRC number
245
+ - `TITLE` - Track title
246
+ - `PERFORMER` - Track performer
247
+ - `SONGWRITER` - Track songwriter
248
+ - `COMPOSER` - Track composer
249
+ - `ARRANGER` - Track arranger
250
+ - `MESSAGE` - Track message
251
+
252
+ ## Supported File Formats
253
+
254
+ - `BINARY`
255
+ - `MOTOROLA`
256
+ - `AIFF`
257
+ - `WAVE`
258
+ - `MP3`
259
+
260
+ ## Supported Track Modes
261
+
262
+ - `AUDIO`
263
+ - `CDG`
264
+ - `MODE1/2048`
265
+ - `MODE1/2352`
266
+ - `MODE2/2336`
267
+ - `MODE2/2352`
268
+ - `CDI/2336`
269
+ - `CDI/2352`
270
+
271
+ ## API Reference
272
+
273
+ ### Types
274
+
275
+ #### `CueSheet`
276
+ The main interface representing a parsed CUE sheet.
277
+
278
+ ```typescript
279
+ interface CueSheet {
280
+ global: CueGlobal;
281
+ tracks: Track[];
282
+ }
283
+ ```
284
+
285
+ #### `ParseResult`
286
+ The result of parsing a CUE sheet.
287
+
288
+ ```typescript
289
+ interface ParseResult {
290
+ cueSheet?: CueSheet;
291
+ errors: ParseError[];
292
+ warnings: ParseError[];
293
+ }
294
+ ```
295
+
296
+ #### `MSFTime`
297
+ Represents time in Minutes:Seconds:Frames format.
298
+
299
+ ```typescript
300
+ interface MSFTime {
301
+ minutes: number;
302
+ seconds: number;
303
+ frames: number; // 0-74 (1/75 of a second)
304
+ }
305
+ ```
306
+
307
+ ### Functions
308
+
309
+ #### `parseCueSheet(content: string): ParseResult`
310
+ Parses a CUE sheet from string content.
311
+
312
+ #### `parseHMSTime(timeString: string): HMSTime`
313
+ Parses an HMS time string (e.g., "1:30:45") into an HMSTime object.
314
+
315
+ #### `formatHMSTime(time: HMSTime, zeroPad?: boolean): string`
316
+ Formats an HMSTime object back to string format.
317
+
318
+ #### `hmsToSeconds(time: HMSTime): number`
319
+ Converts HMS time to total seconds.
320
+
321
+ #### `secondsToHMS(seconds: number): HMSTime`
322
+ Converts seconds to HMS time format.
323
+
324
+ #### `serializeCueSheet(cueSheet: CueSheet): string`
325
+ Serializes a CueSheet object back to CUE sheet format string.
326
+
327
+ #### `formatCueSheet(cueSheet: CueSheet, options?: object): string`
328
+ Formats a CueSheet with proper indentation and spacing options.
329
+
330
+ #### `createMinimalCueSheet(cueSheet: CueSheet): string`
331
+ Creates a minimal CUE sheet with only essential information.
332
+
333
+ ## Error Handling
334
+
335
+ The parser provides detailed error information including line numbers and descriptions:
336
+
337
+ ```typescript
338
+ const result = parseCueSheet(invalidContent);
339
+
340
+ if (result.errors.length > 0) {
341
+ result.errors.forEach(error => {
342
+ console.error(`Parse error on line ${error.line}: ${error.message}`);
343
+ console.error(`Raw line: ${error.rawLine}`);
344
+ });
345
+ }
346
+ ```
347
+
348
+ ## Examples
349
+
350
+ See the `examples/` directory for sample CUE files and usage examples.
351
+
352
+ ## Development
353
+
354
+ ```bash
355
+ # Install dependencies
356
+ npm install
357
+
358
+ # Build the project
359
+ npm run build
360
+
361
+ # Run tests
362
+ npm test
363
+
364
+ # Watch mode for development
365
+ npm run dev
366
+ ```
367
+
368
+ ## License
369
+
370
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
371
+
372
+ ## Contributing
373
+
374
+ Contributions are welcome! Please feel free to submit a Pull Request.
package/bin/index.js ADDED
@@ -0,0 +1,283 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync, existsSync } from 'fs';
4
+ import { resolve } from 'path';
5
+ import { parseCueSheet, formatHMSTime, hmsToSeconds, serializeCueSheet, formatCueSheet, createMinimalCueSheet, serializeYouTubeTimeline } from '../dist/src/index.js';
6
+
7
+ /**
8
+ * CUE Parser CLI
9
+ */
10
+
11
+ function showHelp() {
12
+ console.log(`
13
+ CUE Parser CLI
14
+
15
+ Usage:
16
+ cue-parser <file.cue> [options]
17
+
18
+ Options:
19
+ -h, --help Show this help message
20
+ -v, --version Show version
21
+ -j, --json Output as JSON
22
+ -c, --cue Output as CUE sheet format
23
+ --minimal Output minimal CUE sheet (with --cue)
24
+ -q, --quiet Only show errors
25
+ --validate Only validate, don't output parsed content
26
+ --stats Show parsing statistics
27
+ --youtube Output YouTube timeline format
28
+
29
+ Examples:
30
+ cue-parser album.cue
31
+ cue-parser album.cue --json
32
+ cue-parser album.cue --cue
33
+ cue-parser album.cue --cue --minimal
34
+ cue-parser album.cue --validate
35
+ cue-parser album.cue --stats
36
+ cue-parser album.cue --youtube
37
+ `);
38
+ }
39
+
40
+ function showVersion() {
41
+ try {
42
+ const packageJson = JSON.parse(readFileSync(resolve(new URL(import.meta.url).pathname, '../../package.json'), 'utf-8'));
43
+ console.log(`cue-parser v${packageJson.version}`);
44
+ } catch (error) {
45
+ console.log('cue-parser (version unknown)');
46
+ }
47
+ }
48
+
49
+ function formatTime(time) {
50
+ if (!time) return 'N/A';
51
+ const timeStr = formatHMSTime(time);
52
+ const seconds = msfToSeconds(time);
53
+ return `${timeStr} (${seconds.toFixed(2)}s)`;
54
+ }
55
+
56
+ function displayYouTubeTimeline(cueSheet) {
57
+ console.log(serializeYouTubeTimeline(cueSheet));
58
+ }function displayCueSheet(cueSheet, options = {}) {
59
+ if (options.json) {
60
+ console.log(JSON.stringify(cueSheet, null, 2));
61
+ return;
62
+ }
63
+
64
+ if (options.youtube) {
65
+ displayYouTubeTimeline(cueSheet);
66
+ return;
67
+ }
68
+
69
+ if (options.cue) {
70
+ if (options.minimal) {
71
+ console.log(createMinimalCueSheet(cueSheet));
72
+ } else {
73
+ console.log(formatCueSheet(cueSheet, { trackSpacing: true }));
74
+ }
75
+ return;
76
+ }
77
+
78
+ // Display global information
79
+ console.log('šŸ“€ CUE Sheet Information');
80
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
81
+
82
+ const global = cueSheet.global;
83
+ if (global.title) console.log(`Title: ${global.title}`);
84
+ if (global.performer) console.log(`Artist: ${global.performer}`);
85
+ if (global.songwriter) console.log(`Songwriter: ${global.songwriter}`);
86
+ if (global.composer) console.log(`Composer: ${global.composer}`);
87
+ if (global.arranger) console.log(`Arranger: ${global.arranger}`);
88
+ if (global.catalog) console.log(`Catalog: ${global.catalog}`);
89
+ if (global.cdTextFile) console.log(`CD-TEXT: ${global.cdTextFile}`);
90
+ if (global.genre) console.log(`Genre: ${global.genre}`);
91
+ if (global.upcEan) console.log(`UPC/EAN: ${global.upcEan}`);
92
+ if (global.message) console.log(`Message: ${global.message}`);
93
+
94
+ console.log(`\nšŸŽµ Tracks (${cueSheet.tracks.length})`);
95
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
96
+
97
+ cueSheet.tracks.forEach((track, index) => {
98
+ console.log(`\n[${track.number.toString().padStart(2, '0')}] ${track.title || 'Untitled'}`);
99
+ console.log(` Mode: ${track.mode}`);
100
+
101
+ if (track.performer && track.performer !== global.performer) {
102
+ console.log(` Artist: ${track.performer}`);
103
+ }
104
+ if (track.songwriter) console.log(` Songwriter: ${track.songwriter}`);
105
+ if (track.composer) console.log(` Composer: ${track.composer}`);
106
+ if (track.arranger) console.log(` Arranger: ${track.arranger}`);
107
+ if (track.isrc) console.log(` ISRC: ${track.isrc}`);
108
+ if (track.message) console.log(` Message: ${track.message}`);
109
+
110
+ if (track.file) {
111
+ console.log(` File: ${track.file.filename}${track.file.format ? ` (${track.file.format})` : ''}`);
112
+ }
113
+
114
+ if (track.flags && track.flags.length > 0) {
115
+ console.log(` Flags: ${track.flags.join(', ')}`);
116
+ }
117
+
118
+ if (track.pregap) {
119
+ console.log(` Pregap: ${formatTime(track.pregap)}`);
120
+ }
121
+
122
+ if (track.indexes && track.indexes.length > 0) {
123
+ console.log(' Indexes:');
124
+ track.indexes.forEach(idx => {
125
+ console.log(` ${idx.number.toString().padStart(2, '0')}: ${formatTime(idx.time)}`);
126
+ });
127
+ }
128
+
129
+ if (track.postgap) {
130
+ console.log(` Postgap: ${formatTime(track.postgap)}`);
131
+ }
132
+ });
133
+ }
134
+
135
+ function displayStats(result, options = {}) {
136
+ const { cueSheet, errors, warnings } = result;
137
+
138
+ console.log('\nšŸ“Š Parsing Statistics');
139
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
140
+
141
+ if (cueSheet) {
142
+ console.log(`āœ… Successfully parsed`);
143
+ console.log(` Tracks: ${cueSheet.tracks.length}`);
144
+
145
+ const totalIndexes = cueSheet.tracks.reduce((sum, track) =>
146
+ sum + (track.indexes ? track.indexes.length : 0), 0);
147
+ console.log(` Indexes: ${totalIndexes}`);
148
+
149
+ const filesUsed = new Set(cueSheet.tracks
150
+ .map(track => track.file?.filename)
151
+ .filter(Boolean));
152
+ console.log(` Files referenced: ${filesUsed.size}`);
153
+
154
+ // Calculate total duration if possible
155
+ const lastTrack = cueSheet.tracks[cueSheet.tracks.length - 1];
156
+ if (lastTrack?.indexes && lastTrack.indexes.length > 0) {
157
+ const lastIndex = lastTrack.indexes[lastTrack.indexes.length - 1];
158
+ if (lastIndex.time) {
159
+ console.log(` Approximate duration: ${formatTime(lastIndex.time)}`);
160
+ }
161
+ }
162
+ } else {
163
+ console.log(`āŒ Parsing failed`);
164
+ }
165
+
166
+ if (warnings.length > 0) {
167
+ console.log(`āš ļø Warnings: ${warnings.length}`);
168
+ }
169
+
170
+ if (errors.length > 0) {
171
+ console.log(`🚨 Errors: ${errors.length}`);
172
+ }
173
+ }
174
+
175
+ function displayErrors(errors, warnings, options = {}) {
176
+ if (warnings.length > 0 && !options.quiet) {
177
+ console.log('\nāš ļø Warnings:');
178
+ warnings.forEach(warning => {
179
+ console.log(` Line ${warning.line}: ${warning.message}`);
180
+ });
181
+ }
182
+
183
+ if (errors.length > 0) {
184
+ console.log('\n🚨 Errors:');
185
+ errors.forEach(error => {
186
+ console.log(` Line ${error.line}: ${error.message}`);
187
+ if (!options.quiet && error.rawLine.trim()) {
188
+ console.log(` → ${error.rawLine.trim()}`);
189
+ }
190
+ });
191
+ }
192
+ }
193
+
194
+ async function main() {
195
+ const args = process.argv.slice(2);
196
+
197
+ if (args.length === 0 || args.includes('-h') || args.includes('--help')) {
198
+ showHelp();
199
+ process.exit(0);
200
+ }
201
+
202
+ if (args.includes('-v') || args.includes('--version')) {
203
+ showVersion();
204
+ process.exit(0);
205
+ }
206
+
207
+ const options = {
208
+ json: args.includes('-j') || args.includes('--json'),
209
+ cue: args.includes('-c') || args.includes('--cue'),
210
+ minimal: args.includes('--minimal'),
211
+ quiet: args.includes('-q') || args.includes('--quiet'),
212
+ validate: args.includes('--validate'),
213
+ stats: args.includes('--stats'),
214
+ youtube: args.includes('--youtube')
215
+ };
216
+
217
+ // Find the file path (first non-option argument)
218
+ const filePath = args.find(arg => !arg.startsWith('-'));
219
+
220
+ if (!filePath) {
221
+ console.error('āŒ Error: No input file specified');
222
+ console.error('Use --help for usage information');
223
+ process.exit(1);
224
+ }
225
+
226
+ const resolvedPath = resolve(filePath);
227
+
228
+ if (!existsSync(resolvedPath)) {
229
+ console.error(`āŒ Error: File not found: ${resolvedPath}`);
230
+ process.exit(1);
231
+ }
232
+
233
+ try {
234
+ const content = readFileSync(resolvedPath, 'utf-8');
235
+ const result = parseCueSheet(content);
236
+
237
+ // Always show errors
238
+ if (result.errors.length > 0 || result.warnings.length > 0) {
239
+ displayErrors(result.errors, result.warnings, options);
240
+ }
241
+
242
+ // Exit with error code if parsing failed
243
+ if (result.errors.length > 0) {
244
+ if (options.validate) {
245
+ console.log('\nāŒ Validation failed');
246
+ }
247
+ process.exit(1);
248
+ }
249
+
250
+ if (options.validate) {
251
+ console.log('\nāœ… Validation successful');
252
+ if (options.stats) {
253
+ displayStats(result, options);
254
+ }
255
+ process.exit(0);
256
+ }
257
+
258
+ if (result.cueSheet) {
259
+ if (!options.quiet) {
260
+ displayCueSheet(result.cueSheet, options);
261
+ }
262
+
263
+ if (options.stats) {
264
+ displayStats(result, options);
265
+ }
266
+ }
267
+
268
+ process.exit(0);
269
+
270
+ } catch (error) {
271
+ console.error(`āŒ Error reading file: ${error.message}`);
272
+ process.exit(1);
273
+ }
274
+ }
275
+
276
+ // Handle unhandled promise rejections
277
+ process.on('unhandledRejection', (error) => {
278
+ console.error('āŒ Unhandled error:', error);
279
+ process.exit(1);
280
+ });
281
+
282
+ // Run the CLI
283
+ main();
@@ -0,0 +1,31 @@
1
+ /**
2
+ * CUE Sheet Parser
3
+ *
4
+ * A TypeScript library for parsing CUE sheet files according to the specification.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { parseCueSheet, CueParser } from 'cue-parser';
9
+ *
10
+ * const cueContent = `
11
+ * TITLE "Example Album"
12
+ * PERFORMER "Example Artist"
13
+ * FILE "audio.wav" WAVE
14
+ * TRACK 01 AUDIO
15
+ * TITLE "Track 1"
16
+ * INDEX 01 00:00:00
17
+ * `;
18
+ *
19
+ * const result = parseCueSheet(cueContent);
20
+ * if (result.cueSheet) {
21
+ * console.log(result.cueSheet.global.title); // "Example Album"
22
+ * console.log(result.cueSheet.tracks[0].title); // "Track 1"
23
+ * }
24
+ * ```
25
+ */
26
+ export type { HMSTime, TrackFlag, TrackMode, FileFormat, CDText, TrackIndex, FileInfo, Track, CueGlobal, CueSheet, ParseError, ParseResult } from './types.js';
27
+ export { parseHMSTime, formatHMSTime, formatCueTime, hmsToSeconds, secondsToHMS, msfToFrames, framesToMSF, addHMSTime, subtractHMSTime, compareHMSTime } from './utils.js';
28
+ export { CueParser, parseCueSheet } from './parser.js';
29
+ export { serializeCueSheet, formatCueSheet, createMinimalCueSheet } from './serializer.js';
30
+ export { serializeYouTubeTimeline } from './youtube-serializer.js';
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,YAAY,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,UAAU,EACV,MAAM,EACN,UAAU,EACV,QAAQ,EACR,KAAK,EACL,SAAS,EACT,QAAQ,EACR,UAAU,EACV,WAAW,EACZ,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGvD,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACtB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC"}