Próbuję dowiedzieć się, jak pobrać wideo z YouTube do lokalnego systemu plików. Próbowałem kilka pakietów, takich jak vGet, ale nie wydaje się, aby działało. Każda pomoc jest doceniana.Jak pobrać wideo z Youtube w java
Odpowiedz
Próbowałem vget, https://github.com/axet/vget (został przeniesiony do https://gitlab.com/axet/vget) i działa dobrze. Możesz użyć programu maven do skonfigurowania lub pobrania ręcznie zależności z plików pom. zależnościach
wget (https://github.com/axet/wget)
fotografia-io-2.4.jar
fotografia-lang3-3.1.jar
httpcore-4.3.jar
httpclient-4.3.jar
xstream-1.4.2.jar
skompilowany z JDK6
prowadził bezpośredniego pobrania próbki jako,
public class DirectDownload {
public static void main(String[] args) {
try {
VGet v = new VGet(new URL("http://www.youtube.com/watch?v=fNU4UNPNeWI"), new File("/"));
v.download();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
check out gotowy przykład pracy, źródła znajdują się w słoik
plik zip - 1,89KB
https://www.wetransfer.com/downloads/465f7ef8c6a76f79e4cbd7c9f38a608c20131005141332/41c09a86ed8eaa6e61f59282eabda2a120131005141332/4ac689
UPDATE # - NPE problem podczas pobierania, jak wspomniano w komentarzach
tldr; Wydaje się, że jest kilka problemów z com.github.axet.vget.vhs.YouTubeParser
, więc dodano nieintruzywny kod, który go załatał i sprawił, że przykład działa tak, jak poprzednio. Więc po prostu zamień oryginalną klasę YoutubeParser
na tę opublikowaną tutaj na końcu.
Znajdź także inny gotowy przykład pracy ze słoikem i wszystkimi wymaganymi bibliotekami, źródła są zawarte w słoju (zostanie on automatycznie usunięty po pewnym czasie (zostanie usunięty w dniu 13 września 2014 r.) - uwzględnione są adresy URL youtube w kodzie są przypadkowe) plik
zip - 1,69MB (wetransfer.com wyświetlacze 1.7MB)
A. ZAGADNIENIA
W com.github.axet.vget.vhs.YouTubeParser LN229 zmienna
qs
większość czasu nie zawiera uzyskany ciąg zapytania http zostanie wykonany zWGet
. Powoduje to, żenpe
będzie generowany później podczas próby przeanalizowania ciągu zapytania.Jeśli problem został rozwiązany 1 potem zmienna
sig
nie zostanie znaleziona w adresach URL wrócił zget_video_info
, więc parsowania zPattern.compile("sig=([^&,]*)")
nie zwraca żadnych wartości. Powoduje to ciągłe próby bez pobierania wideo.
B. UCHWAŁY(są łaty tymczasowe, jak oryginalny format odpowiedzi, a przyczyny Wget nieodpowiednie zachowanie nie są znane)
- Wywołanie
WGet
jeszcze raz, jeśli Wynikowy ciąg zapytania jest pusty, bez niego wydaje się, że wykonuje on zadanie. Podano także metodę wywoływania prostego żądania HTTP przy użyciu apache httpclient v4, w tym przypadku istnieje jeszcze jedna zależność od apache commons-logging.jar.
dodane ln248
if (qs == null || qs.trim().length() == 0) {
qs = WGet.getHtml(url);
////below is sample code for simple HTTP GET with httpclient v4
////if used then apache commons-logging.jar is also required
// CloseableHttpClient httpclient = HttpClients.createDefault();
// try {
// HttpGet httpget = new HttpGet(get);
//
// System.out.println("Executing request " + httpget.getRequestLine());
//
// // Create a custom response handler
// ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
//
// public String handleResponse(
// final HttpResponse response) throws ClientProtocolException, IOException {
// int status = response.getStatusLine().getStatusCode();
// if (status >= 200 && status < 300) {
// HttpEntity entity = response.getEntity();
// return entity != null ? EntityUtils.toString(entity) : null;
// } else {
// throw new ClientProtocolException("Unexpected response status: " + status);
// }
// }
//
// };
// String responseBody = httpclient.execute(httpget, responseHandler);
// qs = responseBody;
// } finally {
// httpclient.close();
// }
}
2.Po patrząc na odpowiedź wydaje się, że podpis w pewnym miejscu, więc zwiększona parsowanie trochę. Tak więc, jeśli wykonanie wzoru Pattern.compile("sig=([^&,]*)")
nie zwraca niczego, to także próbuj z Pattern.compile("signature%3D([^&,%]*)")
. Ta zmiana miała miejsce w metodzie extractUrlEncodedVideos
.
String sig = null;
{
Pattern link = Pattern.compile("signature=([^&,]*)");
Matcher linkMatch = link.matcher(urlString);
if (linkMatch.find()) {
sig = linkMatch.group(1);
} else {
link = Pattern.compile("signature%3D([^&,%]*)");
linkMatch = link.matcher(urlString);
if (linkMatch.find()) {
sig = linkMatch.group(1);
}
}
}
Zmodyfikowany com.github.axet.vget.vhs.YouTubeParser
plik jest następująca,
package com.github.axet.vget.vhs;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import com.github.axet.vget.info.VGetParser;
import com.github.axet.vget.info.VideoInfo;
import com.github.axet.vget.info.VideoInfo.States;
import com.github.axet.vget.info.VideoInfo.VideoQuality;
import com.github.axet.wget.WGet;
import com.github.axet.wget.info.ex.DownloadError;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class YouTubeParser extends VGetParser {
public static class VideoUnavailablePlayer extends DownloadError {
private static final long serialVersionUID = 10905065542230199L;
public VideoUnavailablePlayer() {
super("unavailable-player");
}
}
public static class AgeException extends DownloadError {
private static final long serialVersionUID = 1L;
public AgeException() {
super("Age restriction, account required");
}
}
public static class PrivateVideoException extends DownloadError {
private static final long serialVersionUID = 1L;
public PrivateVideoException() {
super("Private video");
}
public PrivateVideoException(String s) {
super(s);
}
}
public static class EmbeddingDisabled extends DownloadError {
private static final long serialVersionUID = 1L;
public EmbeddingDisabled(String msg) {
super(msg);
}
}
public static class VideoDeleted extends DownloadError {
private static final long serialVersionUID = 1L;
public VideoDeleted(String msg) {
super(msg);
}
}
List<VideoDownload> sNextVideoURL = new ArrayList<VideoDownload>();
URL source;
public YouTubeParser(URL input) {
this.source = input;
}
public static boolean probe(URL url) {
return url.toString().contains("youtube.com");
}
void downloadone(VideoInfo info, AtomicBoolean stop, Runnable notify) throws Exception {
try {
extractEmbedded(info, stop, notify);
} catch (EmbeddingDisabled e) {
streamCpature(info, stop, notify);
}
}
/**
* do not allow to download age restricted videos
*
* @param info
* @param stop
* @param notify
* @throws Exception
*/
void streamCpature(final VideoInfo info, final AtomicBoolean stop, final Runnable notify) throws Exception {
String html;
html = WGet.getHtml(info.getWeb(), new WGet.HtmlLoader() {
@Override
public void notifyRetry(int delay, Throwable e) {
info.setDelay(delay, e);
notify.run();
}
@Override
public void notifyDownloading() {
info.setState(States.DOWNLOADING);
notify.run();
}
@Override
public void notifyMoved() {
info.setState(States.RETRYING);
notify.run();
}
}, stop);
extractHtmlInfo(info, html, stop, notify);
extractIcon(info, html);
}
/**
* Add resolution video for specific youtube link.
*
* @param url download source url
* @throws MalformedURLException
*/
void addVideo(String itag, String url) throws MalformedURLException {
Integer i = Integer.decode(itag);
VideoQuality vd = itagMap.get(i);
URL u = new URL(url);
if (u != null) {
sNextVideoURL.add(new VideoDownload(vd, u));
}
}
// http://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
static final Map<Integer, VideoQuality> itagMap = new HashMap<Integer, VideoInfo.VideoQuality>() {
private static final long serialVersionUID = -6925194111122038477L;
{
put(120, VideoQuality.p720);
put(102, VideoQuality.p720);
put(101, VideoQuality.p360);
put(100, VideoQuality.p360);
put(85, VideoQuality.p520);
put(84, VideoQuality.p720);
put(83, VideoQuality.p240);
put(82, VideoQuality.p360);
put(46, VideoQuality.p1080);
put(45, VideoQuality.p720);
put(44, VideoQuality.p480);
put(43, VideoQuality.p360);
put(38, VideoQuality.p3072);
put(37, VideoQuality.p1080);
put(36, VideoQuality.p240);
put(35, VideoQuality.p480);
put(34, VideoQuality.p360);
put(22, VideoQuality.p720);
put(18, VideoQuality.p360);
put(17, VideoQuality.p144);
put(6, VideoQuality.p270);
put(5, VideoQuality.p240);
}
};
public static String extractId(URL url) {
{
Pattern u = Pattern.compile("youtube.com/watch?.*v=([^&]*)");
Matcher um = u.matcher(url.toString());
if (um.find()) {
return um.group(1);
}
}
{
Pattern u = Pattern.compile("youtube.com/v/([^&]*)");
Matcher um = u.matcher(url.toString());
if (um.find()) {
return um.group(1);
}
}
return null;
}
/**
* allows to download age restricted videos
*
* @param info
* @param stop
* @param notify
* @throws Exception
*/
void extractEmbedded(final VideoInfo info, final AtomicBoolean stop, final Runnable notify) throws Exception {
String id = extractId(source);
if (id == null) {
throw new RuntimeException("unknown url");
}
info.setTitle(String.format("http://www.youtube.com/watch?v=%s", id));
String get = String
.format("http://www.youtube.com/get_video_info?video_id=%s&el=embedded&ps=default&eurl=", id);
URL url = new URL(get);
String qs = WGet.getHtml(url, new WGet.HtmlLoader() {
@Override
public void notifyRetry(int delay, Throwable e) {
info.setDelay(delay, e);
notify.run();
}
@Override
public void notifyDownloading() {
info.setState(States.DOWNLOADING);
notify.run();
}
@Override
public void notifyMoved() {
info.setState(States.RETRYING);
notify.run();
}
}, stop);
if (qs == null || qs.trim().length() == 0) {
qs = WGet.getHtml(url);
////below is sample code for simple HTTP GET with httpclient v4
////if used then apache commons-logging.jar is also required
// CloseableHttpClient httpclient = HttpClients.createDefault();
// try {
// HttpGet httpget = new HttpGet(get);
//
// System.out.println("Executing request " + httpget.getRequestLine());
//
// // Create a custom response handler
// ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
//
// public String handleResponse(
// final HttpResponse response) throws ClientProtocolException, IOException {
// int status = response.getStatusLine().getStatusCode();
// if (status >= 200 && status < 300) {
// HttpEntity entity = response.getEntity();
// return entity != null ? EntityUtils.toString(entity) : null;
// } else {
// throw new ClientProtocolException("Unexpected response status: " + status);
// }
// }
//
// };
// String responseBody = httpclient.execute(httpget, responseHandler);
// qs = responseBody;
// } finally {
// httpclient.close();
// }
}
Map<String, String> map = getQueryMap(qs);
if (map.get("status").equals("fail")) {
String r = URLDecoder.decode(map.get("reason"), "UTF-8");
if (map.get("errorcode").equals("150")) {
throw new EmbeddingDisabled("error code 150");
}
if (map.get("errorcode").equals("100")) {
throw new VideoDeleted("error code 100");
}
throw new DownloadError(r);
// throw new PrivateVideoException(r);
}
info.setTitle(URLDecoder.decode(map.get("title"), "UTF-8"));
// String fmt_list = URLDecoder.decode(map.get("fmt_list"), "UTF-8");
// String[] fmts = fmt_list.split(",");
String url_encoded_fmt_stream_map = URLDecoder.decode(map.get("url_encoded_fmt_stream_map"), "UTF-8");
extractUrlEncodedVideos(url_encoded_fmt_stream_map);
// 'iurlmaxresæ or 'iurlsd' or 'thumbnail_url'
String icon = map.get("thumbnail_url");
icon = URLDecoder.decode(icon, "UTF-8");
info.setIcon(new URL(icon));
}
void extractIcon(VideoInfo info, String html) {
try {
Pattern title = Pattern.compile("itemprop=\"thumbnailUrl\" href=\"(.*)\"");
Matcher titleMatch = title.matcher(html);
if (titleMatch.find()) {
String sline = titleMatch.group(1);
sline = StringEscapeUtils.unescapeHtml4(sline);
info.setIcon(new URL(sline));
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Map<String, String> getQueryMap(String qs) {
try {
qs = qs.trim();
List<NameValuePair> list;
list = URLEncodedUtils.parse(new URI(null, null, null, -1, null, qs, null), "UTF-8");
HashMap<String, String> map = new HashMap<String, String>();
for (NameValuePair p : list) {
map.put(p.getName(), p.getValue());
}
return map;
} catch (URISyntaxException e) {
throw new RuntimeException(qs, e);
}
}
void extractHtmlInfo(VideoInfo info, String html, AtomicBoolean stop, Runnable notify) throws Exception {
{
Pattern age = Pattern.compile("(verify_age)");
Matcher ageMatch = age.matcher(html);
if (ageMatch.find()) {
throw new AgeException();
}
}
{
Pattern age = Pattern.compile("(unavailable-player)");
Matcher ageMatch = age.matcher(html);
if (ageMatch.find()) {
throw new VideoUnavailablePlayer();
}
}
{
Pattern urlencod = Pattern.compile("\"url_encoded_fmt_stream_map\": \"([^\"]*)\"");
Matcher urlencodMatch = urlencod.matcher(html);
if (urlencodMatch.find()) {
String url_encoded_fmt_stream_map;
url_encoded_fmt_stream_map = urlencodMatch.group(1);
// normal embedded video, unable to grab age restricted videos
Pattern encod = Pattern.compile("url=(.*)");
Matcher encodMatch = encod.matcher(url_encoded_fmt_stream_map);
if (encodMatch.find()) {
String sline = encodMatch.group(1);
extractUrlEncodedVideos(sline);
}
// stream video
Pattern encodStream = Pattern.compile("stream=(.*)");
Matcher encodStreamMatch = encodStream.matcher(url_encoded_fmt_stream_map);
if (encodStreamMatch.find()) {
String sline = encodStreamMatch.group(1);
String[] urlStrings = sline.split("stream=");
for (String urlString : urlStrings) {
urlString = StringEscapeUtils.unescapeJava(urlString);
Pattern link = Pattern.compile("(sparams.*)&itag=(\\d+)&.*&conn=rtmpe(.*),");
Matcher linkMatch = link.matcher(urlString);
if (linkMatch.find()) {
String sparams = linkMatch.group(1);
String itag = linkMatch.group(2);
String url = linkMatch.group(3);
url = "http" + url + "?" + sparams;
url = URLDecoder.decode(url, "UTF-8");
addVideo(itag, url);
}
}
}
}
}
{
Pattern title = Pattern.compile("<meta name=\"title\" content=(.*)");
Matcher titleMatch = title.matcher(html);
if (titleMatch.find()) {
String sline = titleMatch.group(1);
String name = sline.replaceFirst("<meta name=\"title\" content=", "").trim();
name = StringUtils.strip(name, "\">");
name = StringEscapeUtils.unescapeHtml4(name);
info.setTitle(name);
}
}
}
void extractUrlEncodedVideos(String sline) throws Exception {
String[] urlStrings = sline.split("url=");
for (String urlString : urlStrings) {
urlString = StringEscapeUtils.unescapeJava(urlString);
// universal request
{
String url = null;
{
Pattern link = Pattern.compile("([^&]*)&");
Matcher linkMatch = link.matcher(urlString);
if (linkMatch.find()) {
url = linkMatch.group(1);
url = URLDecoder.decode(url, "UTF-8");
}
}
String itag = null;
{
Pattern link = Pattern.compile("itag=(\\d+)");
Matcher linkMatch = link.matcher(urlString);
if (linkMatch.find()) {
itag = linkMatch.group(1);
}
}
String sig = null;
{
Pattern link = Pattern.compile("signature=([^&,]*)");
Matcher linkMatch = link.matcher(urlString);
if (linkMatch.find()) {
sig = linkMatch.group(1);
} else {
link = Pattern.compile("signature%3D([^&,%]*)");
linkMatch = link.matcher(urlString);
if (linkMatch.find()) {
sig = linkMatch.group(1);
}
}
}
if (url != null && itag != null && sig != null) {
try {
new URL(url);
if (sig != null) {
url += "&signature=" + sig;
}
if (itag != null) {
addVideo(itag, url);
continue;
}
} catch (MalformedURLException e) {
// ignore bad urls
}
}
}
}
}
@Override
public void extract(VideoInfo info, AtomicBoolean stop, Runnable notify) {
try {
downloadone(info, stop, notify);
getVideo(info, sNextVideoURL);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Możemy to wykorzystać do celów komercyjnych? Mam na myśli, czy jest na to licencja. –
@Shabarinath Mogę tylko powiedzieć na pewno, że kod wysłany przeze mnie może być używany w dowolny sposób. Jeśli chodzi o vget i biblioteki, od których to zależy, nie jestem pewny, czy sądzę, że można je swobodnie wykorzystywać w komercyjnym projekcie, ale nie można go sprzedawać komercyjnie, jak to jest na przykład. Sprzedaję vget. Ale to tylko spekulacje, sugeruję, żebyś sprawdził ich licencje przynajmniej te z vget i wget. – melc
Gotowy działający przykładowy link nie działa – Confuse