2009年7月30日 星期四

攻略:javascript下載youtube影片(PHP+jQuery)

不知不覺blog文章來到第100篇
說來慚愧,雖然申請部落格是兩三年前的事情了
但是真的開始有用的習慣也是前幾個月才開始的
------------------------------------------------
今天因老師請託要下載youtube的影片
我就藉這個機會來研究他的原理
目前網路上的教學大概都是找出實體檔案的方式來下載youtube的檔案
常用程式碼如下
JavaScript
一般FLV畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&l=" + swfArgs['l'] + "&sk=" + swfArgs['sk'] + '&t=' +
swfArgs['t'];

HQ畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&fmt=18" + "&l=" + swfArgs['l'] + "&sk=" +
swfArgs['sk'] + '&t=' + swfArgs['t'];

HD畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&fmt=22" + "&l=" + swfArgs['l'] + "&sk=" +

原文網址

但是我覺得光這樣太無趣了點,於是在去研究了一下原理

開了Fiddler去看一下封包

youtube實體影片是像其底下的get_video這網頁要來的(其實看上面javascript碼就知道了)
他帶了許多參數,後來發現,如果不考慮畫面,直接下載純影像的話
其實必備只須要下面兩個參數就夠了
  1. video_id
  2. t
是的,只須要上面兩個參數就可以開啟影片下載

舉個例子
http://www.youtube.com/watch?v=hjTb2gR8rpE&feature=related
隨便開啟一個youtube影片,打開他的HTML原始碼觀看
之後找到flash影片參數的部分,也就是 swfArgs的部分
這部份知識請去摸一下flash就會知道了


var swfArgs = {"usef": 0, "fexp": "903900", "enablecsi": "1", "watermark": "http://s.ytimg.com/yt/swf/logo-vfl106645.swf,http://s.ytimg.com/yt/swf/hdlogo-vfl100714.swf", "sourceid": "yw", "video_id": "hjTb2gR8rpE", "l": 15, "fmt_map": "18/512000/9/0/115,34/0/9/0/115,5/0/7/0/0", "feature": "related", "sk": "nZDATrs2t38ie9xRcRK_a3mjI-RuKXhPC", "is_doubleclick_tracked": "1", "vq": null, "t": "vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4=", "hl": "zh_TW", "plid": "AARv6bNtawhBJVmH", "keywords": "%E6%96%B0%E4%B8%96%E7%B4%80%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%B3%E3%82%B2%E3%83%AA%E3%82%AA%E3%83%B3%2C%E7%B6%BE%E6%B3%A2%E8%82%B2%E6%88%90%E8%A8%88%E7%94%BB%2C%E3%82%A2%E3%82%B9%E3%82%AB%E8%A3%9C%E5%AE%8C%E8%A8%88%E7%94%BB%2CPS2", "cr": "TW", "fmt_url_map": "18%7Chttp%3A//v22.lscache7.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D18%26ipbits%3D0%26signature%3D12986C2C910D07BD87B445AE1164DDDC8330C06A.4AC1217E49AC790C83083037590C528C82E6A187%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91%2C34%7Chttp%3A//v3.lscache8.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D34%26ipbits%3D0%26signature%3D1B606B2E46C0471A611386C163B6B18FB617D7AD.0CA6C95A06F6D8E55C99A4552B4066CB1CD541C6%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91%2C5%7Chttp%3A//v6.lscache2.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D5%26ipbits%3D0%26signature%3D14E5E77EB01FE7F0152AA1318492DFBDE6A42BA5.CA1E4504117C976ECC479DFF573BD96E3E9685D4%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91", "sdetail": "f%3Arelated%2Crv%3A2yRxIwkBelc"};

他裡面帶很多參數,但是在此我們把問題簡化,只關心裡面的video_id跟t參數

.......
"video_id": "hjTb2gR8rpE"
"t": "vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4="
......


之後我們只要把這兩個參數合併到youtube的網址就可以直接下載檔案如下

http://www.youtube.com/get_video?video_id=hjTb2gR8rpE&t=vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4=

之後把他放到網址列按enter就可以下載影片了

那我們是否可以把這個工作自動化呢
當然可以,了解原理後,剩下的就只是字串處裡的問題而已
如何把兩個參數給抓出來
在此我們用jQuery+PHP實作一個簡單的範例
首先須要一個html檔當界面來接受我們網址的輸入

