Youtube 在擷取影音串流多將原本的 sig參數改為 signature,但是在取得 Video Information的網址並沒有跟著修改,我參照了 youtube-dl的改法將 parse的規則改了一下,應該就過囉.只是不知道何時會再修改就是了.
記錄在下方這個commit.
https://github.com/kvzhuang/video-parser/commit/1d2c6cb7b5de852951d1eaf8153a6e0ee984409a
最近因為一些需求在研究youtube的影音串流網址,其目的就是有一個 youtube影片的URL,最後得到此影片真實的影音串流.
分做三個部分:取得youtube的原始影音串流,取得字幕檔,處理解析度.
影音串流:
然而有一個問題就是跨國之間 youtube的影音串流網址不同,如果我們使用一個 API Server架在台灣,若其他國家來跟我們詢問,透過的是我們網段取得的影音串流網址,再轉給其他國家將會無法使用.
所以把目標轉到 JavaScript,這個網路上有很多人做,主要就是透過 Bookmark(或是Greasemonkey),在使用者端執行 Script Injection.做法有很多,如 Vexe'd有介紹用我的最愛下載 YouTube 影片.如果要更複雜一點的就如下方的 Script,可以把它貼到bookmark裡面,在看影片時候執行即可以下載影片.
javascript:(function() {
function get_filetype(fmt_id) {
switch(fmt_id) {
case '5':
case '6':
case '34':
case '35':
return 'FLV';
case '18':
case '22':
case '37':
case '38':
case '82':
case '83':
case '84':
case '85':
return 'MP4';
case '43':
case '44':
case '45':
case '46':
case '100':
case '101':
case '102':
return 'WEBM';
default:
return 'unknown';
}
}
function get_video_url(fmt_stream_map,
chosen_fmt_id,
avail_fmt_ids) {
fmt_stream_map=unescape(fmt_stream_map);
if(avail_fmt_ids.indexOf(chosen_fmt_id)===0)
return
fmt_stream_map.substring(4,
fmt_stream_map.indexOf('&quality='));
if(avail_fmt_ids.indexOf(chosen_fmt_id)===avail_fmt_ids.length-1)
return
fmt_stream_map.substring(fmt_stream_map.lastIndexOf('http'),
fmt_stream_map.lastIndexOf('&quality='));
var pattern=new RegExp('&itag='+avail_fmt_ids[avail_fmt_ids.indexOf(chosen_fmt_id)-1]+',url=(.+?)&quality=');
return fmt_stream_map.match(pattern)[1];
}
(function main() {
var args=yt.playerConfig['args'];
var fmt_quality_list='';
var chosen_fmt_id=0;
var fmt_info=args['fmt_list'].split(',');
var fmt_resolution='';
var avail_fmt_ids=new Array(fmt_info.length);
for(var i in fmt_info) {
avail_fmt_ids[i]=fmt_info[i].split('/')[0];
fmt_resolution=fmt_info[i].split('/')[1];
fmt_quality_list+=(avail_fmt_ids[i]+' = '+fmt_resolution+' ('+get_filetype(avail_fmt_ids[i])+')\n');
}
loop: while(true) {
chosen_fmt_id=prompt('Please enter a format id.\n'+fmt_quality_list, avail_fmt_ids[0]);
if(chosen_fmt_id===null) {
return;
}
for(var i in avail_fmt_ids) {
if(chosen_fmt_id===avail_fmt_ids[i]) {
break loop;
}
}
}
window.open(get_video_url(args['url_encoded_fmt_stream_map'], chosen_fmt_id, avail_fmt_ids)+'&title='+document.getElementsByName('title')[0].content);
}());
}());
主要原理使用 Script Injection的概念透過 youtube當中的 JavaScript object: yt ,來取得所有的資訊.列出幾個比較常用的關鍵字:url_encoded_fmt_stream_map(原始影音串流URL),fmt_list(影片支援解析度列表).
字幕檔Subtitle:
Youtube把字幕檔放在他們家的 video.google.com,所以當有 Video ID跟確認有此語言的代碼,即可取得字幕檔.不過格式為 Google設計的XML檔案,要直接使用或許要做一些手腳.
範例連結:http://video.google.com/timedtext?lang=en&v=j3avqi1zObE
以下擷取 youtube-dl的轉換 xml->srt的操作.
def _closed_captions_xml_to_srt(self, xml_string):
srt = ''
texts = re.findall(r'([^<]+) ', xml_string, re.MULTILINE)
# TODO parse xml instead of regex
for n, (start, dur_tag, dur, caption) in enumerate(texts):
if not dur: dur = '4'
start = float(start)
end = start + float(dur)
start = "%02i:%02i:%02i,%03i" %(start/(60*60), start/60%60, start%60, start%1*1000)
end = "%02i:%02i:%02i,%03i" %(end/(60*60), end/60%60, end%60, end%1*1000)
caption = unescapeHTML(caption)
caption = unescapeHTML(caption) # double cycle, intentional
srt += str(n+1) + '\n'
srt += start + ' --> ' + end + '\n'
srt += caption + '\n\n'
return srt
影片格式 以及解析度:
Youtube也提供許多種影片格式,我們回到上面的 Script Injection Code可以知道,yt.playerConfig裏頭的 args['fmt_list']有此影片提供的格式.並且參照一次搞懂十種YouTube格式.整理出各fmt參數相對應的影片格式跟解析度.
舉例來說,如果我要取得720P的MP4影音串流,我就要設定我的影音串流URL的ittag為22就會有不同的影音串流.
(PS.我試了很多次直接在 youtube url裏頭設定fmt=22, fmt=45似乎已經不能設定影音格式了?)
沒有留言:
張貼留言