<?php
/***********************************************************
fvs_functions.php

FVSで使用する関数を一括して定義するファイル
クラス化は面倒+必要性に欠けるのでやらない
要PHP5以上、要rc4.php

このソースコードは修正BSDライセンスにて提供されています。
詳細なライセンスはファイル末尾をご覧ください。
動画再生用URLから動画ファイルへのURLを見つける処理は、
ほぼこのファイルに含まれるコードのみで実現されています。

だんだんファイルサイズが肥大化してきたので、本当は対策したいけど
単一ファイルのみコード公開するには今の方式があってるので、
どうすればいいか悩みどころ。
***********************************************************/

/*
ごく簡単な実装例
…っていうか、これ以上のことはほとんどしてないけど。

require_once("fvs_functions.php");
$url="http://www.nicovideo.jp/watch/sm9";
$id=get_id_from_url($url);
$result=get_flv_url_from_id($id['sid'],$id['vid']);
echo '<a href="'.htmlspecialchars($result['url']).'">動画データ</a>';

ただし、配信サービスなどによっては複数の動画URLを返す可能性があり、
その辺を気にするのであれば下の実装をよく読んだほうがいい気がしなくも無い。

今の実装だと関数の仕様が複数URLを返すことを考慮していないので、
そのうち作り変えるかもしれない。
*/

require( 'rc4.php' );
//http://pear.php.net/package/Crypt_Rc4/より、ArcFour(RC4)のクラス。
//…と言いつつ、http://captcha.jp/rc4_php.txtを使ってる自分(先に見つけたから)。
//Key()とsetKey()が変わってる位で基本的に同じものなので問題は無いんだけど、
//気になるのはcaptcha.jpの奴の方がバージョンが上だということ。
//なぜだ…pearが本家のはずでは…

include_once('mailmsg.php');
/*
function mailalart(
    $body='message from Flash☆Video☆Star',
    $title='message from Flash☆Video☆Star',
    $head="From: test@example.com\r\nContent-Type:text/plain;charset=ISO-2022-JP"
){
    $title=mb_encode_mimeheader(mb_convert_encoding($title,'ISO-2022-JP','UTF-8'),'ISO-2022-JP','Q');
    $body=mb_convert_encoding($body,'ISO-2022-JP','UTF-8');
    mail(
        'test@example.com',
        $title,
        $body,
        $head
    );
}

要はメッセージ送信先アドレスを知られないためだけの関数。
上の「include_once」をコメントアウトして、すぐ下の関数定義部分を有効にして、
test@example.comの部分(2箇所)を自分のアドレスにすればそれでOK。
現状、SMILEVIDEOの外部プレイヤーのバージョンが変わったことを検知したときだけ
メールが送信される。
*/

/*
fvs_functions.phpに引数「code」を渡すと、ソースコードが出力されるようになる実装
もし問題点があったらコッソリ教えてくれるとうれしかったりする。

稼動中のコードをそのまま公開してるけど、これが元で何らかの攻撃を受けることはない…と思う…
*/
if(isset($_GET["code"])){//引数codeが存在する場合
    
$myname="fvs_functions.php";
    if(
strpos($_SERVER["PHP_SELF"],$myname)!==FALSE){
        
Header("Content-Type: text/html; charset=UTF-8");
        
highlight_file($myname);
    }
}

/*==========================================================
定数定義
今のところそんなに多くない
==========================================================*/
//一時ディレクトリの相対パス
define("TMPDIR","tmp/");
//キャッシュ有効時間(秒)
define("CACHETIME",3600);
//ホスト名
define('MYSERVER',$_SERVER['SERVER_NAME']);
//スクリプトファイル名
define('MYNAME',$_SERVER['PHP_SELF']);

/*==========================================================
functions
==========================================================*/

/*----------------------------------------------------------
get_id_from_url($url)
$url:配信サイトのURL
戻り値:連想配列 [sid]に配信サイトID、[vid]に動画ID

動画配信サイトのURLを渡すと、配信サイトIDと動画IDが返る。
なお、配信サイトIDはトラブル防止のため半角英字のみとする。

URLからいきなり動画パスを得ないのは、
・ニコニコ動画がめんどくさい仕様である
・一時ファイルを特定の動画に対してUniqueな名前にする必要がある
などの理由でIDを決めておいた方が都合が良いから。
さらに言えば、ここで得られた配信サイトIDが正しいとは限らない。
例えば、GoogleVideoのURLを渡せば配信サイトIDは'GoogleVideo'になるが、
中身はYouTubeである可能性がある。これはget_flv_url_from_id()で自動是正される。

以前はurlencode()等は使用していなかったが、自分のサーバーでは問題なさそうなので
もう気にせず使うことに決定。
ちなみに一部サーバーだと%2F(/のエスケープ後)が名前に含まれるファイルに
FTPから一切アクセスできなくなる、などの苦しい仕様がある(NMNLがまさにそう)ため
あまり使いたくない、という事情があったりする。
別の方式でエンコードするという手もあるにはあるけども。
そういうわけなので、もしこのコードを流用したいという人がいるなら、
その辺の仕様をよく調べてから使ったほうがいいかもしれない。あとで消せないファイルとか出来ちゃうかも。

消せないファイルが出来ちゃった場合は、PHPで消せる。自力で何とか。
*/
function get_id_from_url($url){
    
$sid=FALSE;
/*--------------------------------------------------------*/
    
if(strpos($url,"http://www.nicovideo.jp/watch/")===0){        //ニコニコ動画
        
$vid=places_text($url,"http://www.nicovideo.jp/watch/","?");
        
conv_smile_id($sid,$vid);
    }
    elseif(
strpos($url,"http://tw.nicovideo.jp/watch/")===0){        //ニコニコ動畫 台灣
        
$vid=places_text($url,"http://tw.nicovideo.jp/watch/","?");
        
conv_smile_id($sid,$vid);
    }
    elseif(
strpos($url,"http://de.nicovideo.jp/watch/")===0){        //NICO NICO DOUGA Deutsch
        
$vid=places_text($url,"http://de.nicovideo.jp/watch/","?");
        
conv_smile_id($sid,$vid);
    }
    elseif(
strpos($url,"http://es.nicovideo.jp/watch/")===0){        //NICO NICO DOUGA Español
        
$vid=places_text($url,"http://es.nicovideo.jp/watch/","?");
        
conv_smile_id($sid,$vid);
    }
    elseif(
strpos($url,"http://www.nicovideo.jp/watch?v=")===0){        //ニコニコ動画(旧)
        
$vid=substr($url,strlen("http://www.nicovideo.jp/watch?v="),30);
        
conv_smile_id($sid,$vid);

    }
    elseif(
strpos($url,"http://www.smilevideo.jp/view/")===0){    //SMILEVIDEO
        
$vid="sm".places_text($url,"view/","/");
        
$sid="SMILEVIDEO";

    }
    elseif(
strpos($url,"http://www.smilevideo.jp/allegation/allegation/")===0){    //SMILEVIDEO
        
$vid="sm".places_text($url,"/allegation/allegation/","/");
        
$sid="SMILEVIDEO";

    }
    elseif(
strpos($url,"http://dic.nicovideo.jp/v/")===0){    //ニコニコ大百科
        
$vid=places_text($url,"http://dic.nicovideo.jp/v/","/");
        
$sid="SMILEVIDEO";

    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://photozou.jp/photo/show/")===0){        //フォト蔵
        
$vid=substr($url,strpos($url,"/",strlen("http://photozou.jp/photo/show/"))+1,30);
        
$sid="photozou";

    }
    elseif(
strpos($url,"http://nicovideo.photozou.jp/photo/show/")===0){    //フォト蔵(nicovideo)
        
$vid=substr($url,strpos($url,"/",strlen("http://nicovideo.photozou.jp/photo/show/"))+1,30);
        
$sid="photozou";

    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://vision.ameba.jp/watch.do?movie=")===0){    //AmebaVision
        
$vid=places_text($url,"movie=","&");
        
$sid="AmebaVision";

    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://www.veoh.com/")===0){    //Veoh
        
$vid=substr($url,strrpos($url,'/'),100);
        
$vid=places_text($vid,'/','#');
        
$sid="Veoh";
    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://www.guba.com/watch/")===0){    //Guba
        
$vid=places_text($url,"/watch/","?");
        
$sid="Guba";

    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://www.dailymotion.com/")===0){    //DailyMotion
        
$vid=places_text($url,"/video/","/");
        
$sid="DailyMotion";
    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://www.metacafe.com/")===0){    //MetaCafe
        
$vid=places_text($url,"/watch/","/");
        
$sid="MetaCafe";
    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://zoome.jp/")===0){        //zoome
        
$vid=urlencode(substr($url,strlen("http://zoome.jp/"),60));
        
$sid="zoome_diary";
    }
    elseif(
strpos($url,"http://circle.zoome.jp/")===0){    //zoome(サークル)
        
$vid=urlencode(substr($url,strlen("http://circle.zoome.jp/"),60));
        
$sid="zoome_circle";
    }
    elseif(
strpos($url,"http://navi.zoome.jp/")===0){    //zoome(Navi)
        
$vid=urlencode(substr($url,strlen("http://navi.zoome.jp/"),60));
        
$sid="zoome_navi";
    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://megavideo.com/")===0){    //MegaVideo
        
$vid=places_text($url,"v=","&");
        
$sid="MegaVideo";
    }
    elseif(
strpos($url,"http://www.megavideo.com/")===0){    //MegaVideo
        
$vid=places_text($url,"v=","&");
        
$sid="MegaVideo";
    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"youtube.com")!==FALSE){    //YouTube
        
$vid=places_text($url,"v=","&");
        
$sid="YouTube";
    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://video.google.com/videoplay")===0){    //GoogleVideo
        
$vid=places_text($url,"docid=","&");
        
$sid="GoogleVideo";
    }
