Last.fm Scrobbling

PHP*

Начало работы


В пабле нет ни одной нормальной библиотеки для работы с Last.FM «Submission» API PHP, пришлось разбираться и писать самому…
Для начала Вам необходимо перейти на страницу регистрации вашего API аккаунта.
После ввода всех данных, Вам предоставят 2 ключа: публичный и секретный.
image

image
Все поля обязательны к заполнению:
  • Application/Device Name — Имя вашего приложения
  • Application/Device Description — Описание вашего приложения
  • Callback URL — Ссылка на страницу вашего php скрипта, где вы будете принимать token (см.ниже)

Общаемся с Last.FM


Теперь необходимо написать на почту submissions@last.fm для того чтобы Вам активировали собственный clientID.
Собственный clientID иметь в принципе не обязательно, но если вы хотите чтобы при прослушивании трека показывалось приложение, через которые проигрывается трек, то написать все же придется.

image
Вот немного смешной лог моей переписки:
Я: Здравствуйте.
Хочу приобрести собственный clientID для использования в моих запросах.
Сайт — vpleer.ru музыкальный поисковик. Хочу прикрутить scrobbling на last.fm
Спасибо
Adrian: Hey there,
I'm afraid I don't speak Russian, any way you could reword that request in English?
Regards, Adrian
Я: Okey, sorry for bad english..Hello.
I own clientID to use in my queries.
Website — vpleer.ru music search engine. I want to tie scrobbling to last.fm
Thanks. Understand me?)
Adrian: Hey there,
OK, I understood it this time. Your new client id is "***" — you should be able to start using this an hour from now. Happy scrobbling!
Regards, Adrian

Вот так вот =) Свой clientID я предпочел скрыть т.к. если будут какие-либо проблемы по запросам с моего client ID, то могут прикрыть. (По крайней мере так написано у них в API)

Приступаем к работе


Ваш пользователь должен перейти по ссылке: www.lastfm.ru/api/auth?api_key=MY_PUBLIC_KEY, где MY_PUBLIC_KEY это ваш публичный ключ.
Далее если пользователь соглашается работать с этим приложением, то его перенаправляет на тот самый Callback URL с одним единственным GET запросом 'token'…

