Skip to content

Instantly share code, notes, and snippets.

@faryne
Created March 5, 2012 08:45
Show Gist options
  • Save faryne/1977508 to your computer and use it in GitHub Desktop.
Save faryne/1977508 to your computer and use it in GitHub Desktop.
利用PHP抓Youtube影片(範例程式)
<?php
/**
使用前請先下載phpQuery,
否則你需要自己改寫get_meta_data方法的內容
*/
require_once 'libraries/phpQuery.php'; // 請更改為phpQuery的位置
define('lang_ytdl02', '低品質影片', true);
define('lang_ytdl03', '標準品質影片', true);
define('lang_ytdl05', '高畫質影片', true);
define('lang_ytdl06', '超高畫質影片', true);
class ytdl
{
// 每一個ID代表一種格式,這裡只列基本的部份。其他還有3gp等格式可用......
private $_format = array(
'5' =>array('format'=> 'FLV', 'res'=> '240p', 'desc'=> lang_ytdl02),
'18'=>array('format'=> 'MP4', 'res'=> '360p', 'desc'=> lang_ytdl02),
'22'=>array('format'=> 'MP4', 'res'=> '720p', 'desc'=> lang_ytdl05),
'34'=>array('format'=> 'FLV', 'res'=> '360p', 'desc'=> lang_ytdl02),
'35'=>array('format'=> 'FLV', 'res'=> '480p', 'desc'=> lang_ytdl03),
'37'=>array('format'=> 'MP4', 'res'=> '1080p', 'desc'=> lang_ytdl06),
'38'=>array('format'=> 'MP4', 'res'=> '4k', 'desc'=> lang_ytdl06),
'43'=>array('format'=> 'WebM', 'res'=> '360p', 'desc'=> lang_ytdl02),
'44'=>array('format'=> 'WebM', 'res'=> '480p', 'desc'=> lang_ytdl03),
'45'=>array('format'=> 'WebM', 'res'=> '720p', 'desc'=> lang_ytdl05),
'46'=>array('format'=> 'WebM', 'res'=> '1080p', 'desc'=> lang_ytdl06),
);
private $_ytid;
/**
建構子
string $ytid: Youtube影片ID
string $memory_limit: 因為抓影片時有可能耗盡記憶體,所以此值可以設大一些。不過256M應該是足夠了......
*/
public function __construct ($ytid, $memory_limit = '256M') {
$this->_ytid = $ytid;
ini_set('memory_limit', $memory_limit);
if (!class_exists('phpQuery')) {
throw new Exception('No phpQuery class. Please download it at http://code.googe.com/p/phpQuery');
}
}
/**
取得影片標題與各種解析度的影片位址
*/
public function get_meta_data () {
$output = array('title'=>'', 'videos'=>array());
// 這裡是抓影片播放頁的資料,如果要減少傳輸量的話,可以用http://www.youtube.com/get_video_info?video_id={ytid},可以少抓很多html廢話,效果也是一樣啦
$url = 'http://www.youtube.com/watch?v='.$this->_ytid;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($info['http_code'] > 299 || $info['http_code'] < 200) {
throw new Exception("Cannot fetch video data");
}
// 這部份是要抓出影片標題以便掛在影片url用,不過老實說我沒實驗過不加這個會不會怎樣呢?
$output['title'] = pq('#eow-title', $pq)->attr('title');
// 接著要來parse影片的位址了
$pattern = '#"url_encoded_fmt_stream_map": "([^"]*)"#i';
preg_match($pattern, $content, $match);
if (!isset($match[1])) {
throw new Exception('Cannot parse video information');
}
$links = explode(',', $match[1]);
foreach ($links as $link) {
parse_str($link, $d);
if (!isset($d['url'])) {
continue;
}
$url = str_replace('\\', '', $d['url']);
$url = preg_replace('#(u0026[^&]*)#', '', $url).'&title='.urlencode($output['title']);
preg_match('#itag\=([0-9]{1,2})#', $url, $tag);
$output['videos'][strval($tag[1])] = $url;
}
// 傳回結果
return $output;
}
/**
將影片寫入成為檔案
string $url: 影片的uri
string $filename: 要存檔的位址
*/
public function get_video ($url, $filename) {
// 先把檔案抓下來
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$result = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($info['http_code'] > 299 || $info['http_code'] < 200) {
throw new Exception("HTTP Retrieve failed({$info['http_code']})");
}
// 抓下來以後再寫入
$fp = fopen($filename, 'w');
if (!$fp) {
throw new Exception("File Open Error");
}
fwrite($fp, $result);
fclose($fp);
return true;
}
}
try {
$ytid = "NvB5IhJ-m40";
$ytdler = new ytdl($ytid);
$info = $ytdler->get_meta_data();
if (!isset($info['videos']['5'])) {
throw new Exception("Cannot get low resolution video";
}
// 抓影片啦
$filename = $ytid.".mp4";
$ytdler->get_video($info['videos']['5'], $filename);
} catch (Exception $e) {
echo 'Error: '.$e->getMessage()."\n";
die();
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment