Complete Musixmatch client API C# implementation
Development of this project is suspended due to pending rewrite in Node.js, libmxm. When the project is finished, I'll keep both projects up to date.
Definitions:
- W: Work in progress
- H: Hold
- I: Implemented
- S: Code-documented (summary)
- T: Tested
- D: Wiki-documented
- R: Research in progress (for undocumented)
- U: Ignored (useless)
Core
- Custom request function | I
- Async functionality
Officially implemented API methods
- chart.artists.get | IS
- chart.tracks.get | IST
- track.search | IST
- track.get | IST
- track.lyrics.get | IST
- track.snippet.get | IST
- track.subtitle.get | IST
- track.richsync.get | IST
- track.lyrics.translation.get | IS
- track.subtitle.translation.get | W
- music.genres.get | IS
- matcher.lyrics.get | HU
- matcher.track.get | HU
- matcher.subtitle.get | HU
- artist.get | IST
- artist.search | IST
- artist.albums.get | IST
- artist.related.get | H
- album.get | IST
- album.tracks.get | IST
Unofficial API methods
- track.subtitle.post | IST
- track.lyrics.post | IST
- track.translation.post | H
- crowd.user.feedback.get | IS
- crowd.polls.tracks.search | IS
- token.get | IST
- credentials.post | IST
- crowd.user.suggestion.lyrics.get | IST
- crowd.user.suggestion.subtitles.get | IST
- crowd.user.suggestion.translations.get | IST
- crowd.user.suggestion.votes.get | IST
- ai.question.post | WRIST
- crowd.chart.users.get | IST
- track.richsync.post | IS
- crowd.score.get | WIST
Missions API
- Get missions | IST
- Get tasks | WS
- Reserve tasks | WS
- Release tasks | WS
Project
- Write samples for all the functions | IT
- Create wiki | H
All the information provided in this repository is for educational purposes only. Please do not use this to write bots or other automation applications. Everything in this repo is against Musixmatch ToS.
Using the library is quite simple. A complete list of samples is under development, until it's ready I'll leave some usage examples:
Too boring? Jump to example app!
MusixmatchToken
class represents the Musixmatch client token, that is used in all the client requests.
It can be requested from Musixmatch:
MusixmatchToken token = new MusixmatchToken();
Or it can be extracted from Musixmatch desktop application and used in the library:
MusixmatchToken token = new MusixmatchToken("MyToken");
A token could be created with a different API context, such as Musixmatch Community or Musixmatch iOS (more coming soon):
MusixmatchToken token = new MusixmatchToken("MyToken", API.Contexts.ApiContext.iOS);
Currently, you cannot create a token with a context other than Desktop
.
Also, a token requested from Musixmatch has limited capabilities (let's call it guest token) until you log in through the browser:
MusixmatchToken token = new MusixmatchToken();
Process.Start(token.GetAuthUrl()); // Open a browser with auth link
To create a MusixmatchClient
class you have to pass a MusixmatchToken
to its constructor:
MusixmatchToken token = new MusixmatchToken("MyToken");
MusixmatchClient client = new MusixmatchClient(token);
You may also create a client without creating a token:
MusixmatchClient client = new MusixmatchClient("MyToken", API.Contexts.ApiContext.iOS);
Song search:
// Search by query
List<Track> tracks = client.SongSearch("Hommarju - Universe");
// Search by artist and track name
List<Track> tracks = client.SongSearch("Kobaryo", "Speed Complexxx");
// Search by the lyrics part
List<Track> tracks = client.SongSearchByLyrics("Watchin' you every night, to cast a small spell of fright");
// It is also possible to separate lines with '\n'
List<Track> tracks = client.SongSearchByLyrics("Just like you never ruined my heart\nLike you never said the words");
// Advanced search by parameters
List<Track> tracks = client.SongSearch(new TrackSearchParameters
{
Album = "Heartache Debug", // Album name
Artist = "t+pazolite", // Artist name
Title = "Messed Up Gravity", // Track name
LyricsQuery = "", // Search by the given part of lyrics
Query = "t+pazolite - Messed Up Gravity", // Search query, covers all the search parameters above
HasLyrics = false, // Only search for tracks with lyrics
HasSubtitles = false, // Only search for tracks with synced lyrics
Language = "", // Only search for tracks with lyrics in specified language
Sort = TrackSearchParameters.SortStrategy.TrackRatingDesc // List sorting strategy
});
Get song lyrics:
// Search for the track and get lyrics
int trackId = client.SongSearch("REDALiCE - Alive").First().TrackId;
Lyrics lyrics = client.GetTrackLyrics(trackId);
string lyricsBody = lyrics.Instrumental != 1 ? lyrics.LyricsBody : "This track is instrumental"; // lyrics.LyricsBody is null when the track is instrumental
Submit song lyrics:
// Submit track lyrics by id
int trackId = client.SongSearch("REDALiCE - Alive").First().TrackId;
client.SubmitTrackLyrics(trackId, "You make me feel alright\nYou make me feel alive...");
Get track by id:
// Get track by its Musixmatch id
Track track = client.GetTrackById(206481521);
string trackName = track.TrackName;
Get track snippet:
// Get track snippet (short line of lyrics to define the song)
int trackId = client.SongSearch("REDALiCE - Alive").First().TrackId;
string snippet = client.GetTrackSnippet(trackId);
Submit synced song lyrics:
// Submit track lyrics with time sync
Subtitles subtitles = new Subtitles();
subtitles.Lines.Add(new LyricsLine
{
Text = "You make me feel alive",
LyricsTime = TimeSpan.FromMilliseconds(1448)
});
int trackId = client.SongSearch("REDALiCE - Alive").First().TrackId;
client.SubmitTrackSubtitles(trackId, subtitles);
Get synced song lyrics:
// Search for the track and get synced lyrics
int trackId = client.SongSearch("REDALiCE - Alive").First().TrackId;
Subtitles subtitles = client.GetTrackSubtitles(trackId); // Throws ResourceNotFound if the track has no subtitles, check that first
List<LyricsLine> lines = subtitles.Lines;
string lineContent = lines.First().Text; // Line content
TimeSpan lineTime = lines.First().LyricsTime; // Line time (from the beginning of the song)
Submit raw synced song lyrics:
// Submit track lyrics with time sync (in Musixmatch format)
int trackId = client.SongSearch("REDALiCE - Alive").First().TrackId;
client.SubmitTrackSubtitlesRaw(trackId, "[{\"text\":\"You make me feel alive\",\"time\":{\"total\":17.33,\"minutes\":0,\"seconds\":17,\"hundredths\":33}}]");
Get raw synced song lyrics:
// Get raw track lyrics with time sync
int trackId = client.SongSearch("REDALiCE - Alive").First().TrackId;
string mxm = client.GetTrackSubtitlesRaw(trackId, MusixmatchClient.SubtitleFormat.Musixmatch);
Submit track mood:
int trackId = client.SongSearch("Camellia - AREA 52").First().TrackId;
client.SubmitTrackMood(trackId, 100 /* energy */, 69 /* mood */);
Get lyrics translation:
int trackId = client.SongSearch("Camellia - Nasty * Nasty * Spell").First().TrackId;
string translated = client.GetLyricsTranslation(trackId, "ru");
Get top weekly contributors:
List<User> coolGuysFromBelarus = client.GetUserWeeklyTop("BY");
List<User> theCoolestGuys = client.GetUserWeeklyTop();
Get spotify token (LOL):
string spotifyToken = client.GetSpotifyOauthToken().OauthRefreshtokenReply.AccessToken;
string refreshToken = client.GetSpotifyOauthToken().OauthRefreshtokenReply.RefreshToken;
string scope = client.GetSpotifyOauthToken().OauthRefreshtokenReply.Scope;
Get your statistics:
User you = client.GetUserScore();
int score = you.Score; // Cannot implicitly convert type 'long' to 'int' (joke, it works)
Your data:
var user = client.GetUserInfo();
string yourAge = user.UserData.Profile.AgeRange; // Not for everyone
Profile data update:
client.UpdateUserProfileCountry("BY"); // Set country by ISO code
client.UpdateUserProfileFavouriteArtists(new List<int>() { client.ArtistSearch("Camellia").First().ArtistId }); // Set favourite artists
client.UpdateUserProfileFavouriteGenres(new List<int>() { client.GetMusicGenres().Where(genre => genre.MusicGenreName.ToLower() == "hardcore").First().MusicGenreId }); // Set favourite genres
The cool stuff is, now the library supports musixmatch missions. The implementation is pretty raw tho, so feel free to contact me and give feedback via issues page or directly either via Discord or Telegram. Here are some quick examples on how to use the API:
Get mission tracks:
MissionManager missions = client.RequestMissionManager();
List<Mission> missionList = missions.GetMissions();
Mission mission = missionList.Find(m => m.Title == "The Jukebox");
foreach (var track in missions.GetMissionTracks(mission.Id, "en", "en"))
Console.WriteLine($"{track.Artist} - {track.Title}");
This prints out the entire mission list to your console window.
Reserve a mission task:
// Imagine spamming this one :clown:
MissionManager missions = client.RequestMissionManager();
List<Mission> missionList = missions.GetMissions();
Mission mission = missionList.Find(m => m.Title == "The Jukebox");
MissionTrack missionTrack = missions.GetMissionTracks(mission.Id, "en", "en").Find(t => t.Artist == "Cepheid" && t.Title == "Catch Wind");
missions.ReserveTask(mission.Id, missionTrack.Id); // this reserves a Catch Wind task (it doesn't exist, example), so it appears on your "In Progress" list
Thanks to @AlexanderDotH, library now supports async calls. The usage hasn't changed.
Currently this library supports only MusixmatchRequestException
. It has a StatusCode
property to understand the problem better.
By default, MusixmatchClient
would throw these if it runs into a problem during request. To ignore some problems, you could set AssertOnRequestException
parameter to false
.