<body>
<input id="url" type="text" />
<input type="button" value="Get" onclick="getFlv();" />
</body>

再簡單不過的一個範例,一個textbox跟一個button
用一個function,getFlv()來處理我們的需求
而jQuery的部分也很單純

function getFlv(){
var url=$('#url').get(0).value;
$.post("getYouyube.php",{'url':url},function(data){
location.href='http://www.youtube.com/get_video?'+data
});
}


首先使用$('#url')或得textbox,並用get函式把他從jQuery物件轉成DOM物件
這樣我們才能抓取他的value
之後用一個post的請求給我們處裡字串的程式 getYouyube.php(這邊我打錯字 但是我也不想改了)
送一個參數url,也就是我們輸入的youtube網址
之後用location.href轉址就可以自動下載了

至於PHP的部分,他只是一些字串處裡而已

$html=file_get_contents($_POST['url']);
$arr=split("\n",$html);
$num=count($arr);
for($i=0;$i<$num;$i++)
{
if(ereg("swfArgs",$arr[$i]))
{
getArgs($arr[$i]);
}
}

首先用file_get_contents得到輸入網址的HTML原始碼
之後把它切割成一行一行的陣列 直到找到我們的目標swfArgs為止
之後我們用一個自定函式getArgs去抓出我們要的參數 video_id跟t


function getArgs($text)
{
$arr=split(",",$text);
$num=count($arr);
for($i=0;$i<$num;$i++)
{

$key=strtok($arr[$i],':');
$value=stripShell(strtok(':'));
if(strcmp(trim($key),"\"video_id\"")==0)
{
echo sprintf("%s=%s&",stripShell($key),$value);
}
else if(strcmp(trim($key),"\"t\"")==0)
{
echo sprintf("%s=%s&",stripShell($key),$value);
}

}
}
/*去頭尾字元*/
function stripShell($str)
{
return substr($str,2,-1);
}


結果展示

功能非常陽春,而且是適用於目前的youtube
他以後若改版之類的就不保證啦
不過可以根據參數這部份來提供更多服務,譬如說畫質選擇、檔名等等
這部份就以後再說吧

2009年7月28日 星期二

web學習-跳出式對話框 使用jQuery

雖然這對話框這東西已經有一大堆現成套件可以用了
但是基於求知的心態還是會想要知道他是怎麼弄的
下面一個自己寫的範例



很簡單的功能,就跳出一個訊息然後可以關掉

這個範例須要四個元素
  1. 一個看效果網頁,隨便弄一個就好了 這邊拿DW的範例當底(懶惰一下)
  2. 一個起動開啟Dialog事件的按鈕

    <input type="button" value="叫出對話框" onclick="showDialog();" >

  3. 一個遮住底頁的黑色不透明區塊

    <div id="dialog"></div>

  4. 真正要顯示訊息的區塊,他包含關閉Dialog事件的按鈕

    <div id="msg">
    <p>這是一個測試的對話框</p>
    <input type="button" value="關閉" onclick="closeDialog();" />
    </div>



-------
除了範例網頁之外,第三跟第四個元素,也就是Dialog對話框的Div可以隨便放
因為他們的位置是用絕對位置控制

先來觀察css設定的部分

html,body {
margin: 0;
padding: 0;
height:100%;
}

這第一部分,為了跟舊firefox相容,所以必須連html tag也設定,而不能光設定body tag
在此把height設為100%,不然的話IE6的div元素沒有辦法延展至100%
並且margin設為0,避免延展後的div區塊跟瀏覽器有間隔(這邊也是IE的bug)
下面是不加margin: 0;的效果,明顯可以看出遮擋的div沒有完全填滿視窗


接著看其他css設定

#dialog{
/* 非IE瀏覽用設定,使其長寬都延展至100% */
position:fixed;
top:0px;
left:0px;
width:100%;
height:100%;
margin:0px;
background-color:#000000;
z-index:1;
text-align:center;
}
*html #dialog{position:absolute;}/*IE舊瀏覽器用,設定絕對定位*/

#msg{ /*訊息區塊,背景設為白色,使用絕對定位*/
position:absolute;
top:0px;
left:0px;
background-color:#FFFFFF;
width:400px;
z-index:3;
}

