Pull to refresh

Делаем личный сборник радио-чартов

Reading time5 min
Views2.1K
ВКонтакте многими нелюбим, однако он предоставляет замечательное и стабильное хранилище музыки. В рамках описываемого ниже скрипта мы научимся скачивать оттуда песню по названию, парсить чарты радиостанций и паковать скачанные нами песни в zip-архив. Песни будут пронумерованы согласно месту в чарте, и 100 песен обычно легко влазят на компакт-диск — автомобилистам понравится.
Также в одной из главных ролей сайт moskva.fm, заботливо собравший в одном месте список большого числа радиостанций с чартами. Все очень тривиально, но думаю многим начинающим программистам будет интересно.
Скрин того, что получилось:


По щелчку по логотипу происходит скачивание свежего zip-архива топ100 этой станции, содержащего файлы в mp3 формате.
Итак, пойдем от меньшего к большего:
	error_reporting(E_ALL);
	//мы будем использовать проект simplehtmldom
	include_once('simplydom.php');
	//100 файлов х 50 станций = 5000 файлов
	//поэтому ставим тайм-лимит 9000
	set_time_limit(9000);

Проект SimpleHTMLDOM — это неприхотливый аналог SimplyXML и других библиотек работы с HTML/DOM. Отличительные особенности: писал китаец, что видно по названию, абсолютно плюет на ошибки в разметке, пытаясь разбирать файл как получится; падает в segmentation fault после пары использований; люто ест память, т.к. для каждого узла хранит в самом же объекте родителей и детей, внутренности можно наглядно посмотреть выведя через print_r объект, также есть небольшие, сразу незаметные, но очень крутые штуки, например, можно искать по отрицательным индексам, т.е. если нам нужно получить третий с конца страницы div, то никаких трудностей нам это не составит.
Пойдем дальше — напишем функцию, которая будет получать песню по названию и сохранять в определенном нами месте.
/*
*  функция получает на входе название или часть названия песни $title
*  ищет эту песню и скачивает в папку $path,
*  сохраняя в файл с названием "$number $title.mp3"
*/
function getSongByTitle($title,$path,$number) {
	// вконтакте требует наличие UserAgent
	$user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.2.13)';
	$cookie = '';
	// наши данные для доступа
	$login = '*******@gmail.com';
	$password = '********';
	//инициализируем cURL
	$ch = curl_init();
	//мы будем слать POST запрос
	curl_setopt($ch, CURLOPT_POST, true);  
	//установим UserAgent
	curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
	//нам не нужно выводить на экран результат запроса
	//мы будем его использовать для получения ссылки на скачивание
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	//установим таймаут в рамках разумного
	curl_setopt($ch, CURLOPT_TIMEOUT, 10);
	//если вдруг нам отдадут Location: ... 
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	//и собственно куда мы будем слать наш запрос
	curl_setopt($ch, CURLOPT_URL, 'http://login.vk.com/?act=login');
	//формируем POST-запрос
	$post = array(
	            'act' => 'login',
	            'q' => '',
	            'al_frame' => '1',
	            'expire' => '',
	            'captcha_sid' => '',
	            'captcha_key' => '',
	            'from_host' => 'vkontakte.ru',
	            'email' => $login,
	            'pass' => $password
	        );
	curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
	//действуем
	$answer = curl_exec($ch);
	//самое главное - получаем вконтактовскую сессию
	$sid = substr($answer, strpos($answer, "setCookieEx('sid', '") + 20, 60);
	$cookie = 'remixsid=' . $sid;
	//теперь мы будем делать GET
	curl_setopt($ch, CURLOPT_POST, false);
	//используем cookie
	curl_setopt($ch, CURLOPT_COOKIE, $cookie);
	//новый URL
	curl_setopt($ch, CURLOPT_URL, 'http://vkontakte.ru/al_search.php?al=1&c[q]='.urlencode($title).'&c[section]=audio');
	//получаем страничку поиска песни
	$answer = curl_exec($ch);
	curl_close($ch);
	//вконтакте отдает и не совсем json и не совсем html 
	//ну в общем было решено сделать так
	$answer = substr($answer,strpos($answer,'{"section":"audio"'));
	$answer = substr($answer,strpos($answer,'<!> ')+4);
	$answer = trim($answer);
	//если вдруг мы уже скачали файл, то ничего не делаем
	if (!file_exists($path . $number . ' ' . $title . '.mp3')) {
		if (strpos($answer,'По Вашему запросу не найдено популярных результатов')==false) {
			//используем библиотеку simplydom,
			$html = str_get_html($answer);
			//ищем первый же input, в 99% случаев это 
			//самая нормальная и качественная версия
			$filelink = $html->find('input',0)->attr['value'];
			//ссылка на песню находится в формате http://....mp3,bitrate
			//если кто-то хочет - может дополнительно использовать bitrate
			$filelink = explode(",",$filelink);
			$filelink = $filelink[0];
			echo "Пытаюсь получить песню $filelink \n";
			$ch = curl_init();
			//открываем файл для записи (выше мы проверили, что его нет)
			$fp = fopen($path . $number . ' ' . $title . '.mp3', 'w');
			//мы получаем ответ от cURL непосредственно в файл
			curl_setopt($ch, CURLOPT_FILE, $fp);
			curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
			curl_setopt($ch, CURLOPT_URL, $filelink);
			curl_setopt($ch, CURLOPT_COOKIE, $cookie);
			$answer = curl_exec($ch);
			fclose($fp);
			echo "Получил песню $filelink \n";
			//если не сделать очистку, то после пары песен PHP выдаст seg.fault
			$html->clear(); 
			unset($html);
		} else {
			echo "Песня не найдена\n";
		}
	}

}


