Repository navigation
Releases: 4matic/trackparse
Release list
spec: v0.2.0
python: v0.2.0
trackparse is now on PyPI. The Python port parses track strings exactly like the npm package: it passes the same 11,891 fixtures, and its JSON output is byte-identical to the JS package for every one of them.
pip install trackparse # or: uv add trackparsefrom trackparse import parse, format_track
track = parse("01. Wilkinson ft. Becky Hill & Tom Cane - Afterglow (Sub Focus VIP Remix) [Official Video]")
[f"{a.name} ({a.role})" for a in track.artists]
# ['Wilkinson (primary)', 'Becky Hill (featured)', 'Tom Cane (featured)']
track.title # 'Afterglow'
track.versions[0].artists[0].name # 'Sub Focus'
track.versions[0].modifiers # ('vip',)
track.junk # (Junk(raw='Official Video', kind='video'),)
format_track(track, joiners="canonical")
# 'Wilkinson feat. Becky Hill & Tom Cane - Afterglow (Sub Focus VIP Remix)'Python
- Python 3.9 to 3.14, no dependencies, typed (
py.typed, passesmypy --strict). parse,parse_artists,format_track,normalize,all_artists,create_parser,SPEC_VERSION. Options are keyword arguments (known_artists=[...]).- Results are frozen dataclasses with snake_case attributes and tuples.
to_dict()returns the spec's camelCase JSON, the same as the JS package. - Checked against JS on the full output of every fixture (
scripts/compare-ports.mjs, 0 differences). - Full API: python/README.md.
Spec
- R0.6 now defines "letter" as Unicode general category L (JS
/\p{L}/u, Pythonstr.isalpha()) instead of Unicode Alphabetic, which Python can't test directly. Letter numbers such asⅠand combining marks no longer count as letters. Only the unspaced-dash split (R6.7, youtube and filename modes) uses this test. Two new fixtures inseparators.jsonpin it.
Releases and CI
js,specandpythonnow share one version and release together. Tags:js-v0.2.0,spec-v0.2.0,python-v0.2.0.- PyPI publishing uses trusted publishing (OIDC, no stored token) with attestations. The wheel and sdist are attached to the GitHub Release.
- New
python.ymlworkflow: lint,mypy --strictand the full test suite on Python 3.9 to 3.14, plus every fixture run against the built wheel in a clean venv.
Changelog
0.2.0 (2026-10-01)
Features
- initial trackparse spec, fixtures and js package (cf346e8)
- python: add the python port of trackparse (a618a42)
Install (Python)
pip install trackparse==0.2.0PyPI: https://pypi.org/project/trackparse/0.2.0/ · implements spec 0.2.0 (SPEC.md)
js: v0.2.0
trackparse is now on PyPI. The Python port parses track strings exactly like the npm package: it passes the same 11,891 fixtures, and its JSON output is byte-identical to the JS package for every one of them.
pip install trackparse # or: uv add trackparsefrom trackparse import parse, format_track
track = parse("01. Wilkinson ft. Becky Hill & Tom Cane - Afterglow (Sub Focus VIP Remix) [Official Video]")
[f"{a.name} ({a.role})" for a in track.artists]
# ['Wilkinson (primary)', 'Becky Hill (featured)', 'Tom Cane (featured)']
track.title # 'Afterglow'
track.versions[0].artists[0].name # 'Sub Focus'
track.versions[0].modifiers # ('vip',)
track.junk # (Junk(raw='Official Video', kind='video'),)
format_track(track, joiners="canonical")
# 'Wilkinson feat. Becky Hill & Tom Cane - Afterglow (Sub Focus VIP Remix)'Python
- Python 3.9 to 3.14, no dependencies, typed (
py.typed, passesmypy --strict). parse,parse_artists,format_track,normalize,all_artists,create_parser,SPEC_VERSION. Options are keyword arguments (known_artists=[...]).- Results are frozen dataclasses with snake_case attributes and tuples.
to_dict()returns the spec's camelCase JSON, the same as the JS package. - Checked against JS on the full output of every fixture (
scripts/compare-ports.mjs, 0 differences). - Full API: python/README.md.
Spec
- R0.6 now defines "letter" as Unicode general category L (JS
/\p{L}/u, Pythonstr.isalpha()) instead of Unicode Alphabetic, which Python can't test directly. Letter numbers such asⅠand combining marks no longer count as letters. Only the unspaced-dash split (R6.7, youtube and filename modes) uses this test. Two new fixtures inseparators.jsonpin it.
Releases and CI
js,specandpythonnow share one version and release together. Tags:js-v0.2.0,spec-v0.2.0,python-v0.2.0.- PyPI publishing uses trusted publishing (OIDC, no stored token) with attestations. The wheel and sdist are attached to the GitHub Release.
- New
python.ymlworkflow: lint,mypy --strictand the full test suite on Python 3.9 to 3.14, plus every fixture run against the built wheel in a clean venv.
Changelog
0.2.0 (2026-10-01)
Features
- spec: define letter as unicode general category L (5c26379)
Bug Fixes
- js: never throw on malformed knownArtists or keyword options (f6cd454)
Performance
- js: strip trailing junk in linear time (53557b1)
Install
npm install trackparse@0.2.0npm: https://www.npmjs.com/package/trackparse/v/0.2.0 · implements spec 0.2.0 (SPEC.md)
spec: v0.1.0
js: v0.1.0
First public release of trackparse, a parser that turns music track strings into structured metadata. The spec behind it is shared by every port.
import { parse } from "trackparse";
parse("01. Wilkinson ft. Becky Hill - Afterglow (Sub Focus VIP Remix) [Official Video]");
// artists: Wilkinson (primary), Becky Hill (featured, "ft.")
// title: "Afterglow"
// versions: remix by Sub Focus, modifiers ["vip"]
// junk: "Official Video" (video) · position: 1Highlights
- Extract, don't delete. Featured artists, remixers, producers, version type (remix, VIP, bootleg, extended, radio, original, live, remaster with year, sped up…), explicit/clean flags, track numbers, timestamps and junk ("Official Video", "4K", "Free Download") each come back as their own field, next to a clean title.
- Artists as a list. Splits on
&,xvs/+withand, uses the leftmost feat marker, keeps the joiners soformat()can rebuild the string, and never splitsAC/DC,2 UnlimitedorBlink-182. Names that must never be split go inknownArtists. - Modes for store titles, YouTube titles (pipes,
by, quoted titles, uploader fallback) and filenames. - Unicode-aware. NFC, every dash and bracket variant, Cyrillic, CJK and diacritics, with diacritic-insensitive dedup.
- Zero dependencies. ESM + CJS + TypeScript types, Node ≥ 18.
parsenever throws.
Spec 0.1.0
spec/SPEC.md: rules R0–R12 written to be portable (hand-written scanners, no regex lookaround), so the JS, Python and Rust ports can give byte-identical output.- 11,889 shared fixtures: 898 handwritten (including regressions from real-world parsers) and 10,991 from a combinatorial generator whose expected values are built from ground-truth atoms, not from the parser.
- The JS reference implementation passes all of them with an empty skip list.
Python (PyPI) and Rust (crates.io) ports are planned against the same fixtures.
Changelog
0.1.0 (2026-09-29)
Features
- initial trackparse spec, fixtures and js package (cf346e8)
Install
npm install trackparse@0.1.0npm: https://www.npmjs.com/package/trackparse/v/0.1.0 · implements spec 0.1.0 (SPEC.md)