- PVSM.RU - https://www.pvsm.ru -

Используем Last.fm API с помощью C#

Приветствую Вас, Читатели!
image
В этом [1] посте я рассказал о своей программе для скробблинга треков на Last.fm [2]. Теперь я хочу рассказать Вам, как на языке C# наладить взаимодействие с Last.fm API [3] на примере скробблинга трека.

Первое, что нам нужно сделать — это зарегистрировать свой API аккаунт. Заходим в свой профиль и переходим по этой ссылке [4]. После заполнения нужных полей мы получим так называемые API Key и секретный ключ. Они понадобятся для идентификации вашего клиента сервисом и получения ключа сессии. Проблем с их получением у меня не возникло.

Так как скробблинг трека требует получения ключа сессии, то нас будут интересовать следующие методы:
Получение токена [5]
Получение ключа сессии [6]
Скроббл трека [7]

Упрощённая схема такова — мы получаем токен, используя наш API Key, потом получаем ключ сессии, используя токен и секретный ключ, потом скробблим трек, используя ключ сессии, токен и ещё несколько параметров.

Также нам понадобится использование двух классов — HttpWebRequest [8] и HttpWebResponse [9] для осуществления HTTP-запросов.

Итак, приступим к рассмотрению кода.
Сначала метод для получения сессии:

// создаём объект HttpWebRequest через статический метод Create класса WebRequest, явно приводим результат к HttpWebRequest. В параметрах указываем страницу, которая указана в API, в качестве параметров - method=auth.gettoken и наш API Key
HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create("http://ws.audioscrobbler.com/2.0/?method=auth.gettoken&api_key=" + ApiKey); 

// получаем ответ сервера
HttpWebResponse tokenResponse = (HttpWebResponse)tokenRequest.GetResponse(); 

