Skip to main content

tile-twinx

Takes a raw YouTube title and splits it into artist, title and extras.

$ uv run app.py --json "Marshmello - Alone (Official Music Video)"
{"artist": "Marshmello", "title": "Alone", "extras": ["Official Music Video"]}

Install

uv add tile-twinx

OR

pip install tile-twinx
from Tile import parse_title

parse_title("Kesariya - Arijit Singh | T-Series | 2023")
# {'artist': 'Arijit Singh', 'title': 'Kesariya', 'extras': ['T-Series', '2023']}

No dependencies, Python 3.12+.

The demo app

app.py runs a list of real YouTube titles through the parser and prints a table. With no arguments it uses its built-in list of 29 titles:

uv run app.py                                   # the built-in list
uv run app.py "Alan Walker - Faded"             # one title
uv run app.py --file my_titles.txt              # a file, one title per line
yt-dlp --print "%(title)s" URL | uv run app.py  # straight from yt-dlp
uv run app.py --random 5                        # 5 random ones
uv run app.py --interactive                     # type titles by hand
  ARTIST  TITLE  EXTRAS
  --------------------------  ----------------------------------  ----------------------
  Marshmello                  Alone                               Official Music Video
  Kesariya                    Kesariya                            Full Song, 4K, 1080p, HD
  Arijit Singh                Kesariya                            T-Series, 2023
  ...

  parsed 29 titles
  artist found 29/29  100%
  extras found 25/29  86%

Flags: --json, --dict, --explain (why the parser decided what it did), --summary, --colour auto|always|never. uv run app.py --help lists them all.

app.py doubles as a smoke test: it holds 29 real titles whose expected output is in the table above, so if a parser change breaks something it shows up there.

Library

from Tile import parse_title, get_context

parse_title("Marshmello - Alone (Official Music Video)")
# {'artist': 'Marshmello', 'title': 'Alone', 'extras': ['Official Music Video']}

parse_title(raw, explain=True)        # adds a "debug" list of decision notes
ctx = get_context("~/my-ignore.txt", "~/my-artists.txt")   # your own data files
parse_title(raw, ctx)

Tile also exports build_context, Context, Segment and Token for anyone poking at the internals. get_context caches by mtime and reloads automatically when a data file changes.

Files

Path Purpose
main.py the whole engine plus its CLI - still the single source of truth
assets/ignore.txt junk words/phrases to strip (4k, lyric, official ...)
assets/artist.txt artist names, Main Name | Alias per line
Tile/__init__.py the public API, from Tile import ...
app.py the demo app

main.py stays in the repo root; the wheel ships that same file as Tile/main.py so it installs inside the package, and Tile/__init__.py supports both layouts. The checkout and an installed copy behave identically.

Both data files are re-read whenever they change, no restart needed. # starts a comment in either one.

How it decides

  1. Clean - unescape &, normalise unicode, unify dashes and quotes, split the title into chunks on -, |, •.
  2. Brackets - each (...) / [...] / {...} group is either metadata ((Official Video), (feat. X), (from "Album")) or real title text ((Humming)). A group whose every word is junk becomes an extra.
  3. Junk - ignore.txt words go anywhere, except the handful that also start or end real titles (old, song, video, full, audio, ...), which are only removed next to other junk. That is what keeps Old Town Road and Video Games intact while Song 4K still loses its junk.
  4. Credits - feat./ft./prod./cover by/from "..." are pulled out before junk removal, then folded into the artist.
  5. Artist - the best artist.txt match: a chunk that is the artist beats one that merely contains the name, the earlier chunk beats a later one, and within a chunk the longest match wins. It then extends over x, &, , and feat. collaborators. Without a match it falls back to the first chunk, then a Song by Artist form, then the last chunk.
  6. Title - whatever is left, with extras in the order they appeared.

Adding to the data files

# ignore.txt - a single word is stripped anywhere, a phrase too
official teaser          # safe anywhere: never part of a title

# artist.txt - aliases after a pipe, matched without case or accents
Alan Walker | Alan W.

# artist.txt - "!" marks a channel or label, never a performer
!Saregama

A label in its own chunk becomes an extra, so Kesariya - Arijit Singh | T-Series | 2023 gives Arijit Singh / Kesariya / ["T-Series", "2023"], while T-Series - Kesariya still credits T-Series as the artist.

Run uv run app.py after editing: it reloads the data files, so a regression shows up immediately in the table.

Known limits

  • An unspaced dash is never a separator (Marshmello-Alone-Official stays one word), because Spider-Man and Merry-Go-Round outnumber the broken form.
  • When a title and its artist are both unknown and both are short, the first chunk is taken as the artist. Adding the name to assets/artist.txt fixes the whole family of titles at once.

Publishing

uv build                                  # dist/*.whl + dist/*.tar.gz
twine check dist/*                        # verify metadata without uploading
uv publish                                # needs a token in ~/.pypirc or UV_PUBLISH_TOKEN

Distribution name tile-twinx, import name Tile.

Metadata

Release files for tile-twinx 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tile-twinx 1.0.0
File Size Uploaded
tile_twinx-1.0.0.tar.gz 36.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tile-twinx 1.0.0
File Interpreter ABI Platform
tile_twinx-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 70.4 kB

Release files / tile_twinx-1.0.0.tar.gz

Download URL tile_twinx-1.0.0.tar.gz
Size 36.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ad7ec7ecb313db622997ee1ad20ee809f71aa98a858d9584d6215fa28e04cbb4
BLAKE2b-256 checksum
How to use checksums
16cfc0366e1da2863029309e90a0cba5536ab9008dce4b0a4dc1b0aa5a22083b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / tile_twinx-1.0.0-py3-none-any.whl

Download URL tile_twinx-1.0.0-py3-none-any.whl
Size 34.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
04c025aae1a4eca1dc16d5b605c7435421833fb97a9d2e56c77c45898e6a3d64
BLAKE2b-256 checksum
How to use checksums
a9251073ab6fa442ff4407cd0cec013dc27ab636b7eb49f13fc7967c0f32dbc4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

1.0.1

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page