trackparse 0.2.1 → 0.3.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/README.md CHANGED
@@ -7,9 +7,11 @@ Parse music track names into structured metadata: artists, featured artists, rem
7
7
  [![js](https://img.shields.io/github/actions/workflow/status/4matic/trackparse/js.yml?branch=main&label=js)](https://github.com/4matic/trackparse/actions/workflows/js.yml)
8
8
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/4matic/trackparse/blob/main/LICENSE)
9
9
 
10
+ **[Documentation](https://4matic.github.io/trackparse/)** · **[Playground](https://4matic.github.io/trackparse/playground/)**
11
+
10
12
  This is the JavaScript/TypeScript reference implementation of the
11
13
  [trackparse spec](https://github.com/4matic/trackparse/blob/main/spec/SPEC.md). It passes all
12
- 15,000+ shared fixtures. Zero dependencies, ESM and CommonJS, TypeScript types included, never
14
+ 12,965 shared fixtures. Zero dependencies, ESM and CommonJS, TypeScript types included, never
13
15
  throws.
14
16
 
15
17
  The principle is **extract, don't delete**: everything recognised lands in a field (artists with
@@ -127,13 +129,13 @@ r.junk; // [ { raw: 'Full Album', kind: 'other' } ]
127
129
 
128
130
  ### `SPEC_VERSION`
129
131
 
130
- The spec version this build implements, e.g. `"0.2.0"`. Always equal to the package version.
132
+ The spec version this build implements, e.g. `"0.3.0"`. Always equal to the package version.
131
133
 
132
134
  ## Options
133
135
 
134
136
  | Option | Default | Effect |
135
137
  |---|---|---|
136
- | `mode` | `"auto"` | `"clean"` (tags, store metadata), `"youtube"` (video titles), `"filename"`, or `"auto"` to detect. |
138
+ | `mode` | `"auto"` | `"clean"` (tags, store metadata), `"youtube"` (video titles), `"filename"`, `"tracklist"` (one line of a tracklist), or `"auto"` to detect. |
137
139
  | `uploader` | – | YouTube channel, used as the artist when no separator is found. ` - Topic` and `VEVO` are stripped. |
138
140
  | `knownArtists` | `[]` | Names never split (`Chase & Status`). There is no built-in list. |
139
141
  | `splitAnd` | `"auto"` | `and` splits only after a comma in the same list (`A, B and C`), so `Simon and Garfunkel` stays one. `"always"` / `"never"`. |
@@ -157,7 +159,7 @@ All types are exported (`import type { ParsedTrack } from "trackparse"`).
157
159
  ```ts
158
160
  interface ParsedTrack {
159
161
  input: string; // original, untouched
160
- mode: "clean" | "youtube" | "filename"; // resolved mode
162
+ mode: "clean" | "youtube" | "filename" | "tracklist"; // resolved mode
161
163
  position: { raw: string; number: number } | null;
162
164
  timestamp: { raw: string; seconds: number } | null;
163
165
  artists: Artist[]; // primary, featured, producer (not remixers)
@@ -197,13 +199,97 @@ interface Version {
197
199
  `bySplit`, `quotedTitleSplit`, `ambiguousMixCredit`, `unbalancedBrackets`.
198
200
 
199
201
  The full field reference, a gallery of examples and the comparison with other libraries are in the
200
- [main README](https://github.com/4matic/trackparse#readme). Exact behaviour is defined by the
202
+ [documentation](https://4matic.github.io/trackparse/): [`parse` and ParsedTrack](https://4matic.github.io/trackparse/reference/parse/),
203
+ [options](https://4matic.github.io/trackparse/reference/options/), [warnings](https://4matic.github.io/trackparse/reference/warnings/),
204
+ [what it understands](https://4matic.github.io/trackparse/guides/what-it-understands/). Exact behaviour is defined by the
201
205
  [spec](https://github.com/4matic/trackparse/blob/main/spec/SPEC.md) and its
202
206
  [fixtures](https://github.com/4matic/trackparse/tree/main/spec/fixtures).
203
207
 
208
+ ## Tracklists
209
+
210
+ `trackparse/tracklist` parses a whole tracklist: one entry per line with its kind, start time and
211
+ a full `ParsedTrack`, plus checks with line numbers. Joining `raw + eol` over the entries gives the
212
+ input back byte for byte, whatever the line endings. It's a separate entry point (about 7.6 KiB
213
+ gzipped), so you only pay for it if you import it.
214
+
215
+ ```js
216
+ import { applyEdits, parseTracklist } from "trackparse/tracklist";
217
+ // const { applyEdits, parseTracklist } = require("trackparse/tracklist");
218
+
219
+ const text = [
220
+ "Hour 2",
221
+ "48:20 Noisia - Stigma",
222
+ "52:47 Mefjus & Kasra - Bandwagon (Phace Remix)",
223
+ "56:05 Black Sun Empire - ID",
224
+ "59:31 Alix Perez - Fade Away",
225
+ "01:03:10 Interview with Hybris",
226
+ "01:07:44 Imanu - Sacrifice",
227
+ "00:11:02 Current Value feat. Teddy Killerz - Payload", // typo for 01:11:02
228
+ "01:15:36 Hybris - Spinning Top",
229
+ ].join("\r\n");
230
+
231
+ const list = parseTracklist(text);
232
+
233
+ list.entries.map((e) => e.kind);
234
+ // [ 'header', 'track', 'track', 'track', 'track', 'marker', 'track', 'track', 'track' ]
235
+ list.entries[2].time; // { raw: '52:47', seconds: 3167 }
236
+ list.entries[2].track.versions[0].type; // 'remix'
237
+ list.entries[3].track.flags.unknownTitle; // true
238
+
239
+ list.warnings;
240
+ // [
241
+ // { code: 'no-start-at-zero', line: 2, severity: 'info', suggestion: null },
242
+ // { code: 'time-out-of-order', line: 8, severity: 'warning',
243
+ // suggestion: { line: 8, raw: '01:11:02', seconds: 4262 } }
244
+ // ]
245
+ list.stats;
246
+ // { lines: 9, tracks: 7, markers: 1, timed: 8, firstTime: 2900, lastTime: 4536 }
247
+ ```
248
+
249
+ `applyEdits` rewrites only the lines you name. Times keep their line's style, and the rest of the
250
+ text, CRLF included, stays as it was:
251
+
252
+ ```js
253
+ const fix = list.warnings[1].suggestion;
254
+ const result = applyEdits(text, [
255
+ { op: "set-time", line: fix.line, seconds: fix.seconds },
256
+ { op: "shift", seconds: 45, from: 5 },
257
+ ]);
258
+
259
+ result.changed; // [ 5, 6, 7, 8, 9 ]
260
+ result.warnings; // [ { code: 'style-upgraded', edit: 1, line: 5 } ]
261
+ result.text.split("\r\n")[4]; // '01:00:16 Alix Perez - Fade Away' (was 59:31)
262
+ ```
263
+
264
+ Edits: `set-time {line, seconds}`, `shift {seconds, lines? | from?}`
265
+ (all timed lines when neither is given), `sort-by-time {}`, `set-rest {line, rest}`,
266
+ `insert {after, text}` (`after: 0` inserts at the top), `delete {line}`.
267
+ A bad edit changes nothing and warns `edit-invalid`; a time pushed below zero stops at zero and
268
+ warns `time-clamped`.
269
+
270
+ Warning codes: `time-missing`, `time-out-of-order` (with a one- or two-digit `suggestion` when
271
+ exactly one fix fits), `time-duplicate`, `no-start-at-zero`, `time-after-audio-end` (pass
272
+ `audioSeconds`), `invalid-time`, `position-gap`, `position-duplicate`, `line-unparsed`.
273
+
274
+ Options: `mode` (default `"tracklist"`), `knownArtists`, `splitAnd`, `keywords`, `audioSeconds`,
275
+ `markerWords`. Every type is exported (`import type { Tracklist, Edit } from
276
+ "trackparse/tracklist"`).
277
+
278
+ Each line is parsed with `mode: "tracklist"`, where the first spaced dash always separates artist
279
+ and title. `parse()` takes it too:
280
+
281
+ ```js
282
+ parse("Electrosoul System - Liquid Metal").title; // 'Electrosoul System'
283
+ parse("Electrosoul System - Liquid Metal", { mode: "tracklist" }).title; // 'Liquid Metal'
284
+ ```
285
+
286
+ Field tables and the full list of rules: the [tracklists guide](https://4matic.github.io/trackparse/guides/tracklists/), the
287
+ [Tracklist API](https://4matic.github.io/trackparse/reference/tracklist/) and [SPEC R13](https://github.com/4matic/trackparse/blob/main/spec/SPEC.md#r13-tracklists).
288
+
204
289
  ## Limitations
205
290
 
206
- One track string per call (no multi-line tracklists yet), no label/catalog, key or BPM fields, and
291
+ One track string per `parse()` call; tracklists go through `trackparse/tracklist`, which reads
292
+ start times only (no durations, trailing times or ranges). No label/catalog, key or BPM fields, and
207
293
  no built-in artist database: pass `knownArtists` for names that contain a joiner.
208
294
 
209
295
  ## License