泰宁新闻网

M3U8在线视频文件下载合成MP4视频(以AV360为例)

泰宁新闻网 http://www.tainingxinwen.cn 2020-11-22 08:35 出处:网络
成人av在线,M3U8在线视频文件下载合成MP4视频(以AV360为例) 转载于:https://my.oschina.net/haitaohu/blog/1941179

成人av在线,M3U8在线视频文件下载合成MP4视频(以AV360为例)

转载于:https://my.oschina.net/haitaohu/blog/1941179

朋友推荐了一个比较隐蔽的盗版电影观看网站,网速特别慢观看不爽,就想是不是可以下载下来看,于是就写了这个小工具(www.av360.top)

首先,你要有能力在网页里面找到这个M3U8的索引文件,相信对于一个开发人员这个应该很容易,通过浏览器F12找到了这个索引文件,如下,我只截取了一部分,这个文件简单讲一下就是把一个视频切分成了好多小片段,而这个文件就是他们的目录文件,找到这个就容易了,接下来,把里面的每个视频片段下载下来合成就可以了。

第一步,下载索引文件

    public static String getIndexFile(String urlpath){
        try{
            URL url = new URL(urlpath);
            //下在资源
            BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(),"UTF-8"));
            String content = "" ;
            String line;
            while ((line = in.readLine()) != null) {
                content += line + "\n";
            }
            in.close();
            System.out.println(content);
            return content;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:4.971633,
ba1620338f71656.ts
#EXTINF:3.336667,
ba1620338f71657.ts
#EXTINF:3.336667,
ba1620338f71658.ts
#EXTINF:3.336667,
ba1620338f71659.ts
#EXTINF:3.336667,
ba1620338f71660.ts
#EXTINF:0.266933,
ba1620338f71661.ts
#EXT-X-ENDLIST

第二步,解析索引文件

    public static List analysisIndex(String content){
        Pattern pattern = Pattern.compile(".*ts");
        Matcher ma = pattern.matcher(content);

        List<String> list = new ArrayList<String>();

        while(ma.find()){
            String s = ma.group();
            list.add(s);
            System.out.println(s);
        }
        return list;
    }

解析的数据结果,把索引中的ts部分解析出来,方法很多

ba1620338f7035.ts
ba1620338f7036.ts
ba1620338f7037.ts
ba1620338f7038.ts
ba1620338f7039.ts
ba1620338f7040.ts
ba1620338f7041.ts
ba1620338f7042.ts
ba1620338f7043.ts
ba1620338f7044.ts
ba1620338f7045.ts
ba1620338f7046.ts
ba1620338f7047.ts

第三步,根据第二步的解析结果下载视频片段

    public static List<String> downLoadIndexFile(String preUrlPath,List<String> urlList){
        try{
            List<String> filePathList = new ArrayList<String>();
            String uuid = UUID.randomUUID().toString().replaceAll("-","");
            for(String urlpath:urlList){
                URL url = new URL(preUrlPath+urlpath);
                //下在资源
                DataInputStream dataInputStream = new DataInputStream(url.openStream());
                String fileOutPath = rootPath+File.separator+uuid+File.separator+urlpath;
                File file = new File(rootPath+File.separator+uuid);
                if(!file.exists()){
                    file.mkdirs();
                }
                FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath));
                byte[] bytes = new byte[1024];
                int length = 0;
                while ((length = dataInputStream.read(bytes)) != -1) {
                    fileOutputStream.write(bytes, 0, length);
                }
                System.out.println("下载完成..."+fileOutPath);
                dataInputStream.close();
                filePathList.add(fileOutPath);
            }

            return  filePathList;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

到这里基本大功告成了,写一个 main方法执行一下就ok了

    private static String rootPath = "F:\\m3u8dir";
    
    public static void main(String[] args) {
        String indexPath = "https://youku.cdn2-youku.com/20180710/12991_efbabf56/1000k/hls/index.m3u8";
        String prePath = indexPath.substring(0,indexPath.lastIndexOf("/")+1);
        System.out.println(prePath);
        //下载索引文件
        String indexStr = getIndexFile(indexPath);
        //解析索引文件
        List videoUrlList = analysisIndex(indexStr);
        //下载视频片段
        List<String> fileList = downLoadIndexFile(prePath,videoUrlList);
        

    }

其实还可以补充一步代码合成,额不过着急看电影,就直接用格式工厂合成了,后面会补充

--------------------------------------------------------------------------------------------------------------------