/*
*  функция создает zip-архив, получая на входе список файлов и папку назначения
*/
function create_zip($files = array(),$destination = '') {
	if(file_exists($destination)) { return false; }
	$valid_files = array();
	if(is_array($files)) {
		foreach($files as $file) {
			if(file_exists($file)) {
				$valid_files[] = $file;
			}
		}
	}
	if(count($valid_files)) {
		$zip = new ZipArchive();
		if($zip->open($destination,ZIPARCHIVE::CREATE) !== true) {
			return false;
		}
		foreach($valid_files as $file) {
			$zip->addFile($file,$file);
		}
		$zip->close();
		return file_exists($destination);
	} else {
		return false;
	}
}

$filename = array();
$filename[] = array('href'=>'http://www.moskva.fm/stations/FM_90.8/top100','fm'=>'90_8');
// тут длинный список станций, с которых мы будем получать чарты
//можно взять список с любого другого сборника чартов и настроить парсинг
$filename[] = array('href'=>'http://www.moskva.fm/stations/FM_101.2/top100','fm'=>'101_2');

foreach ($filename as $item) {
	//всё как и раньше - получаем страничку с чартом
	$user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.2.13) Gecko/20101203';
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
	curl_setopt($ch, CURLOPT_URL, $item['href']);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
	$answer = curl_exec($ch);
	$answer = trim($answer);
	curl_close($ch);
	echo 'Получил чарт станции' . $item['href'] . '
';
	$html = str_get_html($answer);
	//в $filesarray мы будем хранить список файлов в виде абсолютных путей к ним
	$filesarray = array();
	for ($i = 0; $i < 100; $i++) {
		echo '----' . $i . '--------
';
		$song = $html->find('td[class=name] p a[class=song]', $i)->innertext;
		$artist = $html->find('td[class=name] p a[class=artist]', $i)->innertext;
		$fullsongname = $artist . ' - ' . $song;
		echo 'Скачиваю песню  ' . $i . ' ' . $fullsongname . "\n";
		if (!is_dir($_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'])) {
			mkdir($_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'],0755);
		}
		//это сделано для того, чтобы на всех автомагнитолах после записи диска 
		//песни располагались по порядку их следования в чарте
		if ($i+1<10) {
			$number = '0'.$i+1;
		} else {
			$number = $i+1;
		}
		//скачиваем песню
		getSongByTitle($fullsongname,$_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'].'/',$number);
		//и добавляем полученный файл в массив
		$filesarray[] = $_SERVER['DOCUMENT_ROOT'].'/mp3/'.$item['fm'].'/' . $number . ' ' . $fullsongname . '.mp3';
		echo "Скачал песню\n";
	}
	if (!is_dir($_SERVER['DOCUMENT_ROOT'].'/zip')) {
		mkdir($_SERVER['DOCUMENT_ROOT'].'/zip',0755);
	}
	//пакуем в архив для удобной скачки
	create_zip($filesarray,$_SERVER['DOCUMENT_ROOT'].'/mp3/zip/'.$item['fm'].'.zip');
	//если не сделать очистку, то после пары песен PHP выдаст seg.fault
	$html->clear(); 
	unset($html);
}



Подборка логотипов с указанием московской частоты cтанций + красивая png
Tags:
Hubs:
Total votes 7: ↑6 and ↓1+5
Comments6

Articles