1

Тема: Нужен скрипт для извлечения названия играющего трека.

Что-то не могу нигде найти такой скрипт. Может кому встречался? Или хоть объясните, откуда берëтся информация о треке, попробую сам написать.

Re: Нужен скрипт для извлечения названия играющего трека.

чем вещаете?

3

Re: Нужен скрипт для извлечения названия играющего трека.

Есть несколько способов получения метаданных: парсить сайт или shoutcast / icecast статусные страницы непосредственно вещателя, получать непосредственно из потока, получать при помощи несложных инструментов от вещателя непосредственно. Первый - самый, шустрый и для вещателя безболезненный, второй достаточно нормален, но иногда может и не сработать, ну а третий сами понимаете подразумевает контакт с вещателем. Насколько я понял самый реальный два Вас способ номер два. в свое время был изобретен php script

<?php
function getMp3StreamTitle($streamingUrl, $interval, $offset = 0, $headers = true)
        {
        $needle = 'StreamTitle=';
        $ua = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36';
        $opts = array(
                'http' => array(
                        'method' => 'GET',
                        'header' => 'Icy-MetaData: 1',
                        'user_agent' => $ua
                )
        );
        if (($headers = get_headers($streamingUrl)))
        foreach($headers as $h)
        if (strpos(strtolower($h) , 'icy-metaint') !== false && ($interval = explode(':', $h) [1])) break;
        $context = stream_context_create($opts);
        if ($stream = fopen($streamingUrl, 'r', false, $context))
                {
                $buffer = stream_get_contents($stream, $interval, $offset);
                fclose($stream);
                if (strpos($buffer, $needle) !== false)
                        {
                        $title = explode($needle, $buffer) [1];
                        return substr($title, 1, strpos($title, ';') - 2);
                        }
                  else return getMp3StreamTitle($streamingUrl, $interval, $offset + $interval, false);
                }
          else throw new Exception("Unable to open stream [{$streamingUrl}]");
        }
$url = $_REQUEST['url'];
echo getMp3StreamTitle($url, 19200);
?>

что то в этом роде, у меня кстати как оказалось несколько таких до сих пор работают. По GET запросу с ?url=полный путь к потоку отдает title.
Примерно вот как тут: http://gyurgin.pro/test.php?url=http:// … se_aacplus (линком прошу не злоупотреблять).
В общем, надеюсь в нужном направлении подтолкнул...

Отредактировано gyurgin_1 (18-07-2015 00:11:18)

4

Re: Нужен скрипт для извлечения названия играющего трека.

пишет Aleksandr.Boyko:

чем вещаете?

Александр, я не вещаю, у меня сайт для прослушивания радиостанций. Чтоб не плодить внешние линки, вот мой пост в разделе рекламы: http://radiotalk.ru/viewtopic.php?id=7258

upd. Немного пообжился на форуме, привёл профиль в порядок. Теперь ссылку можно и в подписи посмотреть.

Я смотрю, что закинув радиопоток в винамп, он как-то извлекает названия треков, вот и задумался.

Отредактировано uglion.ru (18-07-2015 06:56:53)

5

Re: Нужен скрипт для извлечения названия играющего трека.

gyurgin_1, большое спасибо, сегодня буду разбираться.

В программировании я хорошо шарю только в Delphi, поэтому сейчас испытываю сложности. Смотрите, скрипт я установил на свой сервер, он работает прекрасно: http://radio.uglion.ru/radio/gettrackna … 02/dub_128

Но как ответ сервера воткнуть вот в такую структуру я не понял:

<div>
     // Здесь должен быть ответ сервера
</div>

Видимо это надо делать через ajax и вешать обновление по таймеру. Но у меня никак не получается sad

Отредактировано uglion.ru (18-07-2015 14:36:41)

6

Re: Нужен скрипт для извлечения названия играющего трека.

В общем набросал следующий код:

function createObject() {
var request_type;
var browser = navigator.appName;
if(browser == "Microsoft Internet Explorer"){
request_type = new ActiveXObject("Microsoft.XMLHTTP");
}else{
request_type = new XMLHttpRequest();
}
return request_type;
}