/*--------------------------------------------------------*/
    
elseif(strpos($url,"http://www.nicovideo.jp/mylist/")===0){    //ニコニコ動画マイリスト
        
$vid=places_text($url,"mylist/","?");
        
$vid=str_replace("/","_",$vid);
        
$sid="nicovideo_mylist";
    }
    elseif(
strpos($url,"http://www.nicovideo.jp/ranking/")===0){    //ニコニコ動画ランキング
        
$vid=places_text($url,"nicovideo.jp/","?");
        
$vid=str_replace("/","_",$vid);
        
$sid="nicovideo_mylist";
    }
    elseif(
strpos($url,"http://www.nicovideo.jp/myvideo/")===0){    //ニコニコ動画ユーザー投稿動画
        
$vid=places_text($url,"nicovideo.jp/","?");
        
$vid=str_replace("/","_",$vid);
        
$sid="nicovideo_mylist";
    }
/*--------------------------------------------------------*/
    
elseif(stripos($url,"<")===0){    //入力すべきじゃないデータ
        
$vid=FALSE;
        
$sid='errurl';
    }
/*--------------------------------------------------------*/
    
else{
        
$vid=FALSE;
        
$sid="UnknownService";
    }
    if(
$vid==FALSE&&$sid!="errurl"){
        
$vid=FALSE;
        
$sid="UnknownService";
    }
    return array(
"sid" => $sid"vid" => $vid);
}

/*----------------------------------------------------------
conv_smile_id(&$sid,&$vid)
$sid:配信サイトIDを保持する変数
$vid:動画IDを保持する変数
戻り値:なし

ニコニコ動画の場合、複数の動画配信サイトに対応しているため、
それに応じてsidとvidを修正する。
引数は参照渡しで、それを直接変更するため、元の値が必要なら別途保持する必要がある。
ちなみに、$sidは変数が指定されていれば中身は空でもよい。

なお、get_id_from_url()から自動で呼ばれるので、普通自分で呼ぶことは無い。
*/
function conv_smile_id(&$sid,&$vid){
    
$buf=substr($vid,0,2);
    switch(
$buf){
        case 
"fz":    //フォト蔵
            
$vid=substr($vid,2,99);
            
$sid="photozou";
            break;
        case 
"am":    //AmebaVision
            
$vid=substr($vid,2,99);
            
$sid="AmebaVision";
            break;
        case 
"ut":    //YouTube
            
$vid=substr($vid,2,99);
            
$sid="YouTube";
            break;
        default:
            
$sid="SMILEVIDEO";
            break;
    }
    return;
}