// и полностью считываем его в строку
string tokenResult = new StreamReader(tokenResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd(); 

// извлекаем то, что нам нужно. Можно сделать и через парсинг XML (видимо, я о нём ещё не знал в тот момент, когда писал этот код).
string token = String.Empty;
for (int i = tokenResult.IndexOf("<token>") + 7; i < tokenResult.IndexOf("</token"); i++)
{
	token += tokenResult[i];
}

// запускаем в браузере по умолчанию страницу http://www.last.fm/api/auth/ c параметрами API Key и только что полученным токеном)
Process s = Process.Start("http://www.last.fm/api/auth/?api_key=" + ApiKey + "&token=" + token);

// запускается страница, где у пользователя спрашивается, можно ли разрешить данному приложению доступ к профилю.

// ждём подтверждения от пользователя
DialogResult d = MessageBox.Show("Вы подтвердили доступ?", "Подтверждение", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);

// если пользователь дал согласие
if (d == DialogResult.OK)
{
	// создаём сигнатуру для получения сессии (указываем API Key, метод, токен и наш секретный ключ, всё это без символов '&' и '='
	string tmp = "api_key" + ApiKey + "methodauth.getsessiontoken" + token + mySecret; 
	
	// хешируем это алгоритмом MD5 (думаю, у вас не будет проблем найти его в Интернете)
	string sig = MD5(tmp);
	
	// получаем сессию похожим способом
	HttpWebRequest sessionRequest = (HttpWebRequest)WebRequest.Create("http://ws.audioscrobbler.com/2.0/?method=auth.getsession&token=" + token + "&api_key=" + ApiKey + "&api_sig=" + sig);
	// уже не помню, зачем это свойство выставлять в true, но это обязательно. Зачем-то им нужно перенаправление.
	sessionRequest.AllowAutoRedirect = true;

// получаем ответ
	HttpWebResponse sessionResponse = (HttpWebResponse)sessionRequest.GetResponse();
	string sessionResult = new StreamReader(sessionResponse.GetResponseStream(),
								   Encoding.UTF8).ReadToEnd();

	// извлечение сессии (опять же проще использовать XML парсер)
	for (int i = sessionResult.IndexOf("<key>") + 5; i < sessionResult.IndexOf("</key>"); i++)
	{
		sessionKey += sessionResult[i];
	}
}

Итак, полдела сделано, двигаемся дальше. Теперь нужно заскробблить трек.

// узнаем UNIX-время для текущего момента
TimeSpan rtime = DateTime.Now - (new DateTime(1970, 1, 1, 0, 0, 0));
TimeSpan t1 = new TimeSpan(3, 0, 0);
rtime -= t1; // вычитаем три часа, чтобы не было несоответствия из-за разницы в часовых поясах
// получаем количество секунд
int timestamp = (int)rtime.TotalSeconds;

// формируем строку запроса
string submissionReqString = String.Empty;

//добавляем параметры (указываем метод, сессию и API Key):
submissionReqString += "method=track.scrobble&sk=" + sessionKey + "&api_key=" + ApiKey;
           
// добавляем только обязательную информацию о треке (исполнитель, трек, время прослушивания, альбом), кодируя их с помощью статического метода UrlEncode класса HttpUtility.
submissionReqString += "&artist=" + HttpUtility.UrlEncode(artist);
submissionReqString += "&track=" + HttpUtility.UrlEncode(track);
submissionReqString += "& timestamp=" + timestamp.ToString(); // в этой строке не должно быть пробела между & и t. Просто почему-то Хабр неправильно отображает этот участок, если пробел убрать.
submissionReqString += "&album=" + HttpUtility.UrlEncode(album);

// формируем сигнатуру (параметры должны записываться сплошняком (без символов '&' и '=' и в алфавитном порядке):
string signature = String.Empty;

// сначала добавляем альбом
signature += "album" + album;

// потом API Key
signature += "api_key" + ApiKey;
           
// исполнитель		   
signature += "artist" + artist;

// метод и ключ сессии
signature += "methodtrack.scrobblesk" + sessionKey;

// время
signature += "timestamp" + timestamp;

// имя трека
signature += "track" + track;

// добавляем секретный код в конец
signature += mySecret; 

// добавляем сформированную и захешированную MD5 сигнатуру к строке запроса
submissionReqString += "&api_sig=" + MD5(signature);

// и на этот раз делаем POST запрос на нужную страницу
HttpWebRequest submissionRequest = (HttpWebRequest)WebRequest.Create("http://ws.audioscrobbler.com/2.0/"); // адрес запроса без параметров

// очень важная строка. Долго я мучался, пока не выяснил, что она обязательно должна быть
submissionRequest.ServicePoint.Expect100Continue = false;

// Настраиваем параметры запроса
submissionRequest.UserAgent = "Mozilla/5.0";
// Указываем метод отправки данных скрипту, в случае с POST обязательно
submissionRequest.Method = "POST"; 
// В случае с POST обязательная строка
submissionRequest.ContentType = "application/x-www-form-urlencoded"; 

// ставим таймаут, чтобы программа не повисла при неудаче обращения к серверу, а выкинула Exception
submissionRequest.Timeout = 6000;

// Преобразуем данные в соответствующую кодировку, получаем массив байтов из строки с параметрами (UTF8 обязательно)
byte[] EncodedPostParams = Encoding.UTF8.GetBytes(submissionReqString); 
submissionRequest.ContentLength = EncodedPostParams.Length;

// Записываем данные в поток запроса (массив байтов, откуда начинаем, сколько записываем)
submissionRequest.GetRequestStream().Write(EncodedPostParams, 0, EncodedPostParams.Length); 
// закрываем поток
submissionRequest.GetRequestStream().Close(); 

// получаем ответ сервера
HttpWebResponse submissionResponse = (HttpWebResponse)submissionRequest.GetResponse(); 

// считываем поток ответа
string submissionResult = new StreamReader(submissionResponse.GetResponseStream(), Encoding.UTF8).ReadToEnd(); 
// разбор полётов. Если ответ не содержит status="ok", то дело плохо, выкидываем Exception и где-нибудь ловим его.
if (!submissionResult.Contains("status="ok"")) 
         throw new Exception("Треки не отправлены! Причина - " + submissionResult);

// иначе всё хорошо, выходим из метода и оповещаем пользователя, что трек заскробблен.

Таким образом, треки скробблятся без ввода пароля. Это обновлённый API, раньше ввод пароля требовался (это можно понять из моей программы). Сохранив куда-нибудь ключ сессии, вам не нужно будет каждый раз просить пользователя подтверждать доступ (ключ будет действовать до тех пор, пока пользователь не «отключит» ваш клиент от своего профиля на этой [10] странице).

Основные ссылки я привёл в начале статьи. Пожалуй, остаётся добавить ссылку на Last.fm форум для использующих API [11] (только на английском). Без его использования я вряд ли дошёл бы до конца.

На этом всё. Надеюсь, я достаточно подробно описал каждый свой шаг. Буду рад ответить на Ваши вопросы, если таковые возникнут.
Спасибо за внимание.

Автор: v_decadence


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/net/6675

Ссылки в тексте:

[1] этом: http://habrahabr.ru/post/143082/

[2] Last.fm: http://www.lastfm.ru/

[3] Last.fm API: http://www.last.fm/api

[4] этой ссылке: http://www.last.fm/api/account

[5] Получение токена: http://www.last.fm/api/show/auth.getToken

[6] Получение ключа сессии: http://www.last.fm/api/show/auth.getSession

[7] Скроббл трека: http://www.last.fm/api/show/track.scrobble

[8] HttpWebRequest: http://msdn.microsoft.com/ru-ru/library/system.net.httpwebrequest.aspx

[9] HttpWebResponse: http://msdn.microsoft.com/ru-ru/library/system.net.httpwebresponse.aspx

[10] этой: http://www.lastfm.ru/settings/applications

[11] API: http://www.lastfm.ru/group/Last.fm+Web+Services/forum/21604