在firefox就算height設成100%,但是會出現一個問題,他不像IE會自動填補scroll延展的部分,所以只要頁面有scroll並且往下拉就會破功
所以在此使用position:fixed來固定遮罩區塊,但是另一個問題出現了
就是IE不支持position:fixed這個屬性
所以我就利用了css hack的技巧,把IE挑出設定成position:absolute;
*html 是IE only的語法 可以拿來應付這種狀況

下圖是firefox使用position:absolute;來設定height:100%時的狀況

最後把z-index設置一下就ok了

之後就是jQuery的部分了,總共分成三大部分

第一部分,當DOM初始化之後,要先把對話框給隱藏起來
並且把遮罩div的透明度設成0.5
透明度設定請參照
http://hatsukiakio.blogspot.com/2009/07/jquerycss.html

$(document).ready(function(){
$("#dialog").css("display","none");
$("#msg").css("display","none");
$("#dialog").css("opacity","0.5");

});


第二部份是msg的div中,要關閉對話框的事件區動,說是關閉,也只是把dialog隱藏起來而已

function closeDialog(){
$("#dialog").css("display","none");
$("#msg").css("display","none");
}


第三部份,show出dialog,這部份比較雜一點

function showDialog(){
/*秀出對話框*/
$("#dialog").css("display","");
$("#msg").css("display","");

var _sw=document.body.clientWidth;//得到視窗寬度
var _sh=document.body.clientHeight;//得到視窗長度
if($.browser.msie)//判斷使否為IE
{
_sh-=260;
_sw-=24;
}
/*
var scrolltop;
//得到scroll的現在位置
if (document.documentElement && document.documentElement.scrollTop)
{
scrolltop=document.documentElement.scrollTop;
}
else if(document.body){
scrolltop=document.body.scrollTop;
}
*/
var w=$("#msg").width();
var h=$("#msg").height();
var _top=_sh/2-h/2+$(document).scrollTop();//更好的方法 使用jQuery解決
var _left=_sw/2-w/2;

/*設定視窗出現位置*/
$("#msg").css("top",_top+'px');
$("#msg").css("left",_left+'px');
}

要show出對話框,只要把他的display屬性從none改成空值及可
之後可以用document.body的clientWidth跟clientHeight得到視窗的大小
再來有一點也是瀏覽器的問題,IE會把上面工具列的部分也算在視窗size裡
所以要用jQuery的$.browser.msie來判斷是不是IE來做修正
最後是得到scroll的位置,一開始我是用document.documentElement去取得
但是後來發現jQuery的+$(document).scrollTop()就能做到相同的事情了

使用JQuery取代css設置方案

研究jQuery真是對他越來越愛用
他的強大真是難以言喻,今天在玩一些css設計
原本一些難搞的瀏覽器相容性他都替我處理好了
原本我以為jQuery只能替我排除javascript在瀏覽器上的相容性問題
想不到他連css都替我handle了 真是件令人愉快的事情

舉個例子,元素透明度的設定問題
元素半透明的效果可以讓網頁更佳炫麗,但是考慮到瀏覽器問題這往往須要注意很多東西

<style>
.opac{
opacity:0.5; //for firefox
-moz-opacity:0.5;
filter:alpha(opacity=50); //for IE
}
</style>


如上面所示,設定個透明度為了瀏覽器相容必須設定同個屬性三次
但是使用jQuery呢,我們只須要一行程式碼就能解決

<script type="text/javascript">
$(document).ready(function(){
$('.opac').css("opacity","0.5");
});
</script>


這樣一來,要設計網頁障礙就更小了~

2009年7月27日 星期一

IE6下,不出現警告訊息關閉視窗

當我們用javascript的window.close();關閉視窗的時候
如果是母視窗的話就會跳出如下的警告訊息


也就是目前要關閉的視窗不是藉由window.open()來開啟的子視窗
他沒辦法藉由window.close來直接關閉
可以使用window.opener=null;來避開這項限制
也就是在執行close前先把opener設成null

window.opener=null;
window.close();

2009年7月26日 星期日

PHP 寫XML,responseXML一直為null

最近在玩jQuery,碰到了一些有趣的問題
當我用$.ajax像PHP送出要求一個XML文件的時候
照道理他回傳的是一個XMLHttpRequest,然後可以用他得到XML文本

var html = $.ajax({
url: "ajaxOutput.php",
async: false
,type: "GET"
}
).responseXML;