var http = createObject();

function rad_trackname(){
    http.open('get', 'radio.uglion.ru/radio/gettrackname.php?url=http://online.radiorecord.ru:8102/dub_128');
    http.onreadystatechange = ServerReply;
    http.send(null);
}

function ServerReply() {
    if(http.readyState == 4){ 
        var response = http.responseText;
        if(response == ''){
            document.getElementById('track_name').innerHTML = 'Datas not found';
        } else {
            document.getElementById('track_name').innerHTML = response;
        }
    }
}

В итоге получаю вместо названия песни Datas not found. Т.е. response = '' Я думал, что там должно быть название песни. В скрипте так вот: echo getMp3StreamTitle($url, 19200); При вызове через адресную строку всё возвращается как надо.

upd Продолжил копать. Оказалось, что http.status = 0, а не 200. В чём проблема?

upd2 Разобрался. Видимо всё дело было в кросс-доменных запросах. Если запускать с сервера, то работает.

Результат тут: http://radio.uglion.ru/record-dubstep/

Завтра html поправлю, а то уже с ног валюсь. Всем спасибо за помощь. smile

Отредактировано uglion.ru (18-07-2015 20:33:20)

7

Re: Нужен скрипт для извлечения названия играющего трека.

К сожалению данный метод работает не со всеми радиостанциями. Хотя винамп извлекает названия песен отовсюду, где эта информация есть. Например, отсюда: http://85.21.79.31:7128/

8

Re: Нужен скрипт для извлечения названия играющего трека.

Здравствуйте. Довольно долго уже терзает одна проблемка. Пользуюсь скриптом, выдёргивающим названия треков из потока. Скрипт работает и с SHOUTcast и с icecast. Однако с некоторыми потоками он всё-таки не справляется. Например вот с таким:

https://radiola.audio/radio/gettracknam … a24.ru/256

Вместо названия трека выдаёт сразу кучу информации, включая само название.

А вот код скрипта:

<?php
define('CRLF', "\r\n");

