开发者

Code for download video from Youtube on Java, Android

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?

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Vector;

import android.app.Activity;
import android.app.ProgressDialog;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.MediaController;
import android.widget.VideoView;

public class MyActivity extends Activity {

    private class ReceivingDataFromYoutube extends AsyncTask<String, Void, Void> {

        private ProgressDialog dialog = new ProgressDialog(MyActivity.this);
        private String result;

        protected void onPreExecute() {
            dialog.setMessage("Downloading...");
            dialog.show();
        }

        @Override
        protected Void doInBackground(String... arg0) {
            int begin, end;
            String tmpstr = null;
            try {
                URL url=new URL("http://www.youtube.com/watch?v=y12-1miZHLs&nomobile=1");
                HttpURLConnection con = (HttpURLConnection) url.openConnection();
                con.setRequestMethod("GET");
                InputStream stream=con.getInputStream();
                InputStreamReader reader=new InputStreamReader(stream);
                StringBuffer buffer=new StringBuffer();
                char[] buf=new char[262144];                
                int chars_read;
                while ((chars_read = reader.read(buf, 0, 262144)) != -1) {
                    buffer.append(buf, 0, chars_read);
                }
                tmpstr=buffer.toString();

                begin  = tmpstr.indexOf("url_encoded_fmt_stream_map=");
                end = tmpstr.indexOf("&", begin + 27);
                if (end == -1) {
                    end = tmpstr.indexOf("\"", begin + 27);
                }
                tmpstr = UtilClass.URLDecode(tmpstr.substring(begin + 27, end));

            } catch (MalformedURLException e) {
                throw new RuntimeException();
            } catch (IOException e) {
                throw new RuntimeException();
            }

            Vector url_encoded_fmt_stream_map = new Vector();
            begin = 0;
            end   = tmpstr.indexOf(",");

            while (end != -1) {
                url_encoded_fmt_stream_map.addElement(tmpstr.substring(begin, end));
                begin = end + 1;
                end   = tmpstr.indexOf(",", begin);
            }

            url_encoded_fmt_stream_map.addElement(tmpstr.substring(begin, tmpstr.length()));
            String result = "";
            Enumeration url_encoded_fmt_stream_map_enum = url_encoded_fmt_stream_map.elements();
            while (url_encoded_fmt_stream_map_enum.hasMoreElements()) {
                tmpstr = (String)url_encoded_fmt_stream_map_enum.nextElement();
                begin = tmpstr.indexOf("itag=");
                if (begin != -1) {
                    end = tmpstr.indexOf("&", begin + 5);

                    if (end == -1) {
                          end = tmpstr.length();
                    }

              开发者_开发知识库      int fmt = Integer.parseInt(tmpstr.substring(begin + 5, end));

                    if (fmt == 35) {
                        begin = tmpstr.indexOf("url=");
                        if (begin != -1) {
                            end = tmpstr.indexOf("&", begin + 4);
                            if (end == -1) {
                               end = tmpstr.length();
                            }
                            result = UtilClass.URLDecode(tmpstr.substring(begin + 4, end));
                            this.result=result;
                            break;
                        }
                    }
                }
            }         
            try {
              URL u = new URL(result);
              HttpURLConnection c = (HttpURLConnection) u.openConnection();
              c.setRequestMethod("GET");
/*              c.setRequestProperty("Youtubedl-no-compression", "True");
              c.setRequestProperty("User-Agent", "YouTube");*/

              c.setDoOutput(true);
              c.connect();

              FileOutputStream f=new FileOutputStream(new File("/sdcard/3.flv"));

              InputStream in=c.getInputStream();
              byte[] buffer=new byte[1024];
              int sz = 0;
              while ( (sz = in.read(buffer)) > 0 ) {
                   f.write(buffer,0, sz);
              }
              f.close();
            } catch (MalformedURLException e) {
                new RuntimeException();
            } catch (IOException e) {
                new RuntimeException();
            }
            return null;
        }

        protected void onPostExecute(Void unused) {
            dialog.dismiss();
        }    

    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new ReceivingDataFromYoutube().execute();
    }   
}  


3 steps:

  1. Check the source 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 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!!!


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