但是卻發生了responseXML總是為null的狀況,後來查了一下HTTP封包
他似乎被解讀成HTML文本 所以無法轉換
因為responseText可以正確抓到值

後來看了一下的我PHP程式碼

<?php
echo '<?xml version="1.0"?>';
echo '<book>';
echo 'jQuery';
echo '</book>';
?>

沒什麼問題,但是卻沒辦法讀取,找了一些範例好像也都是這樣寫
讀純xml也很正常


var html = $.ajax({
url: "test.xml",
async: false
,type: "GET"
}
).responseXML;


那倒底問題是出在哪裡
後來又看了一下jQuery文件

dataType (String) : (預設值:智能判斷xml或者html)預期服務器返回的資料類型。如果不指定,jQuery 將自動根據 HTTP 包 MIME 資訊返回 responseXML 或 responseText,並作為回調函數參數傳遞,可用值:

這樣就我就明白了,他會根據MIME來判斷這份文件是什麼類型
也就是必須透過Content-type告訴AJAX他是什麼東西,因此我必須告訴他我是一個XML文件
因此我只要設定一下header就能解決了 如下

<?php
header('Content-type: application/xml');
echo '<?xml version="1.0"?>';
echo '<book>';
echo 'jQuery';
echo '</book>';
?>

2009年7月20日 星期一

cannot send session cache limiter-headers already sent錯誤

今天幫學校弄網頁,使用PHP 因為我本身對PHP不熟,所以也碰到不少麻煩
在我使用session_start();想要啟用session的時候出現了

...cannot send session cache limiter-headers already sent....

這樣的錯誤,後來查了一下資料
在使用session_start()的時候網頁要避免有output,包括標準HTML串流

<?php
echo 'Hi';
session_start();
?>

或是
<html>
<?php
session_start();
?>

這樣也是不行,session_start()必須保證執行他之前沒有任何output,甚至是一個空白也不行
所以只要改成下面這樣就行了

<?php //php程式碼從網頁第一行第一格開始(且沒有空格)

session_start();
echo 'Hi~' //output在session_start()之後
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


又或者是更改php.ini,把output_buffering給打開
output_buffering預設是

output_buffering = off

可以改成

output_buffering = 4096

這樣就算大功告成了

2009年7月12日 星期日

VOCALOMARK 初音版顯卡測試軟體

前一陣子因為在忙趨勢科技的雲端運算程式比賽加上碰到畢業旅行
停了好一陣子沒寫Blog,有機會把雲端程式撰寫的心得整理一下PO成文章好了
這之間看了不少資料可以好好整理

-----------------------------------------------------

這期電腦王介紹了一款測試顯卡的軟體VOCALOMARK
他是由當紅音樂軟體-初音ミク來當影片測試主角
檔案非常的小,麻雀雖小五臟俱全

主網站
http://fakefar.jp/vocalomark.html

現階段下載位址
http://fakefar.jp/data/VocaloMark(bb).zip

PCADV的介紹文章
http://www.pcadv.com.tw/?p=7967

如果音源無法出現的話,我另外抽出了mp3音源
請在找轉檔軟體轉成wav應該就可以撥放了
http://w5.loxa.com.tw/hua0053/dummy.mp3

看官網說他目標是讓ミク・リン・レン三人一起跳舞
沒有巡音ルカ還真可惜

雖然這類測試軟體也不少,像之前的TimeLeap也是這種萌系少女跳舞唱歌的測試軟體
不過初音畢竟是大家比較熟的,一起玩玩總是比較有親切感

設定界面,個人覺得很不錯的一點是他提供選擇SOFTWARE或是HARDWARE或是MIxED三種模式
有DirectX遊戲開發經驗的應該可清楚這三種模式的差別
SOFTWARE主要是把繪圖運算工作交給CPU
HARDWARE怎是把繪圖運算工作交給顯示卡
第三種則是混合模式,並且有提供反鋸齒的選項












來看看選單界面吧,還蠻簡單的,畢竟是開發階段的東西














選Play之後就可以開始看可愛的初音跳舞啦


紳士密技:按F8可以固定視角,之後配合W、S、A、D加滑鼠轉動
可以看到初音的胖子


-----------------------------------------------
補個測試結果
我筆電 8600GT大概是3200
我學長ASUS ATI 4670 大約11000

果然時代進步真快阿