class streaminfo{
public $valid = false;
public $useragent = 'Winamp 2.81';

protected $headers = array();
protected $metadata = array();

public function __construct($location){
    $errno = $errstr = '';
    $t = parse_url($location);
    if ( @!$t['port'] ) {
        $t['port'] = '80';
    }
    $sock = fsockopen($t['host'], $t['port'], $errno, $errstr, 5);
    $path = isset($t['path'])?$t['path']:'/';
    if ($sock){
        $request = 'GET '.$path.' HTTP/1.0' . CRLF .
            'Host: ' . $t['host'] . CRLF .
            'Connection: Close' . CRLF .
            'User-Agent: ' . $this->useragent . CRLF .
            'Accept: */*' . CRLF .
            'icy-metadata: 1'.CRLF.
            'icy-prebuffer: 65536'.CRLF.
            (isset($t['user'])?'Authorization: Basic '.base64_encode($t['user'].':'.$t['pass']).CRLF:'').
            'X-TipOfTheDay: Winamp "Classic" rulez all of them.' . CRLF . CRLF;
        if (fwrite($sock, $request)){
            $theaders = $line = '';
            while (!feof($sock)){
                $line = fgets($sock, 4096);
                if('' == trim($line)){
                    break;
                }
                $theaders .= $line;
            }
            $theaders = explode(CRLF, $theaders);
            foreach ($theaders as $header){
                $t = explode(':', $header);
                if (isset($t[0]) && trim($t[0]) != ''){
                    $name = preg_replace('/[^a-z][^a-z0-9]*/i','', strtolower(trim($t[0])));
                    array_shift($t);
                    $value = trim(implode(':', $t));
                    if ($value != ''){
                        if (is_numeric($value)){
                            $this->headers[$name] = (int)$value;
                        }else{
                            $this->headers[$name] = $value;
                        }
                    }
                }
            }
            if (!isset($this->headers['icymetaint'])){
                $data = ''; $metainterval = 512;
                while(!feof($sock)){
                    $data .= fgetc($sock);
                    if (strlen($data) >= $metainterval) break;
                }
               $this->print_data($data);
                $matches = array();
                preg_match_all('/([\x00-\xff]{2})\x0\x0([a-z]+)=/i', $data, $matches, PREG_OFFSET_CAPTURE);
               preg_match_all('/([a-z]+)=([a-z0-9\(\)\[\]., ]+)/i', $data, $matches, PREG_SPLIT_NO_EMPTY);
               echo '<pre>';var_dump($matches);echo '</pre>';
                $title = $artist = '';
                foreach ($matches[0] as $nr => $values){
                  $offset = $values[1];
                  $length = ord($values[0]{0}) +
                            (ord($values[0]{1}) * 256)+
                            (ord($values[0]{2}) * 256*256)+
                            (ord($values[0]{3}) * 256*256*256);
                  $info = substr($data, $offset + 4, $length);
                  $seperator = strpos($info, '=');
                  $this->metadata[substr($info, 0, $seperator)] = substr($info, $seperator + 1);
                    if (substr($info, 0, $seperator) == 'title') $title = substr($info, $seperator + 1);
                    if (substr($info, 0, $seperator) == 'artist') $artist = substr($info, $seperator + 1);
                }
                $this->metadata['streamtitle'] = $artist . ' - ' . $title;
            }else{
                $metainterval = $this->headers['icymetaint'];
                $intervals = 0;
                $metadata = '';
                while(1){
                    $data = '';
                    while(!feof($sock)){
                        $data .= fgetc($sock);
                        if (strlen($data) >= $metainterval) break;
                    }
                    $len = join(unpack('c', fgetc($sock))) * 16;
                    if ($len > 0){
                        $metadata = str_replace("\0", '', fread($sock, $len));
                        break;
                    }else{
                        $intervals++;
                        if ($intervals > 100) break;
                    }
                }
                $metarr = explode(';', $metadata);
                foreach ($metarr as $meta){
                    $t = explode('=', $meta);
                    if (isset($t[0]) && trim($t[0]) != ''){
                        $name = preg_replace('/[^a-z][^a-z0-9]*/i','', strtolower(trim($t[0])));
                        array_shift($t);
                        $value = trim(implode('=', $t));
                        if (substr($value, 0, 1) == '"' || substr($value, 0, 1) == "'"){
                            $value = substr($value, 1);
                        }
                        if (substr($value, -1) == '"' || substr($value, -1) == "'"){
                            $value = substr($value, 0, -1);
                        }
                        if ($value != ''){
                            $this->metadata[$name] = $value;
                        }
                    }
                }
            }
            fclose($sock);
            $this->valid = true;
        }else echo 'unable to write.';
    }else echo 'no socket '.$errno.' - '.$errstr.'.';
}


public function print_data($data){
    $data = str_split($data);
    $c = 0;
    $string = '';
    echo "<pre>\n000000 ";
    foreach ($data as $char){
        $string .= addcslashes($char, "\n\r\0\t");
        $hex = dechex(join(unpack('C', $char)));
        if ($c % 4 == 0) echo ' ';
        if ($c % (4*4) == 0 && $c != 0){
          foreach (str_split($string) as $s){
            if (ord($s) < 32 || ord($s) > 126){
              echo '\\'.ord($s);
            }else{
              echo $s;
            }
          }
          echo "\n";
          $string = '';
          echo str_pad($c, 6, '0', STR_PAD_LEFT).'  ';
        }
        if (strlen($hex) < 1) $hex = '00';
        if (strlen($hex) < 2) $hex = '0'.$hex;
          echo $hex.' ';
        $c++;
    }
    echo "  $string\n</pre>";
}

public function __get($name){
    if (isset($this->metadata[$name])){
        return $this->metadata[$name];
    }
    if (isset($this->headers[$name])){
        return $this->headers[$name];
    }
    return null;
 }
}


$url = $_REQUEST['url'];

$t = new streaminfo($url); // get metadata

if ( mb_detect_encoding($t->streamtitle, 'UTF-8,Windows-1251') == 'Windows-1251') {
    echo iconv( "Windows-1251","UTF-8", $t->streamtitle);
}
else {
    echo $t->streamtitle;
}

