Недавно исследовал сабж, выношу результаты в своего рода FAQ:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
public class D {
private static final String scheme = "http";
private static final String host = "www.youtube.com";
public static void main(String[] args) {
try {
String videoId = null;
String outdir = ".";
if (args.length == 1) {
videoId = args[0];
} else if (args.length == 2) {
videoId = args[0];
outdir = args[1];
}
int format = 18; // http://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
String encoding = "UTF-8";
String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13";
File outputDir = new File(outdir);
play(videoId, format, encoding, userAgent, outputDir);
} catch (Throwable t) {
t.printStackTrace();
}
}
static HttpContext localContext = new BasicHttpContext();
private static void play(String videoId, int format, String encoding, String userAgent, File outputdir) throws Throwable {
System.out.println("Retrieving " + videoId);
List qparams = new ArrayList();
qparams.add(new BasicNameValuePair("video_id", videoId));
qparams.add(new BasicNameValuePair("fmt", "" + format));
URI uri = getUri("get_video_info", qparams);
CookieStore cookieStore = new BasicCookieStore();
localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(uri);
httpget.setHeader("User-Agent", userAgent);
System.out.println("Executing " + uri);
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
if (entity != null && response.getStatusLine().getStatusCode() == 200) {
InputStream instream = entity.getContent();
String videoInfo = getStringFromInputStream(encoding, instream);
if (videoInfo != null && videoInfo.length() > 0) {
List infoMap = new ArrayList();
URLEncodedUtils.parse(infoMap, new Scanner(videoInfo), encoding);
String downloadUrl = null;
String filename = videoId;
String urlMap = null;
for (NameValuePair pair : infoMap) {
String key = pair.getName();
String val = pair.getValue();
System.out.println(key + "=" + val);
if (key.equals("title")) {
filename = val;
} else if (key.equals("url_encoded_fmt_stream_map")) {
urlMap = val;
String[] urls = urlMap.split("url=");
String[] decodedUrls = new String[urls.length];
for (int i = 0; i < urls.length; i++) {
decodedUrls[i] = URLDecoder.decode(URLDecoder.decode(urls[i], "UTF-8"), "UTF-8").replaceAll(",$", "");
}
//we use first available quality
downloadUrl = decodedUrls[1].replaceAll("&fallback_host.*", "");
}
}
File outputfile = new File(outputdir, "out.flv");
if (downloadUrl != null) {
downloadWithHttpClient(userAgent, downloadUrl, outputfile);
}
}
}
}
private static void downloadWithHttpClient(String userAgent, String downloadUrl, File outputfile) throws Throwable {
HttpGet httpget2 = new HttpGet(downloadUrl);
httpget2.setHeader("User-Agent", userAgent);
System.out.println("Executing " + httpget2.getURI());
HttpClient httpclient2 = new DefaultHttpClient();
HttpResponse response2 = httpclient2.execute(httpget2, localContext);
HttpEntity entity2 = response2.getEntity();
if (entity2 != null && response2.getStatusLine().getStatusCode() == 200) {
long length = entity2.getContentLength();
InputStream instream2 = entity2.getContent();
System.out.println("Writing " + length + " bytes to " + outputfile);
if (outputfile.exists()) {
outputfile.delete();
}
FileOutputStream outstream = new FileOutputStream(outputfile);
try {
byte[] buffer = new byte[2048];
int count = -1;
while ((count = instream2.read(buffer)) != -1) {
outstream.write(buffer, 0, count);
}
outstream.flush();
} finally {
outstream.close();
}
}
}
private static URI getUri(String path, List qparams) throws URISyntaxException {
URI uri = URIUtils.createURI(scheme, host, -1, "/" + path, URLEncodedUtils.format(qparams, "UTF-8"), null);
return uri;
}
private static String getStringFromInputStream(String encoding, InputStream instream) throws UnsupportedEncodingException, IOException {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(instream, encoding));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
instream.close();
}
String result = writer.toString();
return result;
}
}
Где быстро и просто узнать о FLV?
На сайте Xuggler есть 4 коротких обучающих видео по 5 минут. Покрывают все основы, единственный вопрос который там остается без внимания, это кодеки в видеопотоке FLV.
Какие кодеки можно использовать в FLV видеостриме?
Написано в этой статье:
Flash Player version | Released | File format | Video compression formats | Audio compression formats |
---|---|---|---|---|
6 | 2002 | SWF | Sorenson Spark, Screen video | MP3, ADPCM, Nellymoser |
7 | 2003 | SWF, FLV | Sorenson Spark, Screen video | MP3, ADPCM, Nellymoser |
8 | 2005 | SWF, FLV | On2 VP6, Sorenson Spark, Screen video, Screen video 2 | MP3, ADPCM, Nellymoser |
9 | 2007 | SWF, FLV | On2 VP6, Sorenson Spark, Screen video, Screen video 2, H.264 | MP3, ADPCM, Nellymoser, AAC |
SWF, F4V, ISO base media file format | H.264 | AAC, MP3 | ||
10 | 2008 | SWF, FLV | On2 VP6, Sorenson Spark, Screen video, Screen video 2, H.264 | MP3, ADPCM, Nellymoser, Speex, AAC |
SWF, F4V, ISO base media file format | H.264 | AAC, MP3 |
Можно ли скачивать видео с YouTube с помощью YouTube Java API?
Нельзя. TOS хоть прямо и не говорит, но намекает что ютубу нет смысла публично заявлять о возможности это делать.
Можно ли скачивать видео с YouTube?
Можно, для этого надо использовать REST апи ютуба (вот они, двойные стандарты!). Это API нещадно меняют время от времени, но суть остается:
1) Первым запросом получаем мета-инфу о видео
2) Вторым запросом (где используем инфу из ответа на первый) запрашиваем файл.
В данный момент это делается с использованием таких методов REST api:
get_video_info, в ответе которого хранится интересующее нас поле url_encoded_fmt_stream_map.
В этом поле содержится несколько ссылок на различные качества видео, а чтобы ссылка была дееспособна, надо отсекать от неё все что идет после "fallback_host" включительно.
Ну и немаловажный момент: первый запрос и второй должны иметь общий http контекст, так как в первом запросе в контексте создается кука, без которой второй запрос получит 403 от сервера.
Вот proof-of-concept код, достаточно корявый но рабочий:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.*;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
public class D {
private static final String scheme = "http";
private static final String host = "www.youtube.com";
public static void main(String[] args) {
try {
String videoId = null;
String outdir = ".";
if (args.length == 1) {
videoId = args[0];
} else if (args.length == 2) {
videoId = args[0];
outdir = args[1];
}
int format = 18; // http://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
String encoding = "UTF-8";
String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13";
File outputDir = new File(outdir);
play(videoId, format, encoding, userAgent, outputDir);
} catch (Throwable t) {
t.printStackTrace();
}
}
static HttpContext localContext = new BasicHttpContext();
private static void play(String videoId, int format, String encoding, String userAgent, File outputdir) throws Throwable {
System.out.println("Retrieving " + videoId);
List
qparams.add(new BasicNameValuePair("video_id", videoId));
qparams.add(new BasicNameValuePair("fmt", "" + format));
URI uri = getUri("get_video_info", qparams);
CookieStore cookieStore = new BasicCookieStore();
localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(uri);
httpget.setHeader("User-Agent", userAgent);
System.out.println("Executing " + uri);
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
if (entity != null && response.getStatusLine().getStatusCode() == 200) {
InputStream instream = entity.getContent();
String videoInfo = getStringFromInputStream(encoding, instream);
if (videoInfo != null && videoInfo.length() > 0) {
List
URLEncodedUtils.parse(infoMap, new Scanner(videoInfo), encoding);
String downloadUrl = null;
String filename = videoId;
String urlMap = null;
for (NameValuePair pair : infoMap) {
String key = pair.getName();
String val = pair.getValue();
System.out.println(key + "=" + val);
if (key.equals("title")) {
filename = val;
} else if (key.equals("url_encoded_fmt_stream_map")) {
urlMap = val;
String[] urls = urlMap.split("url=");
String[] decodedUrls = new String[urls.length];
for (int i = 0; i < urls.length; i++) {
decodedUrls[i] = URLDecoder.decode(URLDecoder.decode(urls[i], "UTF-8"), "UTF-8").replaceAll(",$", "");
}
//we use first available quality
downloadUrl = decodedUrls[1].replaceAll("&fallback_host.*", "");
}
}
File outputfile = new File(outputdir, "out.flv");
if (downloadUrl != null) {
downloadWithHttpClient(userAgent, downloadUrl, outputfile);
}
}
}
}
private static void downloadWithHttpClient(String userAgent, String downloadUrl, File outputfile) throws Throwable {
HttpGet httpget2 = new HttpGet(downloadUrl);
httpget2.setHeader("User-Agent", userAgent);
System.out.println("Executing " + httpget2.getURI());
HttpClient httpclient2 = new DefaultHttpClient();
HttpResponse response2 = httpclient2.execute(httpget2, localContext);
HttpEntity entity2 = response2.getEntity();
if (entity2 != null && response2.getStatusLine().getStatusCode() == 200) {
long length = entity2.getContentLength();
InputStream instream2 = entity2.getContent();
System.out.println("Writing " + length + " bytes to " + outputfile);
if (outputfile.exists()) {
outputfile.delete();
}
FileOutputStream outstream = new FileOutputStream(outputfile);
try {
byte[] buffer = new byte[2048];
int count = -1;
while ((count = instream2.read(buffer)) != -1) {
outstream.write(buffer, 0, count);
}
outstream.flush();
} finally {
outstream.close();
}
}
}
private static URI getUri(String path, List
URI uri = URIUtils.createURI(scheme, host, -1, "/" + path, URLEncodedUtils.format(qparams, "UTF-8"), null);
return uri;
}
private static String getStringFromInputStream(String encoding, InputStream instream) throws UnsupportedEncodingException, IOException {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(instream, encoding));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
instream.close();
}
String result = writer.toString();
return result;
}
}
Комментариев нет:
Отправить комментарий