<?php
    /*
     Coded by Isis (c) 2010, vpleer@gmail.com
     Link: www.lastfm.ru/api/auth?api_key=8ea0be38326c1275db95968ab677cfb6
     */
    define('API_KEY', '8ea0be38326c1275db95968ab677cfb6');
    define('API_SECRET_KEY', 'b95968ab6775f7474a4db827be6bcf');
    define('CLIENT_ID', 'tst'); //Paste your clientID
    define('CLIENT_VERSION', '1.0');
    
    function xml2arr($xml, $recursive = false)
    {
        if(!$recursive)    $array = simplexml_load_string($xml); else $array = $xml ;
 
        $newArray    = array() ;
        $array         = (array)$array ;
        foreach($array as $key =>$value)
        {
            $value    = (array)$value ;
            if(isset($value[0]))    $newArray[$key] = trim($value[0]); else $newArray[$key] = xml2arr($value,true);
        }
        return $newArray ;
    }
    
    function loginLastFM($url, $type, $post = null)
    {
        if($ch    = curl_init($url))
        {
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_USERAGENT, 'Vpleer.ru Scrobbler.');
            $type = $type == 'get'    ?    curl_setopt($ch, CURLOPT_POST, 0)    :    curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
            curl_setopt($ch, CURLOPT_REFERER, 'http://www.lastfm.ru/api/');
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $content    = curl_exec($ch);
            curl_close($ch);
            return $content;
        }
        else
        {
            return 'notconnect';
        }
    }
    
    //1st step. Get token from $_GET['token']
    function getKey($token, $API_KEY, $API_SECRET_KEY)
    {
        $api_sig    = md5('api_key'.$API_KEY.'methodauth.getSessiontoken'.$token.$API_SECRET_KEY);
        $get        = 'method=auth.getSession&api_key='.$API_KEY.'&token='.$token.'&api_sig='.$api_sig;    
        $return        = xml2arr(loginLastFM('http://ws.audioscrobbler.com/2.0/', 'get', $get));
        return $return;
    }
    
    //handShake. Рукопожатие. Вызывается каждый раз когда что-либо не сработало
    function handShake($user, $key, $time, $CLIENT_ID, $CLIENT_VERSION, $API_KEY, $API_SECRET_KEY)
    {
        $handtoken    = md5($API_SECRET_KEY.$time);    
        $handget    = 'hs=true&p=1.2.1&c='.$CLIENT_ID.'&v='.$CLIENT_VERSION.'&u='.$user.'&t='.$time.'&a='.$handtoken.'&api_key='.$API_KEY.'&sk='.$key;
        $handshake    = loginLastFM('http://post.audioscrobbler.com/', 'get', $handget);
        $handecho    = explode("\n", $handshake);
        return $handecho;
    }
    
    //Посылаем на last.fm все данные песни на момент начала проигрывания
    function nowPlaying($session, $artist, $song, $duration)
    {
        $playget    = 's='.$session.'&a='.$artist.'&t='.$song.'&b=&l='.$duration.'&n=&m=';
        $playnow    = loginLastFM('http://post.audioscrobbler.com:80/np_1.2', 'post', $playget);
        return $playnow;
    }
    
    //Посылаем на last.fm все данные песни на момент окончания проигрывания или спустя 50% проигрывания трека
    function submission($session, $artist, $song, $duration, $starttime)
    {
        $subget        = 's='.$session.'&a[0]='.$artist.'&t[0]='.$song.'&i[0]='.$starttime.'&o[0]=P&r[0]=&l[0]='.$duration.'&b[0]=&n[0]=&m[0]=';
        $submission    = loginLastFM('http://post2.audioscrobbler.com:80/protocol_1.2', 'post', $subget);
        return $submission;
    }
    
    function doShake($fmuser, $fmkey, $time, $CLIENT_ID, $CLIENT_VERSION, $API_KEY, $API_SECRET_KEY)
    {
        $handshake    = handShake($fmuser, $fmkey, $time, $CLIENT_ID, $CLIENT_VERSION, $API_KEY, $API_SECRET_KEY);
        $handerror    = trim($handshake[0]);
        $session    = trim($handshake[1]);
        if($handerror == 'OK' && isset($session))
        {
            setcookie('fmsess', $session, time() + 3600 * 24 * 730, '/', '.'.$_SERVER['HTTP_HOST']);
            return 'OK';
        }
        else
        {
            return 'Error : '.$handerror;
        }
    }
    
    $time        = time();

    //Если к нам пришли ппервый раз с last.fm, то ставим куки с необходимыми данными
    if(isset($_GET['token']))
    {
        $return        = getKey($_GET['token'], API_KEY, API_SECRET_KEY);
        $error        = isset($return['error'])            ?    $return['error']            :    null;
        $key        = isset($return['session']['key'])    ?    $return['session']['key']    :    null;
        $user        = isset($return['session']['name'])    ?    $return['session']['name']    :    null;
        if(!isset($error) && isset($key) && isset($user))
        {
            setcookie('fmkey', $key, time() + 3600 * 24 * 730, '/', '.'.$_SERVER['HTTP_HOST']);
            setcookie('fmuser', $user, time() + 3600 * 24 * 730, '/', '.'.$_SERVER['HTTP_HOST']);
            setcookie('scrobb', 'on', time() + 3600 * 24 * 730, '/', '.'.$_SERVER['HTTP_HOST']);
            $a    = doShake($user, $key, $time, CLIENT_ID, CLIENT_VERSION, API_KEY, API_SECRET_KEY);
            header('Location: /scrobb/');
        }
        else
        {
            echo $error;
        }
    }
    
    //1й раз? Надо пожать ручку
    if(isset($_COOKIE['fmkey'], $_COOKIE['fmuser']) && !isset($_COOKIE['fmsess']) && (isset($_POST['nowplaying']) || isset($_POST['submission'])))
    {
        $a    = doShake($_COOKIE['fmuser'], $_COOKIE['fmkey'], $time, CLIENT_ID, CLIENT_VERSION, API_KEY, API_SECRET_KEY);
        echo $a;
    }
    
    //Начали играть!
    if(isset($_POST['nowplaying'], $_COOKIE['fmkey'], $_COOKIE['fmuser'], $_COOKIE['fmsess']))
    {
        $artist        = isset($_POST['artist'])    ?    urldecode($_POST['artist'])    :    'Undefined';
        $song        = isset($_POST['song'])        ?    urldecode($_POST['song'])        :    'Undefined';
        $duration    = isset($_POST['duration'])    ?    urldecode($_POST['duration'])    :    'Undefined';
        setcookie('fmtime', $time, time() + 600, '/', '.'.$_SERVER['HTTP_HOST']);
        echo $playnow    = nowPlaying($_COOKIE['fmsess'], $artist, $song, $duration);
        if(!strstr($playnow, 'OK'))
        {
            echo doShake($_COOKIE['fmuser'], $_COOKIE['fmkey'], $time, CLIENT_ID, CLIENT_VERSION, API_KEY, API_SECRET_KEY);
            //$playnow    = nowPlaying($_COOKIE['fmsess'], $artist, $song, $duration);
        }
    }
    
    //Отправляем на last.fm
    if(isset($_POST['submission'], $_COOKIE['fmkey'], $_COOKIE['fmuser'], $_COOKIE['fmsess']))
    {
        $artist        = isset($_POST['artist'])    ?    urldecode($_POST['artist'])        :    'Undefined';
        $song        = isset($_POST['song'])        ?    urldecode($_POST['song'])        :    'Undefined';
        $duration    = isset($_POST['duration'])    ?    urldecode($_POST['duration'])    :    'Undefined';
        $starttime    = isset($_COOKIE['fmtime'])    ?    $_COOKIE['fmtime']    : time();
        echo $submiss    = submission($_COOKIE['fmsess'], $artist, $song, $duration, $starttime);
        if(!strstr($submiss, 'OK'))
        {
            echo doShake($_COOKIE['fmuser'], $_COOKIE['fmkey'], $time, CLIENT_ID, CLIENT_VERSION, API_KEY, API_SECRET_KEY);
            //$submiss    = submission($_COOKIE['fmsess'], $artist, $song, $duration, $starttime);
        }
    }


