Skip to content

parse and ParsedTrack

parse(input: string, options?: ParseOptions): ParsedTrack

parse never throws on a string. Any string gives a ParsedTrack, and unknown or malformed options fall back to their defaults. (Python raises TypeError if input isn't a str at all.) The options are on the Options page.

Every key is always present. Python has the same fields as attributes of a frozen dataclass, in snake_case (full_title, flags.unknown_artist), with tuples instead of arrays and None instead of null.

Field Type
input string The original string, untouched (not normalised)
mode "clean" | "youtube" | "filename" | "tracklist" The mode that actually ran
position { raw: string, number: number } | null Track number. raw is the digits as written ("01")
timestamp { raw: string, seconds: number } | null Leading cue time, "1:02:03" → 3723
artists Artist[] Primary, featured and producer credits. Remixers are in versions
title string The clean title. Brackets it doesn't recognise stay in
fullTitle string title with the versions put back in their original brackets
versions Version[] Remixes and versions, left to right
year number | null From (2015) or - 2015
flags { explicit, clean, unknownArtist, unknownTitle } All booleans
junk { raw: string, kind: JunkKind }[] What was taken out of the title, and what kind of noise it was
warnings Warning[] Which heuristics fired. See Warnings
{ name: string; role: ArtistRole; joiner: string | null; source: ArtistSource }
Field Values
role primary, featured, remixer, producer
joiner the text before the name as written ("&", ",", "ft.", "prod. by"), or null for the first name in a list
source artist (left of the dash), title (right of it), version (inside a version)

&, x and vs. are joiners, not roles. Everyone they join is primary.

{
type: VersionType;
raw: string;
artists: Artist[];
modifiers: VersionType[];
descriptor: string | null;
year: number | null;
unknownArtist: boolean;
delimiter: "(" | "[" | "{" | "-";
}
Field
type one of remix bootleg vip edit flip refix rework mashup blend dub mix extended radio club original instrumental acapella live acoustic remaster demo reprise cover version spedUp slowed nightcore
raw the text inside the brackets, as written
artists remixers (role remixer, source version)
modifiers type words that didn't become the type: Extended VIP Mix → vip, ["extended"]
descriptor leftover words: "Taylor's", "at Wembley", "D'n'B"
year a year inside the version: Remastered 2015 → 2015
unknownArtist true for ID Remix and the like
delimiter the bracket it was in, or - for a dash suffix

Versions and remixes explains how the type is chosen.

video, audio, lyrics, quality, promo, platform, label, genre, other. Examples are in Junk, flags and prefixes. The vocabulary is in spec/data.

In JavaScript the result is a plain object, so JSON.stringify(track) is the spec's JSON.

In Python, ParsedTrack, Artist, Version, Junk, Flags, Position and Timestamp are frozen dataclasses. Sequences are tuples, so results are immutable and hashable: you can put them in sets or use them as dict keys. to_dict() gives the spec's JSON with its camelCase keys, and from_dict() goes the other way:

import json
json.dumps(track.to_dict(), separators=(",", ":"), ensure_ascii=False)
# the same bytes as JSON.stringify(parse(s)) in JavaScript
ParsedTrack.from_dict(track.to_dict()) == track # True

All of these are exported from trackparse as TypeScript types:

ParsedTrack, Artist, ArtistRole, ArtistSource, Version, VersionType, VersionDelimiter, Junk, JunkKind, Flags, Position, Timestamp, Warning, Mode, ModeOption, ParseOptions, KeywordOptions, FormatOptions.

The JSON shape is also published as a JSON Schema, parsed-track.schema.json.