朋友推荐了一个比较隐蔽的盗版电影观看网站,网速特别慢观看不爽,就想是不是可以下载下来看,于是就写了这个小工具
首先,你要有能力在网页里面找到这个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); Listlist = new ArrayList (); while(ma.find()){ String s = ma.group(); list.add(s); System.out.println(s); } return list; }
解析的数据结果,把索引中的ts部分解析出来,方法很多
ba1620338f7035.tsba1620338f7036.tsba1620338f7037.tsba1620338f7038.tsba1620338f7039.tsba1620338f7040.tsba1620338f7041.tsba1620338f7042.tsba1620338f7043.tsba1620338f7044.tsba1620338f7045.tsba1620338f7046.tsba1620338f7047.ts
第三步,根据第二步的解析结果下载视频片段
public static ListdownLoadIndexFile(String preUrlPath,List urlList){ try{ List filePathList = new ArrayList (); 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); //下载视频片段 ListfileList = 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;ivideoUrlList.size()){ end = videoUrlList.size()-1; } new DownFileUtil().new downLoadNode(videoUrlList,i,end,keyFileMap,prePath,fileRootPath).start(); } //等待下载 while (keyFileMap.size() keyFileMap){ try { FileOutputStream fileOutputStream = new FileOutputStream(new File(fileOutPath)); byte[] bytes = new byte[1024]; int length = 0; for(int i=0;i list = new ArrayList (); while(ma.find()){ String s = ma.group(); list.add(s); System.out.println(s); } return list; } class downLoadNode extends Thread{ private List 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