* This source code was highlighted with Source Code Highlighter.

Описание


Теперь для того чтобы заскробблить трек на last.fm на начало проигрывания, Вам необходимо передать следующие $_POST параметры к этому скрипту:
  • nowplaying: 1
  • artist: artist
  • song: song
  • duration: 214(длительность композиции в секундах)

А чтобы уже совсем заскробблить трек, то такие параметры:
  • submission: 1
  • artist: artist
  • song: song
  • duration: 122(длительность композиции в секундах)

Скачать scrobb.php
+16
9 марта 2010, 22:25
62
Isis 78,1

комментарии (30)

+3
Sma11erM1nd #
Очень удивило что для получения clientID требуеться всего одно письмо, а не куча форм и анкеток как это обычно бывает. Сколько по времени примерно занимал ответ?
+3
Isis #
Отправлено: 2 февраля 2010 г. 5:20
Ответ: 2 февраля 2010 г. 13:32
–1
stigger #
clientId значит скрыл, а *секретный* ключ засветил…
–1
Isis #
Я не настолько глуп ;-)
+1
stigger #
чего код тогда нечитаемый?
+1
Isis #
Я. пожалуй, спорить не буду. На вкус и цвет…
+1
flashkin #
Кто может дать определение слову «scrobbling»?
ни на Вики ни в Словарях не нашел.
+1
Isis #
+1
Colobock #
И кто может объяснить назначение всего этого добра?
0
AFX #
The term «scrobble» was coined by John Masefield in «The Midnight Folk», published in 1827, and is used extensively in the «Box of Delights», published in 1937, where Cole Hawlings is 'scrobbled' by throwing a black bag over his head and bundling him into a car.