?>

Подскажите, как побороть проблему?

9

Re: Нужен скрипт для извлечения названия играющего трека.

Выдачу покажите, выдернем что надо.

10

Re: Нужен скрипт для извлечения названия играющего трека.

уже есть у кого то подобие универсального скрипта для этой задачи? :-) поделитесь пожалуйста

11

Re: Нужен скрипт для извлечения названия играющего трека.

Да есть, но дергать таким образом метаданные не то чтобы не хорошо, даже совсем плохо.
Сотня слушателей принапряжет сервер, тысячя просто нагнет.
Нужен скрипт - обработчик, ну api, как его не назови, смысл один.
Надо - я покажу как.

12

Re: Нужен скрипт для извлечения названия играющего трека.

Мое интернет радио вещает по цепочке RadioBoss > http://listen2myradio.com/ > http://shoutcast.com/ и я не доволен тем, что названия песен (в том числе русские) не отображаются на веб-плеере. Видны только английские названия песен. Пытался вместо RadioBoss трансляцию вести через плеер Winamp. Но в этом случае даже английские названия песен пропадают (их нет на веб-плеере). Все тэги в моих песнях надписаны. Вот посмотрите сами. Как можно исправить кодировку, чтобы все языки отображались?
Наткнулся на такое сообщение http://se2.com.ua/phpBB/viewtopic.php?f … 224963091e и такую http://phpclub.ru/talk/threads/%D0%9F%D … ast.41116/, но пока не рискую ничего делать. У кого есть опыт, посоветуйте, как мне исправить кодировку.

uglion.ru, сайт https://radiola.audio/ просто ретранслирует имеющееся радио или является хостингом (аналогией сервера Shoutcast)? Свю проблему с неотбражением русских тэгов я описал выше. Если знаете решение ,поделитесь. Кстати, откуда вы берете этот код и можно ли через него поменять кодировку?

Отредактировано Rodos (06-10-2016 14:09:20)

13

Re: Нужен скрипт для извлечения названия играющего трека.

Если речь идет об Icecast - пока я использую самый идеальный вариант для получения имен треков - Icecast сам их шлет серверу когда они меняются и делает это для каждого маунта, сервер кладет в базу данных все данные. Да, я реализовал свой собственный yp-directory. Кроме названий треков он еще шлет кол-во слушателей и другую инфу(практически всю по каждому маунту).
И для этого всего-то нужно:

<directory>
  <yp-url-timeout>15</yp-url-timeout>
  <yp-url>https://your-server.radio/yp</yp-url>
</directory>

Ну и у сервера вьюху написал чтобы принимала запросы и клала в бд.

Отредактировано MechanisM (22-10-2016 19:00:33)

14

Re: Нужен скрипт для извлечения названия играющего трека.

Ну это для цивильного радиокаталога, топикстартер тут без спросу хочет на свой сайт потоки подключить. Потому, к примеру от меня можно помощи не ждать.

Кроме названий треков он еще шлет кол-во слушателей и другую инфу(практически всю по каждому маунту).

Подтягиваете данные или реально шлет еще что то кроме метаданных, количества и "add", "remove", "touch" ? Что то я там не наблюдал больше ничего...

15

Re: Нужен скрипт для извлечения названия играющего трека.

Двумя постами выше я описал свою проблему. Убедившись в том что причиной отсуствия русских и на других языках (кроме английского) названий песен является сервер Shoutcast 1 перешел на Shoutcast 2. Сейчас в Панели администратора названия на всех языках корректно отображаются. Нажимаю в панели админа кнопку URL потока и мое радио звучит. Однако на http://shoutcast.com/ мое радио уже не находится по поиску в отличии от прошлого (хотя название то же), а в других каталогах радио (сайтах) на веб-плеере оно хоть звучит, но по-прежнему не видны названия песен на других (кроме английского) языках. Там отображаются вопросительные знаки вместо букв. Что надо еще переключить или пoменять в настройках чтобы был полный порядок?