Track matching - WilliamNT/tunesynctool GitHub Wiki
What is track matching?
Tunesynctool's track matching algorithm uses online services and built-in methods to match tracks (songs) with each other. To use track matching, import the TrackMatcher class from the tunesynctool package. It essentially allows you to find the same song on a different streaming service.
[!IMPORTANT]
- If the song you try to match (find) isn't available on the target streaming service, the matching algorithm will return
None. It also does this if it doesn't find a close enough match. So, for example if your goal is to copy a Spotify playlist to something locally hosted like Navidrome and the matcher returnsNonefor a track, it could either mean that you haven't added the song to your local library or if you are absolutely sure that you have, you haven't properly tagged it. It is out of the scope of this project to download missing tracks or keep track of them. You can write a script that attempts to match your tracks and lists the misses though.- Even though I consider the matching algorithm to be fairly accurate, you still should run tests before using it in production.
Use cases
- Track matching was originally implemented because I wanted to syncronize my playlists between my Spotify account and my locally hosted Navidrome instance.
- You could write a script to move your library from one service to another.
- You could also write a small script to listen to Spotify's recap or auto-generated personalized playlists on other platforms.
How does matching work?
The tool attempts to guess correct ways to search and pull songs from your target service, then performs various matching strategies to check if the song from the streaming service and the results from the searches match. It does this by fuzzy string comparison, metadata normalization and some basic weighting.
How accurate is matching?
Based on my testing, it seems to be pretty accurate. If you face any accuracy issues please open an issue so I can improve it.
In some cases the algorithm might become inaccurate if not enough data is available for track comparison. The more data available, the more confidently we can determine whether 2 tracks are the same or not. Different variations of the same song can lead to false positives. By variants we commonly refer to, but not only the following: remasters, re-releases, remixes, radio or fan edits and re-uploads. In some rare cases people upload unlicensed versions as podcasts, so you might want for look out for that as well.
What is required for matching to work?
The tool works only with properly tagged songs. The following are taken into account when the tool looks for matches:
- Title
- Album name
- Primary (album) artist name
- Duration in seconds
- Track number
- ISRC code
- MusicBrainz ID
- Additional artists' names
- Release year
How can I automatically tag my songs?
You can use MusicBrainz Picard for that.
Using the TrackMatcher class
You can use the track matching algorithm by importing it from the tunesynctool package.
from tunesynctool import TrackMatcher, Configuration, YouTubeDriver, Track
Let's continue by instantiating our configuration object, our driver of choice (in this example we want to find songs on YouTube) and the matcher.
my_config = Configuration(...) # Create your config object
driver = YouTubeDriver( # You can use any driver (DeezerDriver, SpotifyDriver, etc.)
config=my_config
)
matcher = TrackMatcher(
target_driver=driver # The matcher uses the provided driver to look up tracks on the target streaming service
)
In the code above, you can see that we pass the argument target_driver to the TrackMatcher constructor. We have to pass a driver object to the matcher because internally it uses the given driver to search tracks and weigh the results. See the code for specific details.
[!TIP] You can use any driver class with
TrackMatcher. It will work just as good with any of them.
For our example use case, we will create a fake Track. Normally, you'd get a Track object from a driver but if your use case requires it, you can also create a custom object and use that.
example_track = Track(
title="Never gonna give you up",
primary_artist="Rick Astley",
...
)
Now we can finally use the matching algorithm. We have to call the find_match(self, track: Track) -> Optional[Track] method to do so. You can call it like this:
found_match = matcher.find_match(
track=example_track
)
print(found_match)
It will either return a Track object that has metadata from the target streaming service or None if it didn't find a close enough match.
Congrats! You found the same song on another streaming service!