Code for download video from Youtube on Java, Android

前端 未结 3 896
难免孤独
难免孤独 2020-11-30 17:19

I created code for download video from Youtube, but this code doesn\'t work with Wi-fi connection and work with mobile connection. Where did I have mistake?

         


        
相关标签:
3条回答
  • 2020-11-30 17:53

    Ref : Youtube Video Download (Android/Java)

    private static final HashMap<String, Meta> typeMap = new HashMap<String, Meta>();
    

    initTypeMap(); call first

    class Meta {
        public String num;
        public String type;
        public String ext;
    
        Meta(String num, String ext, String type) {
            this.num = num;
            this.ext = ext;
            this.type = type;
        }
    }
    
    class Video {
        public String ext = "";
        public String type = "";
        public String url = "";
    
        Video(String ext, String type, String url) {
            this.ext = ext;
            this.type = type;
            this.url = url;
        }
    }
    
    public ArrayList<Video> getStreamingUrisFromYouTubePage(String ytUrl)
            throws IOException {
        if (ytUrl == null) {
            return null;
        }
    
        // Remove any query params in query string after the watch?v=<vid> in
        // e.g.
        // http://www.youtube.com/watch?v=0RUPACpf8Vs&feature=youtube_gdata_player
        int andIdx = ytUrl.indexOf('&');
        if (andIdx >= 0) {
            ytUrl = ytUrl.substring(0, andIdx);
        }
    
        // Get the HTML response
        /* String userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:8.0.1)";*/
       /* HttpClient client = new DefaultHttpClient();
        client.getParams().setParameter(CoreProtocolPNames.USER_AGENT,
                userAgent);
        HttpGet request = new HttpGet(ytUrl);
        HttpResponse response = client.execute(request);*/
        String html = "";
        HttpsURLConnection c = (HttpsURLConnection) new URL(ytUrl).openConnection();
        c.setRequestMethod("GET");
        c.setDoOutput(true);
        c.connect();
        InputStream in = c.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder str = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            str.append(line.replace("\\u0026", "&"));
        }
        in.close();
        html = str.toString();
    
        // Parse the HTML response and extract the streaming URIs
        if (html.contains("verify-age-thumb")) {
            Log.e("Downloader", "YouTube is asking for age verification. We can't handle that sorry.");
            return null;
        }
    
        if (html.contains("das_captcha")) {
            Log.e("Downloader", "Captcha found, please try with different IP address.");
            return null;
        }
    
        Pattern p = Pattern.compile("stream_map\":\"(.*?)?\"");
        // Pattern p = Pattern.compile("/stream_map=(.[^&]*?)\"/");
        Matcher m = p.matcher(html);
        List<String> matches = new ArrayList<String>();
        while (m.find()) {
            matches.add(m.group());
        }
    
        if (matches.size() != 1) {
            Log.e("Downloader", "Found zero or too many stream maps.");
            return null;
        }
    
        String urls[] = matches.get(0).split(",");
        HashMap<String, String> foundArray = new HashMap<String, String>();
        for (String ppUrl : urls) {
            String url = URLDecoder.decode(ppUrl, "UTF-8");
            Log.e("URL","URL : "+url);
    
            Pattern p1 = Pattern.compile("itag=([0-9]+?)[&]");
            Matcher m1 = p1.matcher(url);
            String itag = null;
            if (m1.find()) {
                itag = m1.group(1);
            }
    
            Pattern p2 = Pattern.compile("signature=(.*?)[&]");
            Matcher m2 = p2.matcher(url);
            String sig = null;
            if (m2.find()) {
                sig = m2.group(1);
            } else {
                Pattern p23 = Pattern.compile("signature&s=(.*?)[&]");
                Matcher m23 = p23.matcher(url);
                if (m23.find()) {
                    sig = m23.group(1);
                }
            }
    
            Pattern p3 = Pattern.compile("url=(.*?)[&]");
            Matcher m3 = p3.matcher(ppUrl);
            String um = null;
            if (m3.find()) {
                um = m3.group(1);
            }
    
            if (itag != null && sig != null && um != null) {
                Log.e("foundArray","Adding Value");
                foundArray.put(itag, URLDecoder.decode(um, "UTF-8") + "&"
                        + "signature=" + sig);
            }
        }
        Log.e("foundArray","Size : "+foundArray.size());
        if (foundArray.size() == 0) {
            Log.e("Downloader", "Couldn't find any URLs and corresponding signatures");
            return null;
        }
    
    
        ArrayList<Video> videos = new ArrayList<Video>();
    
        for (String format : typeMap.keySet()) {
            Meta meta = typeMap.get(format);
    
            if (foundArray.containsKey(format)) {
                Video newVideo = new Video(meta.ext, meta.type,
                        foundArray.get(format));
                videos.add(newVideo);
                Log.d("Downloader", "YouTube Video streaming details: ext:" + newVideo.ext
                        + ", type:" + newVideo.type + ", url:" + newVideo.url);
            }
        }
    
        return videos;
    }
    
    private class YouTubePageStreamUriGetter extends AsyncTask<String, String, ArrayList<Video>> {
        ProgressDialog progressDialog;
    
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog = ProgressDialog.show(webViewActivity.this, "",
                    "Connecting to YouTube...", true);
        }
    
        @Override
        protected ArrayList<Video> doInBackground(String... params) {
            ArrayList<Video> fVideos = new ArrayList<>();
            String url = params[0];
            try {
                ArrayList<Video> videos = getStreamingUrisFromYouTubePage(url);
                /*                Log.e("Downloader","Size of Video : "+videos.size());*/
                if (videos != null && !videos.isEmpty()) {
                    for (Video video : videos)
                    {
                        Log.e("Downloader", "ext : " + video.ext);
                        if (video.ext.toLowerCase().contains("mp4") || video.ext.toLowerCase().contains("3gp") || video.ext.toLowerCase().contains("flv") || video.ext.toLowerCase().contains("webm")) {
                            ext = video.ext.toLowerCase();
                            fVideos.add(new Video(video.ext,video.type,video.url));
                        }
                    }
    
    
                    return fVideos;
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.e("Downloader", "Couldn't get YouTube streaming URL", e);
            }
            Log.e("Downloader", "Couldn't get stream URI for " + url);
            return null;
        }
    
        @Override
        protected void onPostExecute(ArrayList<Video> streamingUrl) {
            super.onPostExecute(streamingUrl);
            progressDialog.dismiss();
            if (streamingUrl != null) {
                if (!streamingUrl.isEmpty()) {
                    //Log.e("Steaming Url", "Value : " + streamingUrl);
    
                    for (int i = 0; i < streamingUrl.size(); i++) {
                        Video fX = streamingUrl.get(i);
                        Log.e("Founded Video", "URL : " + fX.url);
                        Log.e("Founded Video", "TYPE : " + fX.type);
                        Log.e("Founded Video", "EXT : " + fX.ext);
                    }
                    //new ProgressBack().execute(new String[]{streamingUrl, filename + "." + ext});
                }
            }
        }
    }
    public void initTypeMap()
    {
        typeMap.put("13", new Meta("13", "3GP", "Low Quality - 176x144"));
        typeMap.put("17", new Meta("17", "3GP", "Medium Quality - 176x144"));
        typeMap.put("36", new Meta("36", "3GP", "High Quality - 320x240"));
        typeMap.put("5", new Meta("5", "FLV", "Low Quality - 400x226"));
        typeMap.put("6", new Meta("6", "FLV", "Medium Quality - 640x360"));
        typeMap.put("34", new Meta("34", "FLV", "Medium Quality - 640x360"));
        typeMap.put("35", new Meta("35", "FLV", "High Quality - 854x480"));
        typeMap.put("43", new Meta("43", "WEBM", "Low Quality - 640x360"));
        typeMap.put("44", new Meta("44", "WEBM", "Medium Quality - 854x480"));
        typeMap.put("45", new Meta("45", "WEBM", "High Quality - 1280x720"));
        typeMap.put("18", new Meta("18", "MP4", "Medium Quality - 480x360"));
        typeMap.put("22", new Meta("22", "MP4", "High Quality - 1280x720"));
        typeMap.put("37", new Meta("37", "MP4", "High Quality - 1920x1080"));
        typeMap.put("33", new Meta("38", "MP4", "High Quality - 4096x230"));
    }
    

    Edit 2:

    Some time This Code Not worked proper

    Same-origin policy

    https://en.wikipedia.org/wiki/Same-origin_policy

    https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

    problem of Same-origin policy. Essentially, you cannot download this file from www.youtube.com because they are different domains. A workaround of this problem is [CORS][1]. 
    

    Ref : https://superuser.com/questions/773719/how-do-all-of-these-save-video-from-youtube-services-work/773998#773998

    url_encoded_fmt_stream_map // traditional: contains video and audio stream
    adaptive_fmts              // DASH: contains video or audio stream
    

    Each of these is a comma separated array of what I would call "stream objects". Each "stream object" will contain values like this

    url  // direct HTTP link to a video
    itag // code specifying the quality
    s    // signature, security measure to counter downloading
    

    Each URL will be encoded so you will need to decode them. Now the tricky part.

    YouTube has at least 3 security levels for their videos

    unsecured // as expected, you can download these with just the unencoded URL
    s         // see below
    RTMPE     // uses "rtmpe://" protocol, no known method for these
    

    The RTMPE videos are typically used on official full length movies, and are protected with SWF Verification Type 2. This has been around since 2011 and has yet to be reverse engineered.

    The type "s" videos are the most difficult that can actually be downloaded. You will typcially see these on VEVO videos and the like. They start with a signature such as

    AA5D05FA7771AD4868BA4C977C3DEAAC620DE020E.0F421820F42978A1F8EAFCDAC4EF507DB5 Then the signature is scrambled with a function like this

    function mo(a) {
      a = a.split("");
      a = lo.rw(a, 1);
      a = lo.rw(a, 32);
      a = lo.IC(a, 1);
      a = lo.wS(a, 77);
      a = lo.IC(a, 3);
      a = lo.wS(a, 77);
      a = lo.IC(a, 3);
      a = lo.wS(a, 44);
      return a.join("")
    }
    

    This function is dynamic, it typically changes every day. To make it more difficult the function is hosted at a URL such as

    http://s.ytimg.com/yts/jsbin/html5player-en_US-vflycBCEX.js

    this introduces the problem of Same-origin policy. Essentially, you cannot download this file from www.youtube.com because they are different domains. A workaround of this problem is CORS. With CORS, s.ytimg.com could add this header

    Access-Control-Allow-Origin: http://www.youtube.com
    

    and it would allow the JavaScript to download from www.youtube.com. Of course they do not do this. A workaround for this workaround is to use a CORS proxy. This is a proxy that responds with the following header to all requests

    Access-Control-Allow-Origin: *
    

    So, now that you have proxied your JS file, and used the function to scramble the signature, you can use that in the querystring to download a video.

    0 讨论(0)
  • 2020-11-30 17:57

    3 steps:

    1. Check the sorce code (HTML) of YouTube, you'll get the link like this (http%253A%252F%252Fo-o.preferred.telemar-cnf1.v18.lscache6.c.youtube.com%252Fvideoplayback ...);

    2. Decode the url (remove the codes %2B,%25 etc), create a decoder with the codes: http://www.w3schools.com/tags/ref_urlencode.asp and use the function Uri.decode(url) to replace invalid escaped octets;

    3. Use the code to download stream:

      URL u = null;
      InputStream is = null;  
      
      try {
          u = new URL(url);
          is = u.openStream(); 
          HttpURLConnection huc = (HttpURLConnection)u.openConnection(); //to know the size of video
          int size = huc.getContentLength();                 
      
          if(huc != null) {
              String fileName = "FILE.mp4";
              String storagePath = Environment.getExternalStorageDirectory().toString();
              File f = new File(storagePath,fileName);
      
              FileOutputStream fos = new FileOutputStream(f);
              byte[] buffer = new byte[1024];
              int len1 = 0;
              if(is != null) {
                  while ((len1 = is.read(buffer)) > 0) {
                      fos.write(buffer,0, len1);  
                  }
              }
              if(fos != null) {
                  fos.close();
              }
          }                       
      } catch (MalformedURLException mue) {
          mue.printStackTrace();
      } catch (IOException ioe) {
          ioe.printStackTrace();
      } finally {
          try {               
              if(is != null) {
                  is.close();
              }
          } catch (IOException ioe) {
              // just going to ignore this one
          }
      }
      

    That's all, most of stuff you'll find on the web!!!

    0 讨论(0)
  • 2020-11-30 18:00

    METHOD 1 ( Recommanded )

    Library YouTubeExtractor

    Add into your gradle file

     allprojects {
            repositories {
                maven { url "https://jitpack.io" }
            }
        }
    

    And dependencies

     compile 'com.github.Commit451.YouTubeExtractor:youtubeextractor:2.1.0'
    

    Add this small code and you done. Demo HERE

    public class MainActivity extends AppCompatActivity {
    
        private static final String YOUTUBE_ID = "ea4-5mrpGfE";
    
        private final YouTubeExtractor mExtractor = YouTubeExtractor.create();
    
    
        private Callback<YouTubeExtractionResult> mExtractionCallback = new Callback<YouTubeExtractionResult>() {
            @Override
            public void onResponse(Call<YouTubeExtractionResult> call, Response<YouTubeExtractionResult> response) {
                bindVideoResult(response.body());
            }
    
            @Override
            public void onFailure(Call<YouTubeExtractionResult> call, Throwable t) {
                onError(t);
            }
        };
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
    //        For android youtube extractor library  com.github.Commit451.YouTubeExtractor:youtubeextractor:2.1.0'
            mExtractor.extract(YOUTUBE_ID).enqueue(mExtractionCallback);
    
        }
    
    
        private void onError(Throwable t) {
            t.printStackTrace();
            Toast.makeText(MainActivity.this, "It failed to extract. So sad", Toast.LENGTH_SHORT).show();
        }
    
    
        private void bindVideoResult(YouTubeExtractionResult result) {
    
    //        Here you can get download url link
            Log.d("OnSuccess", "Got a result with the best url: " + result.getBestAvailableQualityVideoUri());
    
            Toast.makeText(this, "result : " + result.getSd360VideoUri(), Toast.LENGTH_SHORT).show();
        }
    }
    

    You can get download link in bindVideoResult() method.

    METHOD 2

    Using this library android-youtubeExtractor

    Add into gradle file

    repositories {
        maven { url "https://jitpack.io" }
    }
    
    compile 'com.github.HaarigerHarald:android-youtubeExtractor:master-SNAPSHOT'
    

    Here is the code for getting download url.

           String youtubeLink = "http://youtube.com/watch?v=xxxx";
    
        YouTubeUriExtractor ytEx = new YouTubeUriExtractor(this) {
            @Override
            public void onUrisAvailable(String videoId, String videoTitle, SparseArray<YtFile> ytFiles) {
                if (ytFiles != null) {
                    int itag = 22;
    // Here you can get download url
                    String downloadUrl = ytFiles.get(itag).getUrl();
                }
            }
        };
    
        ytEx.execute(youtubeLink);
    
    0 讨论(0)
提交回复
热议问题