/MusixmatchClientLib

Client library for Musixmatch

Primary LanguageC#MIT LicenseMIT

MusixmatchClientLib

Complete Musixmatch client API C# implementation

CodeFactor DungeonCI Discord


Development suspension notice

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.

TODO

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

A really earnest request

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.

Usage

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!

Tokens

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

Client class

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);

Other examples

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

Missions

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

Async development

Thanks to @AlexanderDotH, library now supports async calls. The usage hasn't changed.

Exception handling

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.