如何在java上从youtube下载视频?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4032766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 10:44:58  来源:igfitidea点击:

How to download videos from youtube on java?

javayoutube

提问by Vytas

how to download videos from youtube on Java? need class(or piece of code) which describes how to do that. Thank you.

如何在 Java 上从 youtube 下载视频?需要描述如何做到这一点的类(或一段代码)。谢谢你。

回答by Boris Pavlovi?

Regarding the format (mp4 or flv) decide which URLyou want to use. Then use this tutorialto download the video and save it into a local directory.

关于格式(mp4 或 flv),决定您要使用的URL。然后使用本教程下载视频并将其保存到本地目录中。

回答by pinkteddybear888

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.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.regex.Pattern;

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 JavaYoutubeDownloader {

 public static String newline = System.getProperty("line.separator");
 private static final Logger log = Logger.getLogger(JavaYoutubeDownloader.class.getCanonicalName());
 private static final Level defaultLogLevelSelf = Level.FINER;
 private static final Level defaultLogLevel = Level.WARNING;
 private static final Logger rootlog = Logger.getLogger("");
 private static final String scheme = "http";
 private static final String host = "www.youtube.com";
 private static final Pattern commaPattern = Pattern.compile(",");
 private static final Pattern pipePattern = Pattern.compile("\|");
 private static final char[] ILLEGAL_FILENAME_CHARACTERS = { '/', '\n', '\r', '\t', '
package com.mycompany.ytd;

import java.io.File;
import java.net.URL;
import com.github.axet.vget.VGet;

/**
 *
 * @author Manindar
 */
public class YTD {

    public static void main(String[] args) {
        try {
            String url = "https://www.youtube.com/watch?v=s10ARdfQUOY";
            String path = "D:\Manindar\YTD\";
            VGet v = new VGet(new URL(url), new File(path));
            v.download();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
', '\f', '`', '?', '*', '\', '<', '>', '|', '\"', ':' }; private static void usage(String error) { if (error != null) { System.err.println("Error: " + error); } System.err.println("usage: JavaYoutubeDownload VIDEO_ID DESTINATION_DIRECTORY"); System.exit(-1); } public static void main(String[] args) { if (args == null || args.length == 0) { usage("Missing video id. Extract from http://www.youtube.com/watch?v=VIDEO_ID"); } try { setupLogging(); log.fine("Starting"); String videoId = null; String outdir = "."; // TODO Ghetto command line parsing 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); String extension = getExtension(format); play(videoId, format, encoding, userAgent, outputDir, extension); } catch (Throwable t) { t.printStackTrace(); } log.fine("Finished"); } private static String getExtension(int format) { // TODO return "mp4"; } private static void play(String videoId, int format, String encoding, String userAgent, File outputdir, String extension) throws Throwable { log.fine("Retrieving " + videoId); List<NameValuePair> qparams = new ArrayList<NameValuePair>(); qparams.add(new BasicNameValuePair("video_id", videoId)); qparams.add(new BasicNameValuePair("fmt", "" + format)); URI uri = getUri("get_video_info", qparams); CookieStore cookieStore = new BasicCookieStore(); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); HttpClient httpclient = new DefaultHttpClient(); HttpGet httpget = new HttpGet(uri); httpget.setHeader("User-Agent", userAgent); log.finer("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<NameValuePair> infoMap = new ArrayList<NameValuePair>(); URLEncodedUtils.parse(infoMap, new Scanner(videoInfo), encoding); String token = null; String downloadUrl = null; String filename = videoId; for (NameValuePair pair : infoMap) { String key = pair.getName(); String val = pair.getValue(); log.finest(key + "=" + val); if (key.equals("token")) { token = val; } else if (key.equals("title")) { filename = val; } else if (key.equals("fmt_url_map")) { String[] formats = commaPattern.split(val); for (String fmt : formats) { String[] fmtPieces = pipePattern.split(fmt); if (fmtPieces.length == 2) { // in the end, download somethin! downloadUrl = fmtPieces[1]; int pieceFormat = Integer.parseInt(fmtPieces[0]); if (pieceFormat == format) { // found what we want downloadUrl = fmtPieces[1]; break; } } } } } filename = cleanFilename(filename); if (filename.length() == 0) { filename = videoId; } else { filename += "_" + videoId; } filename += "." + extension; File outputfile = new File(outputdir, filename); 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); log.finer("Executing " + httpget2.getURI()); HttpClient httpclient2 = new DefaultHttpClient(); HttpResponse response2 = httpclient2.execute(httpget2); HttpEntity entity2 = response2.getEntity(); if (entity2 != null && response2.getStatusLine().getStatusCode() == 200) { long length = entity2.getContentLength(); InputStream instream2 = entity2.getContent(); log.finer("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 String cleanFilename(String filename) { for (char c : ILLEGAL_FILENAME_CHARACTERS) { filename = filename.replace(c, '_'); } return filename; } private static URI getUri(String path, List<NameValuePair> qparams) throws URISyntaxException { URI uri = URIUtils.createURI(scheme, host, -1, "/" + path, URLEncodedUtils.format(qparams, "UTF-8"), null); return uri; } private static void setupLogging() { changeFormatter(new Formatter() { @Override public String format(LogRecord arg0) { return arg0.getMessage() + newline; } }); explicitlySetAllLogging(Level.FINER); } private static void changeFormatter(Formatter formatter) { Handler[] handlers = rootlog.getHandlers(); for (Handler handler : handlers) { handler.setFormatter(formatter); } } private static void explicitlySetAllLogging(Level level) { rootlog.setLevel(Level.ALL); for (Handler handler : rootlog.getHandlers()) { handler.setLevel(defaultLogLevelSelf); } log.setLevel(level); rootlog.setLevel(defaultLogLevel); } 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; } } /** * <pre> * Exploded results from get_video_info: * * fexp=90... * allow_embed=1 * fmt_stream_map=35|http://v9.lscache8... * fmt_url_map=35|http://v9.lscache8... * allow_ratings=1 * keywords=Stefan Molyneux,Luke Bessey,anarchy,stateless society,giant stone cow,the story of our unenslavement,market anarchy,voluntaryism,anarcho capitalism * track_embed=0 * fmt_list=35/854x480/9/0/115,34/640x360/9/0/115,18/640x360/9/0/115,5/320x240/7/0/0 * author=lukebessey * muted=0 * length_seconds=390 * plid=AA... * ftoken=null * status=ok * watermark=http://s.ytimg.com/yt/swf/logo-vfl_bP6ud.swf,http://s.ytimg.com/yt/swf/hdlogo-vfloR6wva.swf * timestamp=12... * has_cc=False * fmt_map=35/854x480/9/0/115,34/640x360/9/0/115,18/640x360/9/0/115,5/320x240/7/0/0 * leanback_module=http://s.ytimg.com/yt/swfbin/leanback_module-vflJYyeZN.swf * hl=en_US * endscreen_module=http://s.ytimg.com/yt/swfbin/endscreen-vflk19iTq.swf * vq=auto * avg_rating=5.0 * video_id=S6IZP3yRJ9I * token=vPpcFNh... * thumbnail_url=http://i4.ytimg.com/vi/S6IZP3yRJ9I/default.jpg * title=The Story of Our Unenslavement - Animated * </pre> */

回答by BullyWiiPlaza

ytd2is a fully functional YouTube video downloader. Check out its source codeif you want to see how it's done.

ytd2是一个功能齐全的 YouTube 视频下载器。如果您想了解它是如何完成的,请查看它的源代码

Alternatively, you can also call an external process like youtube-dlto do the job. This is probably the easiest solution but it isn't in "pure" Java.

或者,您也可以调用外部流程youtube-dl来完成这项工作。这可能是最简单的解决方案,但它不是“纯”Java。

回答by Manindar

I know i am answering late. But this code may useful for some one. So i am attaching it here.

我知道我回答晚了。但是此代码可能对某些人有用。所以我把它附在这里。

Use the following java code to download the videos from YouTube.

使用以下 java 代码从 YouTube 下载视频。

        <dependency>
            <groupId>com.github.axet</groupId>
            <artifactId>vget</artifactId>
            <version>1.1.33</version>
        </dependency>

Add the below Dependency in your POM.XMLfile

POM.XML文件中添加以下依赖

String youtubeLink = "http://youtube.com/watch?v=xxxx";

new YouTubeExtractor(this) {
@Override
public void onExtractionComplete(SparseArray<YtFile> ytFiles, VideoMeta vMeta) {
    if (ytFiles != null) {
        int itag = 22;
    String downloadUrl = ytFiles.get(itag).getUrl();
    }
}
}.extract(youtubeLink, true, true);

Hope this will be useful.

希望这将是有用的。

回答by Ashvin solanki

Ref :Youtube Video Download (Android/Java)

Ref : Youtube 视频下载 (Android/Java)

Edit 3

编辑 3

You can use the Lib : https://github.com/HaarigerHarald/android-youtubeExtractor

您可以使用 Lib :https: //github.com/HaarigerHarald/android-youtubeExtractor

Ex :

前任 :

private boolean decipherSignature(final SparseArray<String> encSignatures) throws IOException {
    // Assume the functions don't change that much
    if (decipherFunctionName == null || decipherFunctions == null) {
        String decipherFunctUrl = "https://s.ytimg.com/yts/jsbin/" + decipherJsFileName;

        BufferedReader reader = null;
        String javascriptFile;
        URL url = new URL(decipherFunctUrl);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestProperty("User-Agent", USER_AGENT);
        try {
            reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            StringBuilder sb = new StringBuilder("");
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append(" ");
            }
            javascriptFile = sb.toString();
        } finally {
            if (reader != null)
                reader.close();
            urlConnection.disconnect();
        }

        if (LOGGING)
            Log.d(LOG_TAG, "Decipher FunctURL: " + decipherFunctUrl);
        Matcher mat = patSignatureDecFunction.matcher(javascriptFile);
        if (mat.find()) {
            decipherFunctionName = mat.group(1);
            if (LOGGING)
                Log.d(LOG_TAG, "Decipher Functname: " + decipherFunctionName);

            Pattern patMainVariable = Pattern.compile("(var |\s|,|;)" + decipherFunctionName.replace("$", "\$") +
                    "(=function\((.{1,3})\)\{)");

            String mainDecipherFunct;

            mat = patMainVariable.matcher(javascriptFile);
            if (mat.find()) {
                mainDecipherFunct = "var " + decipherFunctionName + mat.group(2);
            } else {
                Pattern patMainFunction = Pattern.compile("function " + decipherFunctionName.replace("$", "\$") +
                        "(\((.{1,3})\)\{)");
                mat = patMainFunction.matcher(javascriptFile);
                if (!mat.find())
                    return false;
                mainDecipherFunct = "function " + decipherFunctionName + mat.group(2);
            }

            int startIndex = mat.end();

            for (int braces = 1, i = startIndex; i < javascriptFile.length(); i++) {
                if (braces == 0 && startIndex + 5 < i) {
                    mainDecipherFunct += javascriptFile.substring(startIndex, i) + ";";
                    break;
                }
                if (javascriptFile.charAt(i) == '{')
                    braces++;
                else if (javascriptFile.charAt(i) == '}')
                    braces--;
            }
            decipherFunctions = mainDecipherFunct;
            // Search the main function for extra functions and variables
            // needed for deciphering
            // Search for variables
            mat = patVariableFunction.matcher(mainDecipherFunct);
            while (mat.find()) {
                String variableDef = "var " + mat.group(2) + "={";
                if (decipherFunctions.contains(variableDef)) {
                    continue;
                }
                startIndex = javascriptFile.indexOf(variableDef) + variableDef.length();
                for (int braces = 1, i = startIndex; i < javascriptFile.length(); i++) {
                    if (braces == 0) {
                        decipherFunctions += variableDef + javascriptFile.substring(startIndex, i) + ";";
                        break;
                    }
                    if (javascriptFile.charAt(i) == '{')
                        braces++;
                    else if (javascriptFile.charAt(i) == '}')
                        braces--;
                }
            }
            // Search for functions
            mat = patFunction.matcher(mainDecipherFunct);
            while (mat.find()) {
                String functionDef = "function " + mat.group(2) + "(";
                if (decipherFunctions.contains(functionDef)) {
                    continue;
                }
                startIndex = javascriptFile.indexOf(functionDef) + functionDef.length();
                for (int braces = 0, i = startIndex; i < javascriptFile.length(); i++) {
                    if (braces == 0 && startIndex + 5 < i) {
                        decipherFunctions += functionDef + javascriptFile.substring(startIndex, i) + ";";
                        break;
                    }
                    if (javascriptFile.charAt(i) == '{')
                        braces++;
                    else if (javascriptFile.charAt(i) == '}')
                        braces--;
                }
            }

            if (LOGGING)
                Log.d(LOG_TAG, "Decipher Function: " + decipherFunctions);
            decipherViaWebView(encSignatures);
            if (CACHING) {
                writeDeciperFunctToChache();
            }
        } else {
            return false;
        }
    } else {
        decipherViaWebView(encSignatures);
    }
    return true;
}

They decipherSignature using :

他们使用以下方法解密签名:

 Pattern p2 = Pattern.compile("sig=(.*?)[&]");
        Matcher m2 = p2.matcher(url);
        String sig = null;
        if (m2.find()) {
            sig = m2.group(1);
        }

Now with use of this library High Quality VideosLossing Audio so i use the MediaMuxerfor Murging Audioand Video for Final Output

现在使用这个库高质量视频丢失音频,所以我使用MediaMuxerforMurging Audio和 Video for Final Output

Edit 1

编辑 1

https://stackoverflow.com/a/15240012/9909365

https://stackoverflow.com/a/15240012/9909365

Why the previous answer not worked

为什么以前的答案不起作用

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

As of November 2016, this is a little rough around the edges, but displays the basic principle. The url_encoded_fmt_stream_map today does not have a space after the colon (better make this optional) and "sig" has been changed to "signature"

and while i am debuging the code i found the new keyword its signature&sin many video's URL

截至 2016 年 11 月,这有点粗糙,但显示了基本原理。今天的 url_encoded_fmt_stream_map 冒号后没有空格(最好把它sig设为可选),并且“ ”已更改为“ signature

在调试代码时,我signature&s在许多视频的 URL 中发现了新关键字

here edited answer

这里编辑的答案

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

initTypeMap(); call first

initTypeMap(); 先打电话

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]. 

Edit 2:

编辑2:

Some time This Code Not worked proper

有一段时间此代码无法正常工作

Same-origin policy

同源策略

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

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

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

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

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

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

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

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

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

每一个都是一个逗号分隔的数组,我称之为“流对象”。每个“流对象”将包含这样的值

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

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

每个 URL 都将被编码,因此您需要对其进行解码。现在是棘手的部分。

YouTube has at least 3 security levels for their videos

YouTube 的视频至少有 3 个安全级别

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("")
}

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.

RTMPE 视频通常用于官方全长电影,并受 SWF 验证类型 2 保护。自 2011 年以来一直存在,尚未进行逆向工程。

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

类型“s”的视频是最难下载的。您通常会在 VEVO 视频等中看到这些。它们以签名开头,例如

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

AA5D05FA7771AD4868BA4C977C3DEAAC620DE020E.0F421820F42978A1F8EAFCDAC4EF507DB5 然后用这样的函数对签名进行加扰

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

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

此功能是动态的,通常每天都在变化。为了使其更加困难,该函数托管在一个 URL 上,例如

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

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

这就引入了同源策略的问题。本质上,您不能从 www.youtube.com 下载此文件,因为它们是不同的域。此问题的解决方法是 CORS。使用 CORS,s.ytimg.com 可以添加此标头

Access-Control-Allow-Origin: *

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

它允许从 www.youtube.com 下载 JavaScript。当然,他们不这样做。此变通方法的变通方法是使用 CORS 代理。这是一个代理,以以下标头响应所有请求

##代码##

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.

所以,既然您已经代理了您的 JS 文件,并使用该函数来加扰签名,您可以在查询字符串中使用它来下载视频。