Neil Gaiman also used scrobbling in the same sense in “Neverwhere”, published in 1996. Gaiman acknowledges the Box of Delights as the origin of the word.

"… Kay are waiting to scrobble the treacherous cats" Midnight Folk
0
flashkin #
Спасибо. И, да, минус в карму — ожидался. )
0
cgvictor #
Так у них конечному юзеру только проигрывание платное, что ли?
Или все-таки пользование сервисом целиком?

Просто если можно юзеру заливать базу скроббла, а потом дергать всякие выборки similars, то это как бы очень и очень неплохо (и рано я на него махнул рукой)…
+2
MniD #
Юзеру можно халявно прослушать всего 30-треков, а потом платно(3 бакса в месяц)… ну или юзать немецкое прокси, для немцев халява… весь остальной функционал как раньше =)
Хотя была идейка ещё одна, но так и небыло возможности протестировать, был у меня на работе товарищ, который слушал ласт.фм с айточа бесплатно и без ограничений, т.е. хз какая с кем там договорённость, но факт был виден, хотелось взять, просниферить запрос и научить мой любимый Амарок эмитировать айточ, но т.к. руки не доходили, а теперь и просто нет подобного девайса под рукой, осталось в планах ^_^
0
cgvictor #
Почитал у них на сайте; м-да, по части оплаты именно скробблинга — неочевидно.
Надо тестить (ц) Мне бы их scrobble-движок пригодился.
0
MniD #
Ну если интересно, есть такая штука Ampache ( ampache.org/ ), хоть движёк служит и для других целей, но там тоже есть что-то типа скроблинга, сохраняет историю прослушивая + разные мелкие шняжки, при этом очень удобный плагин в Amarok для использования этого движка… и естественно всё опенсорс ^_^
0
cgvictor #
У Ампача нету поиска по похожести. Можно, конечно, отдельно совместить с лайвовским getSimilar/getRecommended, но тогда смысл? )
0
MniD #
Ну разве похожесть проблема сделать?
По тем же тэгам(иль жанрам) у автором, искать по совпадению тэгов и те у кого больше тэгов совпало, те и рекомендовать… правда тэги всёравно придётся грабить с ласт.фм(ну или с чего-то подобного), либо вбивать ручками(как там это делает сообщество)
0
cgvictor #
Ласт, мне кажется, у кого-то базу жанров и похожести перекупал / брал под заказ. Слишком уж она у них хорошая и чистая, на обычный УГК не похоже.
0
MniD #
Не факт, может тоже грабили какой-то музыкальный инет магазин первоначально, а потом, когда проект раскрутился, переложили это всё на плечи сообщества, авторов, лейблов и т.п…
А что такое УГК?
0
cgvictor #
Узер Генерейтед Контент ;) Т.е. есть качественный UGC, который вроде как все хотят, а есть УГк — как получается обычно…

Да, может и так делали. Сграбить базу с какого-нибудь iTunes/Амазона (или тупо купить, чо париться-то), ну а дальше понятно.
–1
non7top #
а это разве не оно? www.lastfm.ru/group/PHP+Last.fm+API/forum
–1
Isis #
Да ты почти крут, только вот там в целом API, а у меня топик про Submission
0
silentroach #
А зачем отправлять, если случился Undefined?
+1
Polyakov #
Вот это тоже с last fm парсится? расскажите какой парсер с xml использовали. статья об этом будет?


+1
Isis #
Тоже оттуда. Если надо, будет =)
+1
Polyakov #
Было бы неплохо :)
0
Isis #
Домой приду вечером, посмотрю стоит ли делать статью
0
Ewg #
> $type = $type == 'get'? curl_setopt($ch, CURLOPT_POST, 0): curl_setopt($ch, CURLOPT_POST, 1);
Ужос.
0
Isis #
curl_setopt($ch, CURLOPT_POST, ($type == 'get'?0:1));
Так круче?
0
Ewg #
Хуже.
Достаточно
if ($type === 'get') {
curl_setopt($ch, CURLOPT_POST, 1);
}
и $value[0] невалидно.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.