/*----------------------------------------------------------
get_flv_url_from_id($sid,$vid)
$sid:配信サイトIDを保持する変数
$vid:動画IDを保持する変数
戻り値:連想配列
    'url' => 動画データ本体のURL
    'msg' => 追加メッセージ(HTML)
    'sid' => 動画サービスID
    'vid' => 動画ID
    'title' => 動画タイトル
    'mtype' => 動画種別

sidとvidから、FLVへのURLを取得(算出)する。
出力結果あるいはそれに必要なリソースは一定時間キャッシュされるので、
場合によっては短時間正確ではないURLが取得される可能性がある代わりに
配信サイトへの負荷にやさしいつくりとなっている。
デフォルト、というかこのスクリプトではキャッシュ時間は1時間。

取得できなかった場合は、[url]はFALSEになる。
補足文字列は、返らない場合もある。

戻り値のsidとvidは、(例えば)GoogleVideo内のYouTube動画のIDを渡した場合に、
ちゃんとsid=YouTube/vid=(YouTubeのID)で返すためのもの。
使用された配信サイトの管理など行いたい場合は、この戻り値を使用するべき。
*/
/*
実装方針

WebAPI、もしくはそれに準ずるインターフェイスが存在する場合(公式非公式問わず)はそれを利用する。
存在しない場合、できる限り相手サーバーへの負荷を減らして情報取得するようにする。

WebAPIはもともと外部から多数のアクセスがあることを前提として設計されている(はずである)ので
それを利用することで相手に与える負荷を軽減することができる
また正規の情報取得方法であるため、アクセス制御される可能性が低い

その他の負荷軽減方法としては、たとえばYouTubeのようにHTTP HEADを利用する方法がある。
HEADはGETよりネットワーク負荷が低いことは論を待たないので、利用できるならすべき。
(ネットワーク以外の負荷に関しては実装によるので分からないが、GETより負荷が
高くなることは無く、最悪でも同じ程度の負荷になるはず。)

以上の方法でどうしようもなく、かつ配信ページのHTMLにあるデータで何とかなる場合はそれを利用する。
どうにもならない、というケースは理論上は存在しない。ただし、URLが複雑な暗号化によって
隠蔽されている場合などはその解読が困難であるケースもありうる。
*/
function get_flv_url_from_id($sid,$vid){
    
$title=$vid."(タイトル取得失敗又はタイトル取得に非対応)";
    
$mtype="(種別判定に失敗)";
    
$errmessage="";
    
//$_return=NULL;
    
switch($sid) {
/*--------------------------------------------------------*/
/*
フォト蔵の公開APIを利用する。
*/
        
case "photozou":    //フォト蔵
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://api.photozou.jp/rest/photo_info?photo_id=".$vid);
            if(
$buf!==FALSE){
                
$rsp simplexml_load_string($buf);
            }else{
                
$baseurl=FALSE;
                
$errmessage="<p>フォト蔵のAPIへのアクセスに失敗しました</p>";
                break;
            }
            
$base1=$rsp->info->photo->thumbnail_image_url;
            if(
strpos($base1,"photozou.jp/pub/")===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>フォト蔵のAPIからのデータ取得に失敗しました。</p>";
                break;
            }
            
$base1=substr($base1,0,strpos($base1,"/photo/"));
            
$base2=$rsp->info->photo->large_tag;
            if(
strpos($base2,"movie")===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>動画データが含まれていません。<br>たぶん写真のURLです。</p>";
                break;
            }
            
$buf=strpos($base2,$vid);
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>フォト蔵のAPIからのデータ取得に失敗しました</p>";
                break;
            }
            
$base2=substr($base2,$buf,strpos($base2,"_",strpos($base2,"_",$buf)+1)-$buf);
            
$baseurl=$base1."/video/".$base2.".flv";
            
$title=$rsp->info->photo->photo_title;
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => "FlashVideo(.flv)"
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
AmebaVisionの公開APIを利用する。
*/
        
case "AmebaVision":    //AmebaVision
            
$buf cached_data_load(TMPDIR.$sid.$vid,"http://vision.ameba.jp/api/get/detailMovie.do?movie=".$vid);
            if(
$buf!==FALSE){
                
$data simplexml_load_string($buf);
            }else{
                
$baseurl=FALSE;
                
$errmessage="<p>AmebaVisionのAPIへのアクセスに失敗しました</p>";
                break;
            }
            
$base=$data->item->imageUrlLarge;
            if(
strpos($base,"ameba.jp/jpg/")===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>AmebaVisionのAPIからのデータ取得に失敗しました</p>";
                break;
            }
            
$startpt=strpos($base,"ameba.jp/jpg/")+strlen("ameba.jp/jpg/");
            
$length=strpos($base,"_4.jpg")-$startpt;
            
$baseurl=str_replace("/vi","/vm",substr($base,0,strpos($base,"/jpg/"))).
                 
"/flv/".substr($base,$startpt,$length).".flv";
            
$title=$data->item->title;
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => "FlashVideo(.flv)"
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
SMILEVIDEOは、特定条件下のアクセスに限り開放されているAPIのようなものが存在する。
API的なものにアクセスする際に必要な一時キーがあり、それを得るために外部プレイヤーインターフェイスを利用する。
アクセス時に特定のRefererを持っている必要があるが、Refererなんてものは(ブラウザの)自己申告であるため、
結局は多少手順が煩雑になるだけで、APIが外部に公開されているとほぼ同義であるといえる。
「特定のReferer」とはいわゆる「対応サイト」のURLであるが、どの程度の範囲まで
許容されるかはあまり詳しく調べていない。大百科のURLを使用すれば特定コミュニティ専用動画を除き
全ての動画に関して自動取得が可能なようだ。

ちなみに、☆ではUserAgentをPHPで固定にしているが、本当は適切なサービス名を入れるべき。
全自動ニコニコランキングの場合は「Fullauto_Nicoranker」とか入れてる。
…そのうち直しますって。
*/
        
case "SMILEVIDEO":    //SMILEVIDEO
            
do{
/*                //一時的に使用できなかったときの名残。
                $baseurl=FALSE;
                $errmessage="<p>SMILEVIDEOは現在対応サイトから外れています。再対応までちょっとお待ちください。</p>";
                break;
*/
                
conv_smile_id(&$sid,&$vid);//為念 ID渡しに対応した場合これをしないと個々で問題が出るはずなので
                
$baseurl2="http://www.nicovideo.jp/api/getflv?v=$vid";
                
$errmessage=<<< _EOD
<hr>
<p>
自分で1回以上再生した動画のみダウンロードできます。あらかじめいずれかの方法で再生を行ってください。<br>
※再生した記録がブラウザに残っている必要があるので、再生後ブラウザを閉じずにこのページに戻ってください。<br>
<a href="http://www.nicovideo.jp/watch/$vid" target="_blank">ニコニコ動画で再生する</a><br>
<a href="http://dic.nicovideo.jp/v/$vid" target="_blank">ニコニコ大百科で再生する</a><br>
</p>
<hr>
<div style="font:smaller;color:#999;">
<p>※以下に掲載されているのは従来の方法です。上に「データ取得に失敗しました」などと出ている場合にお試しください。(要ニコニコ動画ログイン+JavaScript有効)</p>
<ol>
<li><a href="$baseurl2" target="_blank">smileAPI的なもの</a>のリンクを押し、表示された文字列をコピーしてください。</li>
<li>このすぐ<strong>下にある</strong>フォームにコピーしたデータを貼り付けます。</li>
<li>「変換する」を押すと、ダウンロード用アンカーが出現します。</li>
</ol>
<p>これらの作業で、何らかの情報がFlash☆Video☆Starに送信される事はありません。</p>
<form name="base">
<input type="text" value="ここにデータを入力" name="urldata" onclick="clearform(this);"><input type="button" onClick="q=unescape(document.base.urldata.value);i=q.indexOf('url=');if(i==-1){document.all('result').innerHTML='動画URLが見つかりませんでした';}else{r=q.substring(i+4,q.indexOf('&',i));document.all('result').innerHTML='この動画(FLV)を<a href='+r+' target=_blank>ダウンロード</a>';}" value="変換する">
</form>
<p id="result">ここに結果がでます</p>
</div>
_EOD;
                
$buf=cached_data_load(
                    
TMPDIR.$sid.$vid.'_thumb',
                    
'http://ext.nicovideo.jp/thumb_watch/'.$vid,
                    array(
'http'=>array('header'=>'Referer:http://dic.nicovideo.jp/v/'.$vid.'\r\nUser-Agent:PHP'))
                );
                if(
$buf===FALSE){
                    
$baseurl=FALSE;
                    
$errmessage="<p>smileAPI的なものへのアクセスに失敗しました</p>";
                    break;
                }

                
$key=places_text($buf"thumbPlayKey""\n");
                if(
$key===FALSE){
                    if(
strpos($buf,"http://www.nicovideo.jp/watch/$vid")!==FALSE){
                        
$baseurl="http://www.nicovideo.jp/api/getflv?v=$vid";
                        
$mtype="※「smileAPI的なもの」のURLです";
                        
$errmessage="<p><strong>この動画は外部再生が許可されていません。</strong><br>"
                        
."・ニコニコ動画会員であれば、以下の「従来の方法」でURLが取得できる、かもしれません。<br>"
                        
."・コミュニティ動画のURLを使った場合は、同ページに載っているSMILEVIDEOへのURLか、<br>"
                        
." 「この動画に関する情報を大百科で調べる」のURLを使用してみてください。<br>"
                        
." ただしコミュニティメンバー専用の動画の場合、該当コミュニティに所属していなければ<br>"
                        
." 動画の再生もダウンロードも出来ません。</p>"
                        
.$errmessage;
                    }else{
                        
$baseurl=FALSE;
                        
$errmessage="<p>smileAPI的なものからのデータ取得に失敗しました<br>"
                        
."該当動画が削除された、もともと存在しない、メンテナンス中のどれかですたぶん。</p>";
                    }
                    break;
                }
                
$key=trim(places_text($key"'""'"));

                
//MiniPlayerのバージョンチェック
                //更新されていたら取得方法に影響が出る可能性があるため
                
$nv=file_get_contents('tmp/vup');
                
$v=trim(places_text($buf"version""\n"));
                
$v=trim(places_text($v"'""'"));
                if(
$v!=$nv){
                    
//mailmsg.phpで定義してますが、要はあるアドレス宛にメール送るだけ
                    
mailalart('NicoMiniPlayerが更新された模様 Ver:'.$v);
                    foreach (
glob("tmp/*") as $filename){
                        
unlink($filename);
                    }
                    
file_put_contents('tmp/vup',$v,LOCK_EX);
                    
chmod('tmp/vup',0666);
                }

                
$t='\''.places_text($buf"title: '""\n");
                
$t=trim(str_replace("\'","\u0027",$t));    //カンマが含まれていたらエスケープする
                
$t='{"name":"'.trim(places_text($t"'""'")).'"}';
                
$t2=json_decode($t,TRUE);        //\uXXXX方式のUnicodeを、jsonの一部機能を利用してデコード
                
$title=$t2['name'];
                
$title=set_video_title($sid,$vid,$title);

                
$buf=cached_data_load(TMPDIR.$sid.$vid.'_api','http://www.nicovideo.jp/thumb_watch/'.$vid.'/'.$key);
                if(
$buf===FALSE){
                    
$baseurl=FALSE;
                    
$errmessage="<p>smileAPI的なものへのアクセスに失敗しました2</p>";
                    break;
                }
                if(
strpos($buf,"error=access_locked")!==FALSE){
                    
$baseurl=FALSE;
                    
$errmessage="<p>smileAPI的なものからのデータ取得に失敗しました3<br>アクセス拒否られたかも…1時間位したら再度試してみて</p>";
                    break;
                }
                if(
strpos($buf,"error=invalid")!==FALSE){
                    
$baseurl=FALSE;
                    
$errmessage="<p>smileAPI的なものからのデータ取得に失敗しました4<br>動画データに関する情報取得要求を拒否されました。<br>コミュニティ動画などの場合、JavaScriptを用いた「過去の方法」が使用できるかもしれません。</p>".$errmessage;
                    break;
                }
                
$baseurl=places_text($buf"url=""&");
                if(
$baseurl===FALSE){
                    
$baseurl=FALSE;
                    
$errmessage="<p>smileAPI的なものからのデータ取得に失敗しました2<br>該当動画は削除されたかもしれません</p>";
                    break;
                }
                
$baseurl=urldecode($baseurl);
                if(
strpos($baseurl,'m=',0)!==FALSE){
                    
$mtype="H.264+AAC(.mp4)";
                }elseif(
strpos($baseurl,'s=',0)!==FALSE){
                    
$mtype="Flash(.swf)";
                }else{
                    
$mtype="FlashVideo(.flv)";
                }
            }while(
0);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][]=array(
                    
'url' => $baseurl,
                    
'mtype' => $mtype
                
);
                if(
strpos($baseurl,"low")!==FALSE){
                    
$_return[url][]=array(
                        
'url' => str_replace("low","",$baseurl),
                        
'mtype' => $mtype."※プレミアム専用"
                    
);
                }
            }
            break;
