CSVMusic and the local playlist library built by matching YouTube Music
Scroll down to get to the downloads! Or click on the link below
At a glance
- What is it?
- CSVMusic is a Python and Qt desktop application that takes a public playlist or album link, finds the best matching track on YouTube Music, downloads the audio and writes tagged M4A or MP3 files into a persistent local catalog. It is well built, and its legal standing depends entirely on whether the person running it has the right to the music being downloaded.
- Who is it for?
- CSVMusic fits a user with a large personal playlist collection who wants a local, tagged, offline library and accepts that the audio comes from YouTube Music rather than from the service the playlist came from. It is the wrong tool for a legitimate streaming archive, because the project converts a catalogue reference into a downloaded copy and the rights to that copy sit with the rights holders, not with the person running the app.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The pipeline is match, download, tag, and the match is where the work is
CSVMusic accepts playlist and album links from supported music services, or a playlist exported as CSV from TuneMyMusic, and it automatically finds the best match on YouTube Music, downloads the audio, adds metadata such as artist, album and artwork, and outputs ready-to-use M4A or MP3 files, with optional native Opus output and optional `.m3u` or `.m3u8` playlist files.
The working description in the documentation is five steps. You open the app, where Library Mode is the default interface. You paste a supported public playlist or album link, or click Add CSV for a compatible CSV export. You scan the added playlist, review any warnings or low-confidence matches, and select it. You click Download, confirm the output settings, and click Start Download.
The third step is where the real engineering sits, and the release notes show it. Version 1.7.7 improved YouTube Music matching for official translated titles with compatible durations and version markers, which is the specific case where a naive title match finds the wrong recording. Version 1.7.9 fixed localized Spotify album and playlist links, including `/intl-es/` URLs, and prevented unrelated recommendations and numeric song titles from being captured as playlist rows, which is the kind of scraping bug that turns a short playlist into a bloated one full of junk rows.
The same release added a review step that matters: warnings and low-confidence matches are surfaced for you to look at before anything is downloaded. That is a sensible design, because the alternative, silently downloading a wrong recording, is the failure mode that ruins a library over time.
The package metadata describes the tool in one line as Convert Spotify playlists to MP3/M4A via YouTube Music, packaged, no extra installs, and the 'packaged' part is about how the media tools travel with the application.
Library Mode is the persistent catalog, and everything else hangs off it
Library Mode keeps multiple public Spotify, Apple Music, YouTube Music and YouTube playlists in one persistent local catalog, and it is the default interface rather than an extra mode.
The workflow for building that catalog is straightforward. You paste a public playlist or album URL into Add to library, click the green add button, and repeat for additional playlists, with duplicate links ignored. You then use Rescan All or the refresh button beside one playlist to check for changes.
Rescan is where a lot of the engineering went, and the changelog for 1.7.7 and 1.7.9 gives a good sense of the problem. Rescans preserve filename numbering and audio-processing metadata, and older numbered files can be recovered when the filename match is unambiguous. Version 1.7.9 added recognition of existing accented filenames across equivalent Unicode encodings during library rescans, which addresses a reproduced missing-file case; the readme is careful to note that the original download failure remains unconfirmed.
Two additions in 1.7.7 change how a large library is handled. Download All processes only missing tracks across the library and clearly identifies the playlists contributing work, and portable-player sync now checks playlist counts, order and stable track identities, with new or changed playlists prioritised and selected by default. A later fix stopped older iPod syncs from falsely marking every playlist as changed.
There is also a numbered filename prefix option, `01-`, `02-` and so on, which is disabled by default, with matching M3U and M3U8 paths. And existing downloads are reprocessed when enabled equalizer settings change, while replacing a selected alternative removes the superseded local file, which is the detail that keeps a library from accumulating two copies of the same track.
Version 1.7.8 added Scan Unscanned, which scans only playlists without a completed scan timestamp, and the readme notes that existing audio files are not automatically retagged when artwork changes.
Cookies are an explicit, optional and risky part of the design
The most consequential feature in the recent releases is account sign-in, and the documentation is unusually candid about what it costs.
Version 1.7.9 added optional YouTube account sign-in, connection checks, and browser or manual cookie fallbacks, and it notes that selected sessions remain enabled throughout downloads. It also changed the age restricted download path so that the error explains how to enable cookies in Settings to YouTube Account, save and retry, and suggests reconnecting and checking account eligibility if the cookies are already enabled, with the batch continuing with the next song rather than stopping.
Version 1.7.8 exposed optional browser cookies and Netscape cookies files directly in Library Mode under Settings then Advanced, and the readme states three things about them plainly. They are off by default. They can contain account credentials. And they do not guarantee protection from rate limits.
That is a fair description of the trade. Without cookies, age restricted tracks fail. With cookies, you are putting a credential for a Google account into a file that the application reads, on a machine that also runs a downloader.
The release notes also show that cookie support is recent and still moving. Version 1.7.9 fixed the JavaScript runtime arguments passed to yt-dlp, which is the component that does the downloading, and the older 1.7.8 entry records that release checks now extract the final ZIP, verify its signature and exercise Qt and WebEngine startup, with the caveat that these changes still need native Apple Silicon and Intel build verification and a Monterey test, and that the ARM startup report is not yet confirmed resolved.
That last caveat is the honest signal about the state of the project. The macOS path is the one with the most known rough edges, and the readme says so rather than hiding it.
The install is a ZIP per platform, and the Python route needs a desktop
Distribution is a set of prebuilt archives, one per platform, published as release assets for v1.7.9. There is a Windows ZIP, a macOS Apple Silicon ZIP, a macOS Intel ZIP and a Linux ZIP.
The archives must be extracted before running, and if the desktop does not launch the files directly you open a terminal in the extracted folder and run:
chmod +x CSVMusic yt-dlp
./CSVMusicThe presence of `yt-dlp` in that command is worth noting. The downloader ships alongside the application binary, which is what the package description means by packaged, no extra installs, and the same pattern appears in the Python package data, where `ffmpeg` and `deno` binaries are bundled for macOS, Linux and Windows along with fonts and the licences directory.
Linux has one specific documented failure. If Linux reports that the Qt `xcb` platform plugin could not be initialized, install the commonly required cursor runtime and retry:
sudo apt update
sudo apt install libxcb-cursor0Additional Linux diagnostics are included in `README-LINUX.md` inside the release archive, and the readme asks for the terminal output along with `uname -m` and the contents of `/etc/os-release` when reporting a launch failure.
The Python route is for people who want it in a virtual environment. Install the wheel with `python -m pip install CSVMusic-*.whl`, or install a source checkout with `python -m pip install -e .`, then launch with either:
csvmusic
python -m csvmusicThe constraint on that route is the same as on the binary route. Python installations still require a supported graphical desktop environment for the Qt interface, and Android, Andronix and other phone-hosted Linux environments are not currently supported or tested.
So the honest summary is that this is a desktop application with a Python core, not a headless tool, and anyone planning to run it on a server or a phone should look elsewhere.
The dependency set is pinned tightly and says what the tool is
The pyproject.toml is short and every dependency is a statement about the design.
The package is `csvmusic` at version 1.7.9, it requires Python 3.10 or newer, and it is built with setuptools using a flat package directory with three packages: `csvmusic`, `csvmusic.core` and `csvmusic.ui`. The console script is `csvmusic`, pointing at `csvmusic.app:main`.
The runtime dependencies are pinned to exact versions: PySide6 at 6.8.3, which is the Qt binding, `yt-dlp[default]` at 2026.8.19, which is the downloader, ytmusicapi at 1.7.4 or newer, which is the client for the YouTube Music catalog API, mutagen at 1.47.0 or newer, which writes the tags, requests at 2.32.0 or newer, and pandas at 2.2.0 or newer.
Reading that list tells you the whole architecture. ytmusicapi is what lets the app look up a track in the YouTube Music catalogue and judge which result is the right one, yt-dlp is what fetches the audio, mutagen writes the tags, and PySide6 is the desktop interface. The matching logic described in the release notes sits between the first two.
The exact pinning is unusual for an application, where exact versions cause upgrade friction, and it is deliberate here because the application bundles binaries that have to agree with the libraries driving them. The packaged `ffmpeg` and `deno` builds for the three platforms are listed as package data, alongside the fonts directory and the licences directory.
The repository layout also shows a project with real engineering around it. There is a `tests/` directory, an `AGENTS.md`, a `CSVMusic.spec` for packaging, a `README-LINUX.md` at the root, a `resources/` directory for the bundled media tools and images, and a `spotify_scrape_experiment_results.json` file, which suggests the Spotify scraping behaviour was characterised against recorded results rather than guessed at.
Where CSVMusic is the wrong tool, and the question of rights
There are two limits, and one of them is not a technical problem at all.
The technical limit is the desktop requirement. The Qt interface needs a graphical environment, and the readme is explicit that phone-hosted Linux environments are not supported or tested. So if your goal is a headless conversion service, a scheduled job on a server, or a container image, this is the wrong tool, and no amount of configuration changes that.
The other limit is the one the project does not resolve and cannot. The tool takes a reference to a track in a streaming catalogue and produces a local audio file of it. The rights to that audio sit with the rights holders, and the person running the application is the one making the copy. The project carries no licence grant for the music, and the repository's package metadata records no licence for the code either, while a `licenses/` directory is bundled in the package data, which is where the third party licences for the bundled components live.
There is a legitimate use for this and it is the one the tool is good at. Converting your own playlist into local files for offline listening on a device, or migrating a library you already own to a portable format, is a personal use that many streaming services themselves do not permit, but which is not the same act as distributing the music. The distinction matters, and it is the user's to make rather than the project's.
There is also a practical reliability limit, and the release notes state it more candidly than most projects would. Version 1.7.9 notes that recognition of accented filenames across equivalent Unicode encodings addresses a reproduced missing-file case related to issue 84 while the original download failure remains unconfirmed, and 1.7.8 notes that the macOS native architecture and Monterey compatibility changes still need build verification and a Monterey test, and that the ARM startup report is not yet confirmed resolved. A tool that depends on another service's catalogue and on scraping behaviour will always have a moving target, and this one tracks it closely enough to publish its own open issue list of what is still broken.
The version cadence is fast, with 1.7.7, 1.7.8 and 1.7.9 in the space of a month, and the last push was on 2026-10-15, so the project is being worked on actively. The risk with that pace is that the interface moves, and a script that drives the app will need checking.
Editorial conclusion
CSVMusic fits a user with a large personal playlist collection who wants a local, tagged, offline library and accepts that the audio comes from YouTube Music rather than from the service the playlist came from. It is the wrong tool for a legitimate streaming archive, because the project converts a catalogue reference into a downloaded copy and the rights to that copy sit with the rights holders, not with the person running the app. Before using it, verify two things: that your use of the resulting files is authorised, since the project itself carries no licence grant for the music, and that the account cookies you enable for age restricted tracks are stored on your own machine and are not shared. The code carries no recorded licence in the package metadata, the current version is 1.7.9 from 2026-10-15, and the last push was on the same day.
Frequently asked questions
What does CSVMusic do with a playlist link?
It finds the best match on YouTube Music, downloads the audio, adds metadata such as artist, album and artwork, and outputs ready-to-use M4A or MP3 files, with optional native Opus output and optional `.m3u` or `.m3u8` playlist files. It accepts playlist and album links from supported music services, or a CSV export from TuneMyMusic.
How do I install CSVMusic?
Download the archive for your platform from the v1.7.9 release, extract it, and run `chmod +x CSVMusic yt-dlp` followed by `./CSVMusic` in the extracted folder. A Python route also exists with `python -m pip install CSVMusic-*.whl` or `python -m pip install -e .`, launched with `csvmusic` or `python -m csvmusic`, but it still needs a graphical desktop.
What is Library Mode in CSVMusic?
It is the default interface, and it keeps multiple public Spotify, Apple Music, YouTube Music and YouTube playlists in one persistent local catalog. You add playlists by pasting a URL into Add to library, and you update them with Rescan All or the refresh button beside a playlist, with duplicate links ignored.
Why does CSVMusic ask for YouTube cookies?
For age restricted downloads, and it added optional YouTube account sign-in, connection checks and browser or manual cookie fallbacks in version 1.7.9. The readme states that cookies are off by default, can contain account credentials, and do not guarantee protection from rate limits.
What is the CSVMusic package built on?
The Python package `csvmusic` version 1.7.9 requires Python 3.10 or newer and pins PySide6 6.8.3 for the Qt interface, yt-dlp 2026.8.19 for downloading, ytmusicapi for catalogue lookups, mutagen for writing tags, requests and pandas. The package data bundles ffmpeg and deno binaries for macOS, Linux and Windows.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/angall1-csvmusic)Was this useful?