diff --git a/php/bin/parse_queue.php b/php/bin/parse_queue.php index 34189ca..2d03508 100755 --- a/php/bin/parse_queue.php +++ b/php/bin/parse_queue.php @@ -3,14 +3,15 @@ chdir('..'); require_once 'common.php'; -Config::loadFile('app', 'config/app.ini'); +define('VKTIMEOUT', 1); + $db = Db::getInstance(); $vk = new Vkontakte(); $continue = true; while ($continue) { - $queue = $db->getRows($db->q("SELECT * FROM beathaven.queue WHERE status=0 OR status=2 ORDER BY priority DESC, times_failed ASC LIMIT 10")); + $queue = $db->getRows($db->q("SELECT * FROM beathaven.queue WHERE status=0 OR status=2 ORDER BY priority DESC, status ASC, times_failed ASC LIMIT 100")); if (!$queue || count($queue) == 0) { $continue = false; } else { @@ -19,6 +20,7 @@ while ($continue) { echo "Loading file list: "; $t1 = microtime(true); $vk->parse($t['track_title']); + $vk->parseHtml(); $files = $vk->getFiles(); if ($files && count($files) > 0) { echo "OK (".count($files).")\n"; @@ -27,14 +29,17 @@ while ($continue) { BeatDB::set($t['track_id'], $files); echo "Good files: ". count($files) ."\n\n"; $db->q("UPDATE beathaven.queue SET status=1 WHERE track_id=". $t['track_id']); + @unlink('/www/parser_data/html/'. $t['track_id'] .'.html'); } else { + file_put_contents('/www/parser_data/html/'. $t['track_id'] .'.html', $vk->getHtml()); echo "FAILED\n\n"; $db->q("UPDATE beathaven.queue SET status = 2, times_failed = times_failed + 1 WHERE track_id=". $t['track_id']); } $t2 = microtime(true); - if ($t2 - $t1 < 5) { - sleep(ceil(5 - ($t2 - $t1))); + if ($t2 - $t1 < VKTIMEOUT) { + sleep(ceil(VKTIMEOUT - ($t2 - $t1))); } } + sleep(5); } } diff --git a/php/bin/parser/accounts.txt b/php/bin/parser/accounts.txt new file mode 100644 index 0000000..b315bc9 --- /dev/null +++ b/php/bin/parser/accounts.txt @@ -0,0 +1,10 @@ +[ + { + "email" : "chezzzy@yandex.ru", + "password" : "somepass","user_id":,"remixsid":""} +] +alexgreen1978@gmail.com +fbcn136 + +bc5386a4f49f8bf7df20e11bdd311a7120818d83c23d93cd08177d5d3674 +69139853 \ No newline at end of file diff --git a/php/bin/parser/handler.php b/php/bin/parser/handler.php new file mode 100755 index 0000000..9419774 --- /dev/null +++ b/php/bin/parser/handler.php @@ -0,0 +1,30 @@ +#!/opt/local/bin/php + array(), 'curl_mtgrabber' => array()); +} + +switch ($argv[1]) { + case 'add': + shell_exec("./worker_". $argv[2] .".php > /www/parse.log &"); + break; + case 'remove': + if (isset($workers[$argv[2]]) && count($workers[$argv[2]]) > 0) { + $pid = $workers[$argv[2]][0]; + shell_exec("kill $pid"); + } + case 'status': + + case 'list': + foreach($workers as $type => $pids) { + echo "$type: ". count($pids) ."\n"; + } + break; + default: + break; +} \ No newline at end of file diff --git a/php/bin/parser/worker_html_grabber.php b/php/bin/parser/worker_html_grabber.php new file mode 100644 index 0000000..8265d15 --- /dev/null +++ b/php/bin/parser/worker_html_grabber.php @@ -0,0 +1,33 @@ +#!/opt/local/bin/php +getRows($db->q("SELECT * FROM beathaven.queue WHERE status=0 OR status=2 ORDER BY priority DESC, times_failed ASC LIMIT 10")); + if (!$queue || count($queue) == 0) { + $continue = false; + } else { + foreach ($queue as $t) { + echo "#{$t['track_id']} {$t['track_title']}\n"; + + $vk->parse($t['track_title']); + echo $vk->getHtml(); + + $db->q("UPDATE beathaven.queue SET status=1 WHERE track_id=". $t['track_id']); + } else { + echo "FAILED\n\n"; + $db->q("UPDATE beathaven.queue SET status = 2, times_failed = times_failed + 1 WHERE track_id=". $t['track_id']); + } + $t2 = microtime(true); + if ($t2 - $t1 < 5) { + sleep(ceil(5 - ($t2 - $t1))); + } + } + } +} diff --git a/php/classes/RemoteFile.class.php b/php/classes/RemoteFile.class.php deleted file mode 100644 index 2b8f895..0000000 --- a/php/classes/RemoteFile.class.php +++ /dev/null @@ -1,114 +0,0 @@ -'search', - 'q' => urlencode($this->_query) -)) -*****************************************************************/ - -/** - * Класс для работы с удаленными файлами - * Реализован через библиотеку cURL - * - * @package classes - * @author chez - **/ -class RemoteFile { - - private static $_timeout = 5; // Таймаут ответа от сервера - private static $_headers = array(); // Заголовки для отправки на сервер - - /** - * Отправка запроса и получение ответа от сервера - * Умеет возвращать текст ответа или заголовки - * - * @param string $url URL запроса - * @param bool $headers Флаг: возвращать заголовки, а не текст - * @param array $post_params Массив POST-параметров, если установлен, то метод меняется на POST - * @return string Ответ от сервера - * @author chez - **/ - private static function _exec($url, $headers = false, $post_params = array()) { - if (count($post_params) > 0) { - $p = ''; - foreach ($post_params as $key => $val) { - $p .= '&'. $key .'='. $val; - } - $post_params = substr($p, 1); - } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_HTTPHEADER, self::$_headers); - if ($headers) { - curl_setopt($ch, CURLOPT_HEADER, 1); - curl_setopt($ch, CURLOPT_NOBODY, 1); - } - if (is_string($post_params)) { - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $post_params); - } - curl_setopt($ch, CURLOPT_VERBOSE, 1); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::$_timeout); - $r = curl_exec($ch); - curl_close($ch); - return $r; - } - - /** - * Получение HTTP-заголовков ответа от сервера - * - * @param string $url URL запроса - * @param array $post_params Массив POST-параметров, если установлен, то метод меняется на POST - * @return array Распарсеный массив заголовков - * @author chez - **/ - public static function getHeaders($url, $post_params = array()) { - $headers = explode("\r\n", self::_exec($url, true)); - $headers_array = array(); - - while(list($i, $header) = each($headers)) { - if (substr($header, 0, 5) == 'HTTP/') { - $header = explode(' ', $header); - $headers_array['http'] = $header[1]; - } elseif ($header != '') { - preg_match('/^([a-z0-9\-]*):\s(.*)$/Ui', $header, $m); - $headers_array[strtolower(str_replace('-', '_', $m[1]))] = $m[2]; - } - } - - return $headers_array; - } - - /** - * Получение ответа от сервера - * - * @param string $url URL запроса - * @param array $post_params Массив POST-параметров, если установлен, то метод меняется на POST - * @return string Тело ответа от сервера - * @author chez - **/ - public static function getData($url, $post_params = array()) { - return self::_exec($url, false, $post_params); - } - - /** - * Запись заголовков, которые будет отправлены вместе с запросом - * - * @param array $headers Индексный массив заголовков - * @return void - * @author chez - **/ - public static function setHeaders($headers) { - self::$_headers = $headers; - } -} \ No newline at end of file diff --git a/php/classes/TrackWeight.class.php b/php/classes/TrackWeight.class.php deleted file mode 100644 index 357fb61..0000000 --- a/php/classes/TrackWeight.class.php +++ /dev/null @@ -1,99 +0,0 @@ -setTrackData('Blondie', 'Call Me', 210); -$weight_calc->setFiles($files); // Файлы, полученные от парсера -$weight_calc->calculateWeight(); -$files = $weight_calc->getFiles(); -*****************************************************************/ - -/** - * Класс посчета веса файла (коэфициента, определяющего релевантность) - * - * @package classes - * @author chez - **/ -class TrackWeight { - - private $_artist; // Имя исполнителя - private $_track; // Название трека - private $_duration; // Длительность трека в секундах - - private $_files; // Массив файлов для сравнения - - /** - * Задает параметры оригинального трека - * - * @param string $artist Имя исполнителя - * @param string $track Запрос - * @param int $duration Длительность трека в секундах - * @return void - * @author chez - **/ - public function setTrackData($artist, $track, $duration) { - $this->_artist = $artist; - $this->_track = $track; - $this->_duration = $duration; - } - - /** - * Задает массив файлов для сравнения - * - * @param array $files Массив файлов для сравнения - * @return void - * @author chez - **/ - public function setFiles($files) { - $this->_files = $files; - } - - /** - * Возвращает файлы с проставленным весом - * - * @return array $files Массив файлов - * @author chez - **/ - public function getFiles() { - return $this->_files; - } - - /** - * Рассчитывает вес для каждого файла - * - * @return void - * @author chez - **/ - public function calculateWeight() { - foreach ($this->_files as $i => $file) { - $weight = 0; - - if ($file['artist'] == $this->_artist) { - $weight += 10; - } elseif (strpos($file['artist'], $this->_artist) !== false) { - $weight += 5; - } elseif (strpos($file['track'], $this->_artist) !== false) { - $weight += 4; - } - - if ($file['track'] == $this->_track) { - $weight += 10; - } elseif (strpos($file['track'], $this->_track) !== false) { - $weight += 5; - } - - if ($file['duration'] == $this->_duration) { - $weight += 10; - } else { - $delta = abs($file['duration'] - $this->_duration); - if ($delta < 5) { - $weight += (5 - $delta); - } - } - - $this->_files[$i]['weight'] = $weight; - } - } -} \ No newline at end of file diff --git a/php/classes/Vkontakte.class.php b/php/classes/Vkontakte.class.php deleted file mode 100644 index a435f16..0000000 --- a/php/classes/Vkontakte.class.php +++ /dev/null @@ -1,127 +0,0 @@ -parse('Blondie - Call Me'); -$files = $vk_parser->getFiles(); -*****************************************************************/ - -/** - * Класс парсинга вконтактика - * - * @package classes - * @author chez - **/ -class Vkontakte { - - private $_cookies; // Куки, ассоциативный массив - private $_query; // Запрос, plain text - - private $_html; // HTML, полученый от вконтактика - private $_files; // Распарсеные массивы с информацией о файле - - /** - * Оболочка парсера - * - * @param string $q Запрос - * @return array Массив с файлами - * @author chez - **/ - public function parse($q) { - $this->_query = $q; - $this->auth(); - $cookie = array(); - foreach ($this->_cookies as $key => $val) { - $cookie[] = $key .'='. $val; - } - RemoteFile::setHeaders(array( - 'Cookie: '. implode('; ', $cookie), - 'Referer: http://vkontakte.ru/audio?album_id=0', - 'X-Requested-With: XMLHttpRequest', - 'Origin: http://vkontakte.ru', - 'Content-Type: application/x-www-form-urlencoded', - 'User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16', - 'Connection: close' - )); - $this->setHtml(RemoteFile::getData('http://vkontakte.ru/audio', array( - 'act' =>'search', - 'al' =>'1', - 'gid' =>'0', - 'id' =>'5728795', - 'offset' =>'0', - 'q' => urlencode($this->_query), - 'sort' =>'2' - ))); - $this->parseHtml(); - return $this->_files; - } - - /** - * Пишет полученый html в член объекта - * - * @param string $html HTML - * @return void - * @author chez - **/ - public function setHtml($html) { - $this->_html = $html; - } - - /** - * Возвращает хранимый html - * - * @return string HTML - * @author chez - **/ - public function getHtml() { - return $this->_html; - } - - /** - * Возвращает хранимый массив файлов - * - * @return array Список файлов - * @author chez - **/ - public function getFiles() { - return $this->_files; - } - - /** - * Проводит авторизацию на вконтактике и получает куки - * Пока костыль, потом нужно будет переписать - * - * @return array Ассоциативный массив с куками - * @author chez - **/ - private function auth() { - $this->_cookies = array( - 'remixchk' => 5, - 'remixsid' => 'c68c4362f62f218a25802bae87201d1bc46fadd0b5c64f71678430c9b63b' - ); - } - - /** - * Разбирает HTML, полученый от вконтактика - * - * @return array Список файлов - * @author chez - **/ - public function parseHtml() { - preg_match_all('/(.*)<\/tr>/Usi', $this->_html, $m); - $files = array(); - foreach ($m[0] as $res) { - preg_match('/(.*)<\/div>.*(.*)<\/a>.*\s-\s(.*)<\/div>/Usi', $res, $m1); - $duration = explode(':', $m1[3]); - $files[] = array( - 'url' => $m1[1], - 'duration' => $duration[0] * 60 + $duration[1], - 'artist' => strip_tags($m1[4]), - 'track' => strip_tags($m1[5]) - ); - } - $this->_files = $files; - } -} \ No newline at end of file diff --git a/php/classes/VkontakteMP3.class.php b/php/classes/VkontakteMP3.class.php deleted file mode 100644 index 04a200c..0000000 --- a/php/classes/VkontakteMP3.class.php +++ /dev/null @@ -1,108 +0,0 @@ - $br && ! $found_br) { - $delta = self::$_bitrates[$i] - $br; - $br_delta = self::$_bitrates[$i] - self::$_bitrates[$i-1]; - if (round($br_delta / 3) > $delta) { - $found_br = self::$_bitrates[$i]; - } else { - $found_br = self::$_bitrates[$i-1]; - } - } elseif ($i == count(self::$_bitrates) - 1 && self::$_bitrates[$i] < $br && ! $found_br) { - $delta = $br - self::$_bitrates[$i]; - if ($delta < 32) { - $found_br = self::$_bitrates[$i]; - } else { - $found_br = $br; - } - } - } - return $found_br; - } - - /** - * Проверяет файлы, рассчитывает битрейт и релевантность - * - * @param array $files Массив файлов для обработки - * @return array Обработанный массив файлов - * @author chez - **/ - public static function check($files) { - - $m = new Match(); - $m->setTrackData('Blondie', 'Call Me', 210); - $m->setFiles($files); - $m->calculateWeight(); - $files = $m->getFiles(); - - uasort($files, function($a, $b){ - return $a['weight'] < $b['weight']; - }); - - foreach ($files as $i => $file) { - $files[$i]['length'] = self::convertDuration($file['duration']); - $files[$i]['bitrate'] = self::calculateBitrate($file['size'], $files[$i]['length']); - } - return $files; - } - - /** - * Чистит строку для максимально точного сравнения - * - * @param string $str Необработанная строка - * @return string Чистая строка - * @author chez - **/ - public static function prepareQuery($str) { - $str = trim($str); - while(strpos($str, ' ') !== false) { - $str = str_replace(' ', ' ', $str); - } - return $str; - } - - /** - * Преобразует длину из формата мм:сс в ссс - * - * @param string $duration Читабельная длина - * @return int Длина в секундах - * @author chez - **/ - public static function convertDuration($duration) { - - } -} \ No newline at end of file diff --git a/php/config/accounts.ini b/php/config/accounts.ini new file mode 100644 index 0000000..e2adbbd --- /dev/null +++ b/php/config/accounts.ini @@ -0,0 +1,20 @@ +[Bach] +user_id = 5728795 +email = chezzzy@yandex.ru +password = yabach! +remixsid = 47c2f5501b22a3e3aa6947e5e74d1a72381267df2502570eb75c94481ade +remixchk = 5 + +[Green] +user_id = 69139853 +email = alexgreen1978@gmail.com +password = fbcn136 +remixsid = bc5386a4f49f8bf7df20e11bdd311a7120818d83c23d93cd08177d5d3674 +remixchk = 5 + +[Chez] +user_id = 1217744 +email = phpdev.ru@gmail.com +password = yanebach! +remixsid = fc27c3a7874bc0b84477015e187e5e0bd3a71bdca02d98327595ef255773 +remixchk = 5 \ No newline at end of file diff --git a/php/core/classes/Vkontakte.class.php b/php/core/classes/Vkontakte.class.php index fc23c35..823dea1 100644 --- a/php/core/classes/Vkontakte.class.php +++ b/php/core/classes/Vkontakte.class.php @@ -54,8 +54,6 @@ class Vkontakte { 'q' => urlencode($this->_query), 'sort' =>'2' ))); - $this->parseHtml(); - return $this->_files; } /** @@ -99,7 +97,8 @@ class Vkontakte { private function auth() { $this->_cookies = array( 'remixchk' => 5, - 'remixsid' => 'c68c4362f62f218a25802bae87201d1bc46fadd0b5c64f71678430c9b63b' + 'remixsid' => 'cf8bdd79d451422c1d484532a58205d92fc46b79caab663a40624c812e01', + 'remixlang' => 777 ); } diff --git a/php/core/classes/VkontakteMP3.class.php b/php/core/classes/VkontakteMP3.class.php index df0a70c..83efdf3 100644 --- a/php/core/classes/VkontakteMP3.class.php +++ b/php/core/classes/VkontakteMP3.class.php @@ -62,12 +62,16 @@ class VkontakteMP3 { * @author chez **/ public static function check($files, $artist_name, $track_name, $track_length) { + $urls = array(); + foreach($files as $i => $file) { + $urls[$i] = $file['url']; + } + $headers = RemoteFile::getHeadersMT($urls); foreach ($files as $i => $file) { - $headers = RemoteFile::getHeaders($file['url']); - if ($headers === false || $headers['http'] != 200) { + if (!isset($headers[$i]['http']) || $headers[$i]['http'] != 200) { unset($files[$i]); } else { - $files[$i]['size'] = trim($headers['content_length']); + $files[$i]['size'] = trim($headers[$i]['content_length']); } } $m = new TrackWeight(); diff --git a/php/core/classes/files/RemoteFile.class.php b/php/core/classes/files/RemoteFile.class.php index e2dce43..b0054c9 100644 --- a/php/core/classes/files/RemoteFile.class.php +++ b/php/core/classes/files/RemoteFile.class.php @@ -118,4 +118,51 @@ class RemoteFile { public static function setHeaders($headers) { self::$_headers = $headers; } + + /** + * Массововое получение заголовков по списку файлов + * + * @param array $fules Ассоциативный массив id => url + * @return array Ассоциативный массив id => headers + * @author chez + **/ + public static function getHeadersMT($files) { + $mh = curl_multi_init(); + $headers_all = array(); + $handlers = array(); + foreach($files as $i => $url) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_NOBODY, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_multi_add_handle($mh, $ch); + $handlers[$i] = $ch; + } + $running=null; + do + { + curl_multi_exec($mh, $running); + usleep (250000); + } while ($running > 0); + foreach($handlers as $i => $ch) { + $content = curl_multi_getcontent($handlers[$i]); + curl_multi_remove_handle($mh, $handlers[$i]); + $content = explode("\r\n", $content); + $headers = array(); + foreach($content as $header) { + if (substr($header, 0, 5) == 'HTTP/') { + $header = explode(' ', $header); + $headers['http'] = $header[1]; + } elseif ($header != '') { + preg_match('/^([a-z0-9\-]*):\s(.*)$/Ui', $header, $m); + $headers[strtolower(str_replace('-', '_', $m[1]))] = $m[2]; + } + } + $headers_all[$i] = $headers; + } + curl_multi_close($mh); + return $headers_all; + } } \ No newline at end of file diff --git a/php/index.php b/php/index.php index 863d228..e4f951a 100644 --- a/php/index.php +++ b/php/index.php @@ -16,7 +16,7 @@ $running = (strpos($tmp, '/opt/local/bin/php') !== false) ? 1 : 0; BeatHaven - +