/[nicovideo]/trunk/getdata/getaudio.php
ViewVC logotype

Contents of /trunk/getdata/getaudio.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Thu Feb 4 02:40:19 2010 UTC (7 years, 3 months ago) by ioaia
File size: 11763 byte(s)
Fixed: typo.
1 <?php
2 /*
3 * $dataで指定したアカウントを使用してニコニコ動画へのログインを行い、、GET['id']で指定
4 * された動画をサーバにダウンロードした上で、ffmpegまたはswfextractを使用して音声部分を
5 * 抽出して、その結果(音声ファイル)をブラウザに返します。
6 *
7 * 対応する動画はIDがsmまたはnmから始まるsmilevideoに投稿された動画のみで、fzから始まる
8 * フォト蔵の動画や、ax、naまたはsoなどの公式動画、数字から始まるチャンネル動画などには
9 * 対応していません。(でも多分、数字から始まるIDでも物によっては取得できる)。
10 * また、対応する動画形式はmp4、flv、swfで、それぞれ音声部分はaac、mp3、mp3に対応します。
11 *
12 * 動画と音声はそれぞれサーバの./video/と./audio/にスレッドID.拡張子というファイル名で
13 * 保存されます。拡張子は動画ファイルのURLで判断する為、仕様変更があった場合などに利用
14 * できなくなります。
15 */
16
17 $data = array(
18 'mail' => 'YOUR MAIL ADDRESS', // ニコニコ動画のログインメールアドレス
19 'password' => 'YOUR PASSWORD' // ニコニコ動画のログインパスワード
20 );
21
22 // videoidが不正な形式でないか確認
23 if (!empty($_GET['id']) && ctype_alnum($_GET['id']) ) {
24 $videoid = $_GET['id']; // idが空でなく英数字の場合、そのまま$videoidに代入
25 } else {
26 exit('Bad videoid.'); // そうでない場合はエラーを表示し終了
27 }
28
29 // API,ログインURL
30 $api = "http://ext.nicovideo.jp/api/getflv/{$videoid}?as3=1";
31 $loginurl = 'https://secure.nicovideo.jp/secure/login?site=niconico';
32
33 // プログラムのパス
34 $ffmpeg = '/usr/local/bin/ffmpeg';
35 // $ffmpeg = 'C:\dev\bin\ffmpeg.exe';
36 $swfextract = '/usr/local/bin/swfextract';
37 // $swfextract = 'C:\dev\bin\swfextract.exe';
38
39 // 各フォルダのパス。
40 $tmpdir = './tmp'; // 一時的にcookieを保存するdir
41 $videodir = './video'; // DLした動画ファイルを保存するdir
42 $audiodir = './audio'; // 変換した音声ファイルを保存するdir
43
44 // dirが存在しない場合は作成を試みる
45 if (!file_exists($tmpdir)) {
46 if (!mkdir($tmpdir)) {
47 // 作成できない場合は終了
48 exit('Failed to create tmpdir');
49 }
50 }
51
52 if (!file_exists($videodir)) {
53 if (!mkdir($videodir)) {
54 exit('Failed to create videodir');
55 }
56 }
57
58 if (!file_exists($audiodir)) {
59 if (!mkdir($audiodir)) {
60 exit('Failed to create audiodir');
61 }
62 }
63
64 // cookieを一時保存するtmpファイルを作成
65 $tmp = tempnam($tmpdir, 'NND'); // ./tmpにNNDから始まるtmpファイルを作成
66 if (!touch($tmp)) { // ファイルが存在するか確認
67 exit('Failed to create tmp file.'); // ファイルが使用できない場合はエラーを表示し終了
68 }
69
70 // ニコニコ動画にログインする
71 $ch = curl_init($loginurl);
72 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
73 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // location headerを追う
74 curl_setopt($ch, CURLOPT_COOKIEJAR, $tmp); // 受信したCookieをtmpファイルに保存
75 curl_setopt($ch, CURLOPT_POST, TRUE); // ログイン情報はPOSTで送信
76 curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // 送信する内容$data
77 // SSL証明書の検証をしない。証明書を入れるのが面倒な時用。
78 // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
79 // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
80 // または証明書のパスを指定
81 // curl_setopt($ch, CURLOPT_CAINFO, 'C:\dev\ca\secure.nicovideo.jp.crt');
82 curl_exec($ch); // cURLセッションを実行
83 curl_close($ch); // cURLセッションを閉じる
84
85 // getflv APIを使って動画情報を取得する
86 $ch = curl_init($api);
87 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
88 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
89 curl_setopt($ch, CURLOPT_COOKIEFILE, $tmp); // $cookieFileに保存されたcookieを送信する
90 $getflv = curl_exec($ch); // cURLセッションを実行し、その結果を$getflvに代入
91 curl_close($ch);
92
93 // 一応変数の初期化
94 $error = null;
95 $deleted = null;
96 $closed = null;
97
98 // getflvで取得したクエリ文字列を変数に代入
99 parse_str($getflv);
100
101 // closed=1はログインができていない
102 if ($closed === '1') {
103 unlink($tmp);
104 exit('Failed login to nicovideo.jp');
105 }
106
107 // 今のところ、getflvでerror=がつくのは動画が存在しない場合のみのはず。。。
108 // 多分、errorの値も"invalid_thread"しかない。以前は削除された時、ここに
109 // 削除理由が入ってた(invalid_v1とか)みたいだけど、今はdeletedに入ってる
110 // ToDo: 気が向いたらきちんと値を確認するように直す。
111 if (isset($error)) {
112 unlink($tmp);
113 exit('Unknown videoid.'); // $errorがnullではない場合、不正な動画IDと判断して終了
114 }
115
116 // deletedがnullでない場合は取得できない動画。
117 // 今のところerrorと同じで削除されてない場合はセットされてないはず
118 if (isset($deleted)) {
119 unlink($tmp);
120 switch ($deleted) {
121 case 1:
122 // 投稿ユーザによる削除
123 exit("This video is deleted by user.");
124
125 case 2:
126 // 動画情報が取得できない
127 exit("Cannot download the video information.");
128
129 case 3:
130 // 運営による削除
131 exit("This video is deleted by niwango(operation company).");
132
133 case 8:
134 // 存在しない動画
135 exit('This video is nonexistent.');
136
137 default:
138 // 不明なエラー
139 exit('Unknown error. Please let me know this video id.');
140
141 }
142 }
143
144 // watchページのcookieを取得
145 $ch = curl_init('http://www.nicovideo.jp/watch/'.$videoid);
146 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
147 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
148 curl_setopt($ch, CURLOPT_COOKIEFILE, $tmp);
149 curl_setopt($ch, CURLOPT_COOKIEJAR, $tmp);
150 curl_exec($ch);
151 curl_close($ch);
152
153 // 動画形式を判別
154 if (preg_match("/smile\?v=/", $url)) {
155 // v=はflv
156 $format = 'flv';
157 $aformat = 'mp3';
158 } elseif (preg_match("/smile\?m=/", $url)) {
159 // m=はmp4
160 $format = 'mp4';
161 $aformat = 'aac';
162 // aacをmp3に変換して出力する場合はmp3にする
163 // $aformat = 'mp3';
164 } elseif (preg_match("/smile\?s=/", $url)) {
165 // s=はswf
166 $format = 'swf';
167 $aformat = 'mp3';
168 } else {
169 // その他は不明な形式。smilevideo以外の動画もここ。
170 unlink($tmp);
171 exit('Unknown video format. Please let me know this video id.');
172 }
173
174 $videofile = "{$videodir}/{$thread_id}.{$format}"; //videofileの保存場所と名前
175 $audiofile = "{$audiodir}/{$thread_id}.{$aformat}"; // audiofileの保存場所と名前
176
177 // まず動画ファイルがあるかを確認する。無い場合は取得して音声ファイルの生成。
178 // ある場合は音声ファイルがあるか確認。無い場合は音声ファイルの生成。
179 // わざわざ動画ファイルがあるか確認してるのは、元々動画ファイルの取得するだけ
180 // だった時の名残(最初に動画ファイルの取得だけをするスクリプトを作ってた)。
181 if (!file_exists($videofile)) { // 利用可能な動画が無い場合
182 // 動画ファイルの取得
183 $fp = fopen($videofile, 'w+'); // $videofileを読み/書きで開く
184 if (!$fp) {
185 // もし$videofileを開けなかったら終了
186 unlink($tmp);
187 exit('Failed to open videofile. line ' . __LINE__);
188 }
189 // 動画ファイルの取得/保存
190 $ch = curl_init($url);
191 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
192 curl_setopt($ch, CURLOPT_HTTPGET, true); // GETでリクエスト。多分、無くてもいい。
193 curl_setopt($ch, CURLOPT_COOKIEFILE, $tmp);
194 curl_setopt($ch, CURLOPT_FILE, $fp); // $fp($videofile)に保存
195 curl_exec($ch);
196 curl_close($ch);
197 fclose($fp); // $videofileを閉じる
198 unlink($tmp); // cookieを削除
199 if (is_readable($videofile)) {
200 // videoから音声を抽出
201 switch($format){
202 case 'flv':
203 // そのまま抽出するだけの時はflvもmp4も同じ
204 // exec("{$ffmpeg} -i {$videofile} -acodec copy {$audiofile}");
205 // break;
206
207 case 'mp4':
208 // aacをmp3に変換して出力するなら"-acodec libmp3lame"にする。
209 // exec("{$ffmpeg} -i {$videofile} -acodec libmp3lame {$audiofile}");
210 // mp3に変換して出力する時は$aformatをmp3にしとかないとエラーがでる。
211 exec("{$ffmpeg} -i {$videofile} -acodec copy {$audiofile}");
212 break;
213
214 case 'swf':
215 // swfextract -m [input] -o [output]
216 // -m 音声ストリームを抽出する(--mp3)
217 exec("{$swfextract} -m {$videofile} -o {$audiofile}");
218 break;
219
220 default:
221 // 通常はここにたどり着く事は無いはず。
222 exit('Impossible error. line ' . __LINE__);
223 break;
224
225 }
226 if (!is_readable($audiofile) ) {
227 // 音声ファイルが開けない場合は終了
228 exit('Failed to open audiofile. line ' . __LINE__);
229 }
230 } else {
231 // 動画ファイルが開けない場合は終了
232 exit('Failed to open videofile. line ' . __LINE__);
233 }
234 } else { // 動画ファイルが存在する場合
235 unlink($tmp); // cookieを削除
236 if (is_readable($videofile)) { // 読み込み可能な動画ファイルが存在する場合
237 if (!file_exists($audiofile)) { // 音声ファイルが存在しない場合
238 // 動画から音声を抽出
239 switch($format){
240 case 'flv':
241 // そのまま抽出するだけの時はflvもmp4も同じ
242 // exec("{$ffmpeg} -i {$videofile} -acodec copy {$audiofile}");
243 // break;
244
245 case 'mp4':
246 // exec("{$ffmpeg} -i {$videofile} -acodec libmp3lame {$audiofile}");
247 exec("{$ffmpeg} -i {$videofile} -acodec copy {$audiofile}");
248 break;
249
250 case 'swf':
251 exec("{$swfextract} -m {$videofile} -acodec copy {$audiofile}");
252 break;
253
254 default:
255 exit('Impossible error. line ' . __LINE__);
256 break;
257
258 }
259 if (!is_readable($audiofile)) {
260 // 音声ファイルを読み込めない場合は終了
261 exit('Filed to open audiofile. line ' . __LINE__);
262 }
263 } elseif (!is_readable($audiofile)) {
264 exit('Filed to open audiofile. line ' . __LINE__);
265 }
266 } else {
267 // 動画ファイルを開けない場合は終了
268 exit('Failed to open video file. line ' . __LINE__);
269 }
270 }
271
272 // 音声ファイルをダウンロードさせる
273 header('Content-Type: Application/octet-stream');
274 header('Content-Disposition: attachment; filename='.basename($audiofile));
275 header('Content-Length: '.filesize($audiofile));
276 readfile($audiofile);
277 exit;

  ViewVC Help
Powered by ViewVC 1.1.13