补充代码,多线程的写法,上面的单线程太慢了,同时补充了一个文件合成的方法,不需要格式工厂了

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DownFileUtil {

    private static String rootPath = "F:\\m3u8dir";
    
    public static void main(String[] args) {
        String indexPath = "https://youku.cdn2-youku.com/20180710/12991_efbabf56/1000k/hls/index.m3u8";
        String prePath = indexPath.substring(0,indexPath.lastIndexOf("/")+1);
        System.out.println(prePath);
        //下载索引文件
        String indexStr = getIndexFile(indexPath);
        //解析索引文件
        List videoUrlList = analysisIndex(indexStr);

        //生成文件下载目录
        String uuid = UUID.randomUUID().toString().replaceAll("-","");
        String fileRootPath = rootPath+File.separator+uuid;
        File fileDir = new File(fileRootPath);
        if(!fileDir.exists()){
            fileDir.mkdirs();
        }
        //下载视频片段,分成50个线程切片下载
        HashMap keyFileMap = new HashMap();
        int downForThreadCount = videoUrlList.size()/50;
        for(int i=0;i<videoUrlList.size();i+=downForThreadCount){
            int end = i+downForThreadCount-1;
            if(end>videoUrlList.size()){
                end = videoUrlList.size()-1;
            }
            new DownFileUtil().new downLoadNode(videoUrlList,i,end,keyFileMap,prePath,fileRootPath).start();
        }
        //等待下载
        while (keyFileMap.size()<videoUrlList.size()){
            System.out.println("当前下载数量"+keyFileMap.size());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //合成视频片段
        composeFile(fileRootPath+File.separator+uuid+".mp4",keyFileMap);
    }


    /**
     * 视频片段合成
     * @param fileOutPath
     * @param keyFileMap
     */
    public static void composeFile(String fileOutPath,HashMap<Integer,String> keyFileMap){
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath));
            byte[] bytes = new byte[1024];
            int length = 0;
            for(int i=0;i<keyFileMap.size();i++){
                String nodePath = keyFileMap.get(i);
                File file = new File(nodePath);
                if(!file.exists())
                    continue;
                FileInputStream fis = new FileInputStream(file);
                while ((length = fis.read(bytes)) != -1) {
                    fileOutputStream.write(bytes, 0, length);
                }
            }
        }catch (Exception e){

        }
    }




    public static List analysisIndex(String content){
        Pattern pattern = Pattern.compile(".*ts");
        Matcher ma = pattern.matcher(content);

        List<String> list = new ArrayList<String>();

        while(ma.find()){
            String s = ma.group();
            list.add(s);
            System.out.println(s);
        }
        return list;
    }


    class downLoadNode extends  Thread{
        private List<String> list ;
        private  int start;
        private  int end;
        public  HashMap keyFileMap ;
        private  String preUrlPath ;
        private  String fileRootPath ;

        public  downLoadNode(List list,int start,int end,HashMap keyFileMap,String preUrlPath,String fileRootPath){
            this.list = list;
            this.end = end;
            this.start = start;
            this.keyFileMap = keyFileMap;
            this.preUrlPath = preUrlPath;
            this.fileRootPath = fileRootPath;
        }
        @Override
        public void run(){
            try{
                String uuid = UUID.randomUUID().toString().replaceAll("-","");
                for( int i = start;i<=end;i++){
                    String urlpath = list.get(i);
                    URL url = new URL(preUrlPath+urlpath);
                    //下在资源
                    DataInputStream dataInputStream = new DataInputStream(url.openStream());
                    String fileOutPath = fileRootPath+File.separator+urlpath;
                    FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath));
                    byte[] bytes = new byte[1024];
                    int length = 0;
                    while ((length = dataInputStream.read(bytes)) != -1) {
                        fileOutputStream.write(bytes, 0, length);
                    }
                    dataInputStream.close();
                    keyFileMap.put(i,fileOutPath);
                }
                System.out.println("第"+start/(end-start)+"组完成,"+"开始位置"+start+",结束位置"+end);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static String getIndexFile(String urlpath){
        try{
            URL url = new URL(urlpath);
            //下在资源
            BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(),"UTF-8"));
            String content = "" ;
            String line;
            while ((line = in.readLine()) != null) {
                content += line + "\n";
            }
            in.close();
            System.out.println(content);
            return content;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

补充:部分ts文件被加密的问题

第一步:找到解密的key,一般会在某个请求中返回(额找不到没法解密)

#EXT-X-KEY:METHOD=AES-128,URI="/20180125/NfJJpxIH/1482kb/hls/key.key"

第二步:根据 AES  对ts进行解密,java可以实现可以自行百度一下

技术交流qq群:208779755

 

 

M3U8在线视频文件下载合成MP4视频(以AV360为例)的相关内容如下:

本文标题:M3U8在线视频文件下载合成MP4视频(以AV360为例)
http://www.tainingxinwen.cn/news/552394.html

0

精彩评论

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