2013-10-05 8 views
7

Ich versuche herauszufinden, wie Sie ein Video von youtube in das lokale Dateisystem herunterladen. Ich habe ein paar Pakete wie vGet ausprobiert, aber es scheint nicht zu funktionieren. Jede Hilfe wird sehr geschätzt.So laden Sie Youtube Video in Java

Antwort

10

ich vget habe versucht, https://github.com/axet/vget (bewegt hat https://gitlab.com/axet/vget) und es funktioniert gut. Sie können maven verwenden, um Abhängigkeiten von Pom-Dateien manuell einzurichten oder herunterzuladen. Abhängigkeiten

mit jdk6 zusammengestellt

als die direkten Download Probe lief ein fertiges Arbeitsbeispiel

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, sind Quellen, die in das Glas

zip-Datei - 1,89KB https://www.wetransfer.com/downloads/465f7ef8c6a76f79e4cbd7c9f38a608c20131005141332/41c09a86ed8eaa6e61f59282eabda2a120131005141332/4ac689

UPDATE # - NPE Problem, wenn in den Kommentaren

TLDR wie erwähnt das Herunterladen; Es scheint ein paar Probleme mit com.github.axet.vget.vhs.YouTubeParser zu geben, also fügen Sie nicht intrusiven Code hinzu, um es zu patchen und das Beispiel so zu machen, wie es früher war. Ersetzen Sie also einfach die ursprüngliche YoutubeParser Klasse durch die, die hier am Ende steht.

Finden Sie auch ein anderes funktionsfähiges Beispiel mit jar und allen erforderlichen libs, Quellen sind im jar enthalten (das wird automatisch nach einer gewissen Zeit entfernt (wird am 13. September 2014 gelöscht) - die Youtube URLs enthalten im Code sind zufällig)

Zip-Datei - 1,69MB (wetransfer.com Displays 1,7MB)

https://www.wetransfer.com/downloads/7b2d9182c9d91577919df3907cfd025620140906080118/a9ded3ba71496d4df9b4d035ac5a1e3920140906080118/6acf46#

A. FRAGEN

  1. In com.github.axet.vget.vhs.YouTubeParser ln229 die Variable qs die meisten der Zeit es nicht die resultierende Abfrage-String des http mit WGet erhalten ausgeführt enthält. Dies führt dazu, dass die npe später ausgelöst wird, wenn versucht wird, die Abfragezeichenfolge zu analysieren.

  2. Wenn das Problem 1 behoben wird dann die sig Variable in den URLs nicht gefunden wird, das von dem get_video_info, so mit Pattern.compile("sig=([^&,]*)") Parsen liefert keine Werte. Dies führt zu kontinuierlichen Wiederholungen, ohne dass das Video heruntergeladen werden muss.

B. BESCHLÜSSE(diese sind temporäre Flecken, wie das ursprüngliche Format der Antwort und die Ursache der WGet abgestürzten nicht bekannt sind)

  1. WGet erneut aufrufen, wenn die resultierende Abfragezeichenfolge ist leer, ohne dass ein WGet.HtmlLoader die Aufgabe zu erledigen scheint. Es wurde auch ein Ansatz zum Aufrufen eines einfachen HTTP-GET unter Verwendung des Apache-httpclient v4 bereitgestellt, in diesem Fall gibt es eine weitere Abhängigkeit von apache commons-logging.jar.

in ln248 hinzugefügt

 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.After Blick auf die Antwort gibt die Signatur in einem bestimmten Ort zu sein scheint, so verstärkt das ein bisschen Parsen. Wenn also die Musterausführung von Pattern.compile("sig=([^&,]*)") nichts zurückgibt, dann versuche auch mit Pattern.compile("signature%3D([^&,%]*)"). Diese Änderung erfolgte in der Methode 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); 
         } 
        } 
       } 

Die modifizierte com.github.axet.vget.vhs.YouTubeParser Datei wird wie folgt

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); 
     } 
    } 

} 
+0

Können wir diese für kommerzielle Zwecke? Ich meine, gibt es eine Lizenz dafür. –

+0

@Shabarinath Ich kann nur mit Sicherheit sagen, dass der von mir gepostete Code frei ist, so wie Sie möchten. Soweit vget und die Bibliotheken davon abhängen, bin ich nicht sicher, ob ich wahrscheinlich denken würde, dass sie frei sind, in einem kommerziellen Projekt verwendet zu werden, aber nicht kommerziell verkauft werden, wie z.B. Ich verkaufe Vget. Aber all das sind nur Spekulationen, ich schlage vor, Sie überprüfen ihre Lizenzen mindestens die von vget und wget. – melc

+0

Fertig funktionierendes Beispiel Link funktioniert nicht – Confuse