/*--------------------------------------------------------*/
/*
YouTubeは特定URLにHEADリクエストすると得られる値から、FLVを取得するのに必要な
一次キーを得ることができるのでそれを使う。
HEADリクエストなのでタイトル情報が含まれず、結果的にYouTubeはタイトル非対応となる。

いつのまにか仕様が変わっているので、HTMLスクレイピング方式に変更。
*/
        
case "YouTube":    //YouTube
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://www.youtube.com/watch?v=".$vid);
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>YouTubeからの情報取得に失敗しました</p>";
                break;
            }
            
$t trim(places_text(places_text($buf"&t=""'"), """&"));
            
$baseurl="http://www.youtube.com/get_video?video_id=".$vid."&t=".$t;
            
$errmessage="";
            
$title=places_text(places_text($buf"<meta name=\"title\""">"), "content=\"""\"");
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][]=array(
                    
'url' => $baseurl,
                    
'mtype' => 'デフォルトH.263+MP3(.flv)'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=5",
                    
'mtype' => '低画質版H.263+MP3(.flv)'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=13",
                    
'mtype' => 'H.263+AMR(3gp)/ケータイ向け?'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=17",
                    
'mtype' => 'MPEG4+AAC(.3gp)/ケータイ向け?'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=34",
                    
'mtype' => '低解像度版H.264+AAC(.flv)'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=6",
                    
'mtype' => '高解像度版H.263+MP3(.flv)'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=18",
                    
'mtype' => 'H.264+AAC(.mp4)/iPhone向け'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=35",
                    
'mtype' => '高解像度版H.264+AAC(.flv)'
                
);
                
$_return[url][]=array(
                    
'url' => $baseurl."&fmt=22",
                    
'mtype' => 'HD版H.264+AAC(.mp4)'
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
GoogleVideoのHTMLに含まれるFLVへのURLをそのまま利用する。
なお、YouTubeの場合はそっちに処理を丸投げ。

他のいくつかのサービスにも対応しているようであるが、面倒+需要低そうなので放置。
*/
        
case "GoogleVideo":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://video.google.com/videoplay?docid=".$vid);
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>GoogleVideoからの情報取得に失敗しました</p>";
                break;
            }
            
$t=places_text($buf"videoUrl=""&");
            if(
$t===FALSE){
                
$_vid=places_text($buf,"youtube.com/watch?v=","\"");
                if(
$_vid===FALSE){
                    
$baseurl=FALSE;
                    
$errmessage="<p>GoogleVideoからの情報取得に失敗しました。</p>";
                    break;
                }else{
                    
$sid="YouTube";
                    
$vid=$_vid;
                    
$_result=get_flv_url_from_id("YouTube",$vid);
                    
$baseurl=$_result['url'];
                    break;
                }
            }
            
$baseurl urldecode($t);
            
$title=places_text($buf,"<title>","</title>");
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => "FlashVideo(.flv)"
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
Veohの非公開APIを勝手に利用する。
使い方は引数に動画IDを渡すだけ。かなり多くの情報を得ることが出来る。
*/
        
case "Veoh":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://www.veoh.com/rest/video/".$vid."/details");
            if(
$buf!==FALSE){
                
$videos simplexml_load_string($buf);
            }else{
                
$baseurl=FALSE;
                
$errmessage="<p>Veohからの情報取得に失敗しました</p>";
                break;
            }
            
$baseurl=$videos->video['fullPreviewHashPath'];
            if(
strpos($baseurl,".fll?")===FALSE){
                
$mtype="FlashVideo(.flv)";
            }else{
                
$mtype="H.264+AAC(.flv/.fll)";
            }
            
$title=$videos->video['title'];
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => $mtype
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
Gubaの隠しAPIを利用する。
得られる情報はあまり多くない。動画タイトルも含まれていなかったはず。
*/
        
case "Guba":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://www.guba.com/xml/playerConfig/".$vid);
            if(
$buf!==FALSE){
                
$config simplexml_load_string($buf);
            }else{
                
$baseurl=FALSE;
                
$errmessage="<p>Gubaからの情報取得に失敗しました</p>";
                break;
            }
            
$baseurl=$config->videoUrl;
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => "FlashVideo(.flv)"
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
DailyMotionのHTMLに含まれる、動画へのURLを利用。
得られる3種類のURLのうち1つは(おそらく)サムネイル用途の小さいものなので捨て、
残った通常版ともう一方の動画URLを出力する。
今後MP4対応の追加とかがあっても、(同一の仕様なら)2~3行足すだけで対応できる、かも
取得方法が超手抜きなので、実は危ないが、利用者が少なすぎるため問題になったことがない
*/
        
case "DailyMotion":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://www.dailymotion.com/video/".$vid);
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>DailyMotionからの情報取得に失敗しました</p>";
                break;
            }
            
$tmp places_text($buf,'("video"'";");
            if(
$tmp===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>DailyMotionのページ内情報から動画に関するデータが見つかりませんでした<br>"
                       
."この動画は非公開に設定されていたり存在していなかったりするかもしれません</p>";
                break;
            }
            
$tmp explode("@@",urldecode(places_text($tmp'"''")')));
            
$baseurl='http://www.dailymotion.com'.$tmp[0];
            
$baseurl2='http://www.dailymotion.com'.places_text($tmp[2],'||');
            
$errmessage="";
            
$title=places_text($buf,'<meta name="title"','/>');
            
$title=trim(places_text($title,':','"'));
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => 'FlashVideo(.flv)'
                
);
                
$_return[url][1]=array(
                    
'url' => $baseurl2,
                    
'mtype' => 'FlashVideo(.flv)/On2 VP6'
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
MegaVideoのHTMLに含まれる、動画へのURLを利用。
暗号化は単に置換してるだけなので、テーブル作って対処。
Flashファイルの解析によればやっぱちゃんとした関数があるっぽいけど、
今の置換による実装の方が簡易で簡単で確実っぽいので放置
キーを変えるだけで実装できるようなものだった場合で、
実際にそのような事例にぶち当たったらそのときに考えよう

とか書いてたら本当にそんな実装になった。泣ける。
SWFのデコードがうまくいかないので自力で暗号解くしかないかもしれない。

…問題は、これを実装してもほとんど誰も喜ばない、ということか。
*/
        
case "MegaVideo":
            
$baseurl=FALSE;
            
$errmessage="<p>MegaVideoは現在対応サイトから外れています。再対応までしばしお待ちください。</p>";
            break;
/*
            $buf=cached_data_load(TMPDIR.$sid.$vid,"http://megavideo.com/?v=".$vid);
            if($buf===FALSE){
                $baseurl=FALSE;
                $errmessage="<p>MegaVideoからの情報取得に失敗しました</p>";
                break;
            }
            $baseurl = places_text($buf, "flv\",\"", "\"");
            $strtable = Array(
                "_"=>"b","I"=>"t","J"=>"w","K"=>"v","M"=>"p",
                "N"=>"s","P"=>"m","Q"=>"l","R"=>"o","T"=>"i",
                "U"=>"h","X"=>"e","Y"=>"d","Z"=>"g",
                "%04"=>"9","%05"=>"8","%07"=>":","%08"=>"5","%09"=>"4",
                "%0A"=>"7","%0B"=>"6","%0C"=>"1","%0D"=>"0","%0E"=>"3",
                "%0F"=>"2","%12"=>"/","%13"=>".","%5B"=>"f","%5C"=>"a","%5E"=>"c"
            );
            $baseurl=strtr($baseurl,$strtable);
            $title=places_text($buf,'videoname","','"');
            $title=set_video_title($sid,$vid,$title);
            $_return=array(
                'msg' => $errmessage,
                'sid' => $sid,
                'vid' => $vid,
                'title' => $title,
            );
            if($baseurl!=FALSE){
                $_return[url][0]=array(
                    'url' => $baseurl,
                    'mtype' => "FlashVideo(.flv)"
                );
            }
            break;
*/
/*--------------------------------------------------------*/
/*
MetaCafeのHTMLに含まれる、動画へのURLを利用。
以前の実装試験のときに通らなかったので一旦非対応にして放置してたのに、
今日試してみたら全く問題なくて泣いた、若しくは吹いた。
*/
        
case "MetaCafe":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://www.metacafe.com/watch/".$vid);
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>MetaCafeからの情報取得に失敗しました</p>";
                break;
            }
            
$baseurl urldecode(places_text($buf"mediaURL=""&"));
            
$title=places_text($buf,'<meta name="title"','/>');
            
$title=trim(places_text($title,'-','"'));
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => "FlashVideo(.flv)"
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
zoomeのHTMLに含まれる、暗号化されたURLを利用する。
暗号方式はRC4でキーはHTMLには含まれていないが、
SWFファイルの方にキーがあり、全ての動画で同一であるため対応はそれほど難しくない。
ただし、当然のことながら定期的にキーが差し変わる可能性に注意する必要がある。
ファイル名のパターンは仕様変更前と同一なので、たぶん同じシステムをしばらく使うつもりだろう。

実装方法があまりスマートじゃないので何とかしたいところ。
同一の処理を複数回書いていること自体どうかしている。
*/
        
case "zoome_diary":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://zoome.jp/".urldecode($vid));
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>zoomeからの情報取得に失敗しました</p>";
                break;
            }
            
$_mes places_text($buf'baseXML=''"');
            
$message=conv_zoome_sid($_mes);
            
$baseurl=str_replace("xml","flv",$message);
            
$baseurl2=str_replace("xml","mp4",$message);
            
$errmessage="";
            
$title=places_text($buf,'newdiary_body_text">','</div>');
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => 'FlashVideo(.flv)'
                
);
                
$_return[url][1]=array(
                    
'url' => $baseurl2,
                    
'mtype' => 'H.264+AAC(.mp4)/存在しない場合あり'
                
);
            }
            break;
        case 
"zoome_circle":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://circle.zoome.jp/".urldecode($vid));
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>zoomeからの情報取得に失敗しました</p>";
                break;
            }
            
$_mes places_text($buf'swmcmedn("''"');
            
$message=conv_zoome_sid($_mes);
            
$baseurl=str_replace("xml","flv",$message);
            
$baseurl2=str_replace("xml","mp4",$message);
            
$errmessage="";
            
$title=places_text($buf,'media_title_value_h">','</span>');
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => 'FlashVideo(.flv)'
                
);
                
$_return[url][1]=array(
                    
'url' => $baseurl2,
                    
'mtype' => 'H.264+AAC(.mp4)/存在しない場合あり'
                
);
            }
            break;
        case 
"zoome_navi":
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://navi.zoome.jp/".urldecode($vid));
            if(
$buf===FALSE){
                
$baseurl=FALSE;
                
$errmessage="<p>zoomeからの情報取得に失敗しました</p>";
                break;
            }
            
$_mes places_text($buf'swfWrite("''"');
            
$message=conv_zoome_sid($_mes);
            
$baseurl=str_replace("xml","flv",$message);
            
$baseurl2=str_replace("xml","mp4",$message);
            
$errmessage="";
            
$title=places_text($buf,'plate04mid3_2"><h3>','</h3>');
            
$title=set_video_title($sid,$vid,$title);
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => 'FlashVideo(.flv)'
                
);
                
$_return[url][1]=array(
                    
'url' => $baseurl2,
                    
'mtype' => 'H.264+AAC(.mp4)/存在しない場合あり'
                
);
            }
            break;
/*--------------------------------------------------------*/
/*
ニコニコ動画のマイリストのURL。
$Sに渡すための動作。別サイトで使うなら、($S相当のものがあるのでなければ)取り除いたほうがいい
*/
        
case "nicovideo_mylist":
            
$baseurl="http://".MYSERVER."/~tsukaban/nknkdl_rss.php?id=".$vid;
            
$errmessage="<p>ニコニコ動画のマイリストは、上記URLにて対応します。</p>";
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            if(
$baseurl!=FALSE){
                
$_return[url][0]=array(
                    
'url' => $baseurl,
                    
'mtype' => 'マイリスト専用URL'
                
);
            }
            break;
/*--------------------------------------------------------*/
        
case "errurl":
            
$errmessage="<p>http://から始まる、動画が再生されるURLを入れてください。<br>blog貼り付け用コード等は対応していません。</p>";
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            break;
/*--------------------------------------------------------*/
/*
        新規に対応しようとするサイトは、まずこれを使ってIDが得られているか確認すること
        case "ID-Checker":
            $baseurl=FALSE;
            $errmessage="<p>このURLにはまだ対応していません。ID=$vid</p>";
            $_return=array(
                'msg' => $errmessage,
                'sid' => $sid,
                'vid' => $vid,
                'title' => $title,
            );
            if($baseurl!=FALSE){
                $_return[url][0]=array(
                    'url' => $baseurl,
                    'mtype' => $mtype
                );
            }
            break;
*/
/*--------------------------------------------------------*/
/*
非対応サービス
*/
        
case "UnknownService":
            
$errmessage="<p>このURLには対応していません。</p>";
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            break;
/*--------------------------------------------------------*/
/*
例外
*/
        
default:    //判別できず/通常ここに飛ぶはずはない
            
$baseurl=FALSE;
            
$errmessage="<p>このURLには対応していません。。。</p>";
            
$_return=array(
                
'msg' => $errmessage,
                
'sid' => $sid,
                
'vid' => $vid,
                
'title' => $title,
            );
            break;
    }
    return 
$_return;
}

/*----------------------------------------------------------
get_relation_from_id($sid,$vid)
$sid:サービスID
$vid:動画ID

関連動画URLを配列で返す。
関連動画に相当するものをXMLなどで返してくれるインターフェイスがあり、それを
私が見つけている場合に限り実装してある。

なお、データが返ってくるインターフェイスが存在することが重要であり、
それがXMLである必要はない。XMLであるほうが便利ではあるが。
*/
function get_relation_from_id($sid,$vid){
    
$ret=array();
    switch(
$sid) {
/*--------------------------------------------------------*/
        
case "AmebaVision":    //AmebaVision 公式API使用
            
$buf=cached_data_load(TMPDIR.$sid.$vid."_rel","http://vision.ameba.jp/api/get/relationMovie.do?movie=".$vid);
            if(
$buf!==FALSE){
                
$root simplexml_load_string($buf);
            }else{
                return 
FALSE;
            }
            foreach(
$root->item as $val){
                
$i++;
                
$ret[(string)$val->link]=(string)$val->title;
                if(
$i>=5)break;
            }
            break;
        case 
"SMILEVIDEO":    //ニコニコ動画/SMILEVIDEO 非公開API使用
            
$buf=cached_data_load(TMPDIR.$sid.$vid."_rel","http://www.nicovideo.jp/api/getrelation?video=".$vid);
            if(
$buf!==FALSE){
                
$root simplexml_load_string($buf);
            }else{
                return 
FALSE;
            }
            foreach(
$root->video as $val){
                
$i++;
                
$ret[(string)$val->url]=(string)$val->title;
                if(
$i>=5)break;
            }
            break;
        case 
"YouTube":    //YouTube 非公開API使用
            
$buf=cached_data_load(TMPDIR.$sid.$vid."_rel","http://www.youtube.com/set_awesome?video_id=".$vid."&m=");
            if(
$buf!==FALSE){
                
$root simplexml_load_string($buf);
            }else{
                return 
FALSE;
            }
            foreach(
$root->video_list->video as $val){
                
$i++;
                
$ret[(string)$val->url]=(string)$val->title;
                if(
$i>=5)break;
            }
            break;
        case 
"DailyMotion":    //DailyMotion たぶん非公開のRSS使用
            
$buf=cached_data_load(TMPDIR.$sid.$vid."_rel","http://www.dailymotion.com/rss/related/".$vid);
            if(
$buf!==FALSE){
                
$root simplexml_load_string($buf);
            }else{
                return 
FALSE;
            }
            foreach(
$root->channel->item as $val){
                
$i++;
                
$ret[(string)$val->link]=(string)$val->title;
                if(
$i>=5)break;
            }
            break;
        case 
"MetaCafe":    //MetaCafe
            
$buf=cached_data_load(TMPDIR.$sid.$vid."_rel","http://www.metacafe.com/banner.php?t=xml&itemsNumber=5&itemID=".$vid);
            if(
$buf!==FALSE){
                
$root simplexml_load_string($buf);
            }else{
                return 
FALSE;
            }
            foreach(
$root->items->item as $val){
                
$i++;
                
$ret[(string)$val['clickTag']]=(string)$val['title'];
                if(
$i>=5)break;
            }
            break;
        default:    
//ない
            
return FALSE;

    }
    return 
$ret;
}
/*----------------------------------------------------------
conv_zoome_sid($_mes)
$_mes:zoomeから得た、デコードしたい文字列を16進表現にしたもの
戻り値:復号済みデータ

zoomeでは情報を取得するために必要なXMLへのURLを、RC4で暗号化し、
それを16進表現にして文字列としてページに埋め込んでいる。
復号キーは常に同一のものが使われるようになっているので、
もとの16進表現の文字列さえ得られれば容易にXMLのURLを得ることが出来る。
RC4処理が必要なため、要rc4.php。
ちなみに、XMLのURLの拡張子をflvやmp4に変えるだけで動画のURLが得られる。

この様な実装である以上、キーを頻繁に変えてくることは十分予想されるので、
定期的な観察は必須といえる。
*/
function conv_zoome_sid($_mes){
    for(
$n=0;$n<strlen($_mes);$n+=2){
        
$a=substr($_mes,$n,2);
        
$b=intval($a,16);
        
$message.=pack("C",$b); 
    }
    
$rc4 = new Crypt_RC4;
    
$rc4->setKey("72f27dae3d5ce9ceb803eaad50c3d657");
    
$rc4->decrypt($message);
    return 
$message;
}

/*----------------------------------------------------------
get_watch_url_from_id($sid,$vid)
$sid:配信サイトIDを保持する変数
$vid:動画IDを保持する変数
戻り値:連想配列
    "url" => 閲覧用URL
    "msg" => 補足文字列
    "title" => 動画タイトル

sidとvidから、配信サイトの閲覧用のURLを算出する。
基本的に配信URLは(余計な引数を考えなければ)固定であり、
隠匿されているものでもないため自サーバー内で容易に生成できる。

取得できなかった場合は、[url]はFALSEになる。
補足文字列は、返らない場合もある。
基本的にアクセス解析用で、外から見える範囲では使われていない。

(自分用であることもあり)ネットワークリソースを使うしか
URLを逆生成できない場合(≒フォト蔵)は対応していなかったが、
方針転換して対応してみた。もちろんキャッシュは利く。
*/
function get_watch_url_from_id($sid,$vid){
    
$errmessage="";
    switch(
$sid) {
/*--------------------------------------------------------*/
        
case "photozou":    //フォト蔵 APIを使ってユーザーIDを取得しないとURLが作れない
            
$buf=cached_data_load(TMPDIR.$sid.$vid,"http://api.photozou.jp/rest/photo_info?photo_id=".$vid);
            if(
$buf!==FALSE){
                
$root simplexml_load_string($buf);
                if((string)
$root['stat']=='ok'){
                    
$baseurl=(string)$root->info->photo->url;
                    
$title=(string)$root->info->photo->photo_title;
                }else{
                    
$baseurl=FALSE;//"http://photozou.jp/photo/show/".$vid;
                    
$title=$vid;
                }
            }else{
                
$baseurl=FALSE;//"http://photozou.jp/photo/show/".$vid;
                
$title=$vid;
            }
            break;
/*--------------------------------------------------------*/
        
case "AmebaVision":    //AmebaVision
            
$baseurl="http://vision.ameba.jp/watch.do?movie=".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "SMILEVIDEO":    //SMILEVIDEO
            
$baseurl="http://www.nicovideo.jp/watch/".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "YouTube":    //YouTube
            
$baseurl="http://www.youtube.com/watch?v=".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "GoogleVideo":    //GoogleVideo
            
$baseurl="http://video.google.com/videoplay?docid=".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "MegaVideo":    //MegaVideo
            
$baseurl="http://megavideo.com/?v=".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "Veoh":        //Veoh
            
$baseurl="http://www.veoh.com/videos/".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "Guba":        //Guba
            
$baseurl="http://www.guba.com/watch/".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "DailyMotion":    //DailyMotion
            
$baseurl="http://www.dailymotion.com/video/".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "MetaCafe":    //MetaCafe
            
$baseurl="http://www.metacafe.com/watch/".$vid;
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "zoome_diary":    //zoome
            
$baseurl="http://zoome.jp/".urldecode($vid);
            
$title=$vid;
            break;
        case 
"zoome_circle":
            
$baseurl="http://circle.zoome.jp/".urldecode($vid);
            
$title=$vid;
            break;
        case 
"zoome_navi":
            
$baseurl="http://navi.zoome.jp/".urldecode($vid);
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
case "UnknownService":
            
$baseurl=FALSE;
            
$errmessage="<p>このURLには対応していません。</p>";
            
$title=$vid;
            break;
/*--------------------------------------------------------*/
        
default:    //判別できず/通常ここに飛ぶはずはない
            
$baseurl=FALSE;
            
$errmessage="<p>このURLには対応していません。。。</p>";
            
$title=$vid;
            break;
    }
    if(
file_exists('title/'.$sid.$vid)&&$title==$vid){
        
$title=file_get_contents('title/'.$sid.$vid);
    }
    return array(
"url" => $baseurl"msg" => $errmessage"title" => $title);
}

/*----------------------------------------------------------
set_video_title($_sid,$_vid,$_title[,$_dir])
$_sid:サービスID
$_vid:動画ID
$_title:動画タイトル
$_dir:データを保存するディレクトリ
戻り値:UTF-8に変換されたタイトル文字列

特定のサービス・IDの動画に、タイトルをつける。

文字コードの変換が役に立つのはzoomeだけだけど、今後も何も考えないで
ここに文字列を放り込んでおけばよい、と言う強みはある。
…まあ何も考えないとたいてい痛い目見るけど。
少なくとも日本語以外のローカル文字セットが使用されるサービスに
積極的に対応する予定はあまり無い。
ちなみに、配信元がUTF-8であれば、もともと☆がUTF-8なので全く問題ない。

今のところ取得のたびにタイトルを保存しなおしている。
これは、最終更新日を元にキャッシュされている古いタイトルファイルを
一掃するようにしているためで、少なくともファイルの更新日時の変更は必要である。
ついでに、一般的には動画タイトルは後付で変更できるものであり、
ニコニコ動画のように頻繁にタイトルを変える人が存在するコミュニティもあるので
とりあえずこれでよいと思う。
*/
function set_video_title($_sid,$_vid,$_title,$_dir='title/'){
    
$_title=mb_convert_encoding($_title,'UTF-8','ASCII,JIS,UTF-8,EUC-JP,SJIS');
    
file_put_contents($_dir.$_sid.$_vid,htmlspecialchars(trim($_title)),LOCK_EX);
    
chmod($_dir.$_sid.$_vid0666);
    return 
$_title;
}

/*----------------------------------------------------------
cached_data_load($_filename,$_url[,$_headerbase])
$_filename:キャッシュファイルまでのパス 相対でも絶対でもよい
$_url:元のネットワーク上のリソースへのURL
$_headerbase:リクエストするときの各種情報を連想配列で指定 デフォルト値を見れば大体分かるかと
戻り値:取得できたデータそのもの

インターネット経由で取得できるデータを取得するときに、
CACHETIME秒以内であればキャッシュから、それ以外はインターネット経由で取得するようにする。
戻り値は取得されたデータ。取得に失敗したらFALSEが返る。
ネットワークからのデータの取得はfopen wrappersの機能を使ってfile_get_contentsしているだけなので、
必ずしもネットワークリソースでなくても使えるし、プロトコルはそのサーバーのPHPで
使用できるすべてのものが使えるが、php.iniなどで機能が殺されている場合は使えない。

命名規則が変だけど気にしない^^;
simpleXMLを使ってることと並んでPHP5でなければいけない理由である関数。
PHPいじり始めたころに作った関数の一つだけど、案外重宝している。
本当はもっとちゃんとした実装があるのかもしれないけど、今のところ
これで困ったことは無いし、困らせたことも無いと思う。
別のスクリプトではURLだけ指定すれば取得もキャッシュもキャッシュファイル名も
自動(SHA1でハッシュ化)、という実装もしているが、☆の場合キャッシュに残っているデータが
解析の重要な資料になる場合も多々あるので、実際のファイル名とサービスやIDとの対応が
わからなくなると困る。
*/
function cached_data_load($_filename,$_url,$_headerbase=array('http'=>array('header'=>'User-Agent:PHP'))){
    
$ftime=filemtime($_filename);
    if(
time()-$ftime>CACHETIME||$ftime===FALSE){
        
$header=stream_context_create($_headerbase);
        
$dat file_get_contents($_url,false,$header);
        if(
$dat===FALSE)$dat="FALSE";
        
file_put_contents($_filename,$dat,LOCK_EX);
        
chmod($_filename0666);
        if(
$dat==="FALSE")return FALSE;
    }
    
$dat=file_get_contents($_filename);
    if(
$dat==="FALSE"){
        return 
FALSE;
    }else{
        return 
$dat;
    }

}

/*----------------------------------------------------------
places_text($src, $before, $after="", $num=0)
$src:元の文字列
$before:求める文字列の前にある文字列
$after:求める文字列の後にある文字列
$num:何個目の結果か
戻り値:結果

$beforeと$afterに挟まれている文字列を$srcから探して返す。
複数存在する場合は、$numで位置を調整できる。

from http://hanagasira.s25.xrea.com/php/video.php.txt
*/
function places_text($src$before$after=""$num=0){
    if (
$before==="" && $after!==""){            //先頭指定なしで後ろはある
        
return substr($src,0,strpos($src,$after));
    }

    if (
strpos($src$before)===FALSE){    //指定された先頭の文字がない
        
return FALSE;
    }

    
$result $src;
    for (
$i=0;$i<$num+1;$i++){        //切り取り開始位置を確定する
        
$result substrstristr$result$before), strlen($before));
        if (
$result===FALSE){
            return 
FALSE;
        }
    }

    if (
$after==="" || strpos($result$after)===FALSE){    //後ろの文字列の指定がないか見つからない
        
return $result;
    }else{
        return 
substr$result0strpos($result$after) );
    }
}

/*----------------------------------------------------------
get_http_response($_filename,$_url)
$_filename:キャッシュファイルまでのパス 相対でも絶対でもよい
$_url:元のネットワーク上のリソースへのURL
戻り値:サーバーのレスポンスヘッダそのもの

どこかのHTTPサーバーに対して、HEADリクエストを要求し、戻り値を得る。
cached_data_load()同様、CACHETIME秒以内の再アクセスは
キャッシュを利用する。

参考 http://hanagasira.s25.xrea.com/php/video.php.txt

cached_data_load()と違い、ソケットで実装されている。
あっちでヘッダをいじれるようにしてるので、もうちょっといじって
向こうでHEADリクエストできるようにしてもいいかもしれない。
実装自体も元のスクリプトとはすでに結構違う。
*/
function get_http_response($_filename,$_url){
    
$ftime=filemtime($_filename);
    if(
time()-$ftime>CACHETIME||$ftime===FALSE){
        
$dat="";
        
$url=parse_url($_url);
        
$senddata="HEAD ".$url["path"]."?".$url["query"]." HTTP/1.0\r\n";
        
$senddata.="Connection: Close\r\n\r\n";
        if(
$url["port"]==FALSE){
            
$url["port"]=80;
        }
        
$fp fsockopen($url["host"],$url["port"],$errno,$errstr,30);
        if (!
$fp){
            return 
FALSE;
        }else{
            
fwrite($fp$senddata);
            while (!
feof($fp)){
                
$dat .= fgets($fp,1024);
            }
            
fclose($fp);
        }
        
$fp=fopen($_filename,"r+") or $fp=fopen($_filename,"w");
        if(
$fp===FALSE)return FALSE;
        
flock($fp,LOCK_EX);
        
ftruncate($fp,0);
        
fputs($fp,$dat);
        
flock($fp,LOCK_UN);
        
fclose($fp);
        
chmod($_filename0666);
    }
    return 
file_get_contents($_filename);
}

/*#######################################################################################################
Flash Video Star functions module
Copyright (c) 2007-2008, TSUKABAN!
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

*Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer. 
*Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation and/or
 other materials provided with the distribution. 
*Neither the name of TSUKABAN! nor the names of its contributors
 may be used to endorse or promote products derived from this software
 without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

==============================================================
(参考邦訳)
Flash Video Star functions module
Copyright (c) 2007-2008, TSUKABAN!
All rights reserved.

ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満たす場合に限り、
再頒布および使用が許可されます。

 ・ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項を含めること。
 ・バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作権表示、
  本条件一覧、および下記免責条項を含めること。
 ・書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進に、
  TSUKABAN!の名前またはコントリビューターの名前を使用してはならない。

本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供されており、
明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性に関する暗黙の保証も含め、
またそれに限定されない、いかなる保証もありません。著作権者もコントリビューターも、
事由のいかんを問わず、 損害発生の原因いかんを問わず、かつ責任の根拠が契約であるか厳格責任であるか
(過失その他の)不法行為であるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、
本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の喪失、データの喪失、
利益の喪失、業務の中断も含め、またそれに限定されない)直接損害、間接損害、偶発的な損害、特別損害、
懲罰的損害、または結果損害について、一切責任を負わないものとします。
==============================================================
2008/06/22
著作権表記の上に、何に対する著作表示なのかを明記
よく考えたら範囲不明瞭なのに「All rights reserved.」とか意味不明すぎでした。
2008/02/26
ライセンスの文面を修正
修正内容は邦訳をOSI提供のもので構築しなおしただけであり、ライセンス自体の意図は
今までと全く変わっていない。
#######################################################################################################*/
?>