Skip to content

Releases: 4matic/trackparse

spec: v0.2.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 08:20
95d12ae

0.2.0 (2026-10-01)

Features

  • spec: define letter as unicode general category L (5c26379)

python: v0.2.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 08:20
95d12ae

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 trackparse
from 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, passes mypy --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, Python str.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 in separators.json pin it.

Releases and CI

  • js, spec and python now 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.yml workflow: lint, mypy --strict and 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.0

PyPI: https://pypi.org/project/trackparse/0.2.0/ · implements spec 0.2.0 (SPEC.md)

js: v0.2.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 08:20
95d12ae

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 trackparse
from 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, passes mypy --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, Python str.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 in separators.json pin it.

Releases and CI

  • js, spec and python now 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.yml workflow: lint, mypy --strict and 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.0

npm: https://www.npmjs.com/package/trackparse/v/0.2.0 · implements spec 0.2.0 (SPEC.md)

spec: v0.1.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 13:13
c2bd6dd

0.1.0 (2026-09-29)

Features

  • initial trackparse spec, fixtures and js package (cf346e8)

js: v0.1.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 13:13
c2bd6dd

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: 1

Highlights

  • 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 & , x vs / + with and, uses the leftmost feat marker, keeps the joiners so format() can rebuild the string, and never splits AC/DC, 2 Unlimited or Blink-182. Names that must never be split go in knownArtists.
  • 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. parse never 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.0

npm: https://www.npmjs.com/package/trackparse/v/0.1.0 · implements spec 0.1.0 (SPEC.md)