环境jdk14
maven构建

接口文档地址:https://github.com/1015770492/bilibili-download/blob/master/doc/bilibili-Api文档.md

原理是下载视频文件(不带声音)和音频文件,然后通过第三方工具ffmpeg合并视频文件和音频文件为一个文件
ffmpeg官网地址

自定义的http请求工具类部分代码展示;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;public class BiliBiliHttpUtils {/*** 没有就创建目录,有则返沪true* @param destDirName* @return*/public static boolean createDirect(String destDirName) {File file = new File(destDirName);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}return true;}/*** 下载文件的作用,需要3个参数 资源原路径,真正下载的url,保存本地的路径** @param refererUrl 视频的参考路径,* @param url        真正下载的url链接,可以是m4s文件和audio文件,下载后需要合并* @param savePath   保存的路径* @return 下载成功则返回true,中间报异常退出则返回false*/public static boolean downloadFile(String refererUrl, String url, String savePath) {System.out.print("下载文件:");System.out.println(savePath);//打印保存的文件路径RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.add("referer", refererUrl);//设置请求头HttpEntity<String> entity = new HttpEntity<String>("", headers);System.out.println("发送请求获取文件的输入流");ResponseEntity<Resource> in = restTemplate.exchange(url, HttpMethod.GET, entity, Resource.class);if (in.getStatusCode() == HttpStatus.OK) {try (InputStream is = in.getBody().getInputStream()) {//java9新特性自动关闭流boolean flag = createDirect(savePath);if (flag) {try (FileOutputStream fos = new FileOutputStream(savePath);) {System.out.println("正在写入文件...");is.transferTo(fos);//写入输出流return true;//写入成功返回true} catch (IOException e) {e.printStackTrace();System.out.println("写入中断");}}} catch (IOException e) {e.printStackTrace();System.out.println("创建文件夹失败");}System.out.println("文件写入完成");} else {System.out.println("状态码" + in.getStatusCode());System.out.println(in.toString());}return false;//默认返回失败}/*** 获取url中的 bvid** @param url* @return* @throws Exception*/public static String getBVID(String url) throws Exception {Pattern BVIDPartPattern = Pattern.compile("BV[a-z|0-9|A-Z]*");Matcher matcher = BVIDPartPattern.matcher(url);String bvid;if (matcher.find()) {bvid = matcher.group();} else {throw new Exception("传入的url中不包含bvid");}return bvid;}/*** 传入视频的播放地址,例如url: "https://www.bilibili.com/video/BV1m4411H7pi"  获取其中包含BV的这串字符串** @param url* @return* @throws Exception*/public static JSONObject getCidJSON(String url) throws Exception {String bvid = getBVID(url);//从url中转换成最终请求的url接口String requestUrl = new StringBuilder("http://api.bilibili.com/x/web-interface/view?bvid=").append(bvid).toString();String jsonString = new RestTemplate().getForEntity(requestUrl, String.class).getBody();JSONObject parse = JSONObject.parseObject(jsonString);return parse.getJSONObject("data");//返回data部分}/*** 传入cid的json数组,获取所有下载链接--》一个cid对应一个视频,一个视频有多个清晰度的播放源** @param cidJSONObject* @return*/public static List<JSONObject> getPlayUrlList(JSONObject cidJSONObject) {String bvid = cidJSONObject.getString("bvid");//视频的idString title = cidJSONObject.getString("title");//标题--》用来做文件夹String picUrl = cidJSONObject.getString("pic");//封面图片JSONArray pages = cidJSONObject.getJSONArray("pages");//包含这一系列视频的cid内容//如果传入的cid过多并行流会导致http请求过大,容易被服务器拒绝try (Stream<JSONObject> jsonObjectStream = pages.stream().map(o -> {JSONObject obj = (JSONObject) o;String cid = obj.getString("cid");//获取cidString part = obj.getString("part");//获取视频名  前缀System.out.println(part);//映射//获取播放地址的apiString requestUrl = new StringBuilder("https://api.bilibili.com/x/player/playurl?cid=").append(cid).append("&bvid=").append(bvid).append("&qn=80&fnver=0&fnval=16&fourk=1").toString();String jsonString = new RestTemplate().getForEntity(requestUrl, String.class).getBody();//执行太快了JSONObject data = JSONObject.parseObject(jsonString).getJSONObject("data");//获取api返回的jaon中的data对象/*** 添加自定义的属性,方便保存*/data.put("cid", cid);//将cid添加到返回的数据中data.put("directName", title);//添加视频的标题作为文件夹data.put("videoName", part);//添加视频的名称return data;//将添加了自定义属性的json返回,作为新的流})) {//        System.out.println(cidJSONObject);return jsonObjectStream.collect(Collectors.toList());//将收集到的url封装起来}}}

合并图像和音频文件代码展示

import java.io.File;
import java.io.IOException;
import java.util.concurrent.*;public class MergeVideoAndAudioUtils {static ExecutorService executorService = Executors.newFixedThreadPool(20);public static boolean merge(String videoPath, String audioPath, String savePath) throws ExecutionException, InterruptedException {File directory = new File("");//设定为当前文件夹String currentAbsolutePath = directory.getAbsolutePath();
//        System.out.println(currentAbsolutePath);String relativePath = "src/main/java/top/huashengshu/bilibili/utils/merge/util/ffmpeg.exe";String ffmpegAbsolutePath = new StringBuilder(currentAbsolutePath).append("/").append(relativePath).append(" -i \"").append(videoPath).append("\" -i \"").append(audioPath).append("\" -c copy \"").append(savePath).append("\"").toString();//合并音视频文件得命令CompletableFuture<Process> processFuture = CompletableFuture.supplyAsync(() -> {Process process = null;try {Runtime runtime = Runtime.getRuntime();//获取cmd窗口System.out.println(ffmpegAbsolutePath);//打印一下命令process = runtime.exec(ffmpegAbsolutePath);//执行合并命令} catch (IOException e) {e.printStackTrace();return process;//异常返回}return process;}, executorService);Process process = processFuture.get();//获取上一个的process对象CompletableFuture.runAsync(() -> {while (process.isAlive()) {}//判断合并命令是否执行完成,如果完成则会跳出循环clearGarbageFile(videoPath,savePath);//清理垃圾文件clearGarbageFile(audioPath,savePath);//清理垃圾文件},executorService);return true;//将合并结果返回}public static boolean clearGarbageFile(String filePath,String mp4Path) {File mp4File = new File(mp4Path);if (mp4File.exists()) {File tempFile = new File(filePath);if (tempFile.exists()){tempFile.delete();//文件存在,删除文件}else {System.out.println("文件不存在:"+filePath);}}else {System.out.println("没有合并成:"+mp4Path);}return true;}}

使用方式

调用BiliBiliUtilspatchDownload方法即可

/*** 测试案例** @param args*/
public static void main(String[] args) {String referUrl = "https://www.bilibili.com/video/BV1oi4y1u7Bq";//测试用的urlBiliBiliUtils.patchDownload(referUrl, "D:/");//将referUrl系列的所有视频存到D:/盘
}


项目没有完全完成,在改进中,并且会有后期版本,采用vue+ElementUI的静态页面,调用工具类实现批量下载视频,暂时没有实现登录功能

bilibili-download 哔哩哔哩视频下载器(批量下载专栏视频)相关推荐

  1. 使用Flickr下载器批量下载Flickr的相册

    相信用过Flickr下载图片的人都知道从Flickr上下载原图的操作有点小麻烦.楼主花了许久时间在网上寻找批量下载工具,一直没找到合适的.于是就自己动手写了个Win10应用:Flickr下载器,功能是 ...

  2. Earthdata(NASA)网站数据使用IDM(Internet Download Manager)下载器批量下载方法(MERRA-2为例)

    最近给亲近的人写了教程,想着也给大家分享一下. MERRA-2 网址: GES DISC 这个网址是下载MERRA-2 instM_3d_asm_Np类型的数据文件,具体各部分字母代表什么,看下载列表 ...

  3. 手机下载神器批量下载图片教程

    手机版IDM下载神器批量下载图片漫画实际操作教程,现在介绍两个批量下载图片的方法 视频教程: 手机IDM下载器批量下载图片漫画实际操作 首先,打开你要下载图片的网页,同时打开手机版idm下载器和手机记 ...

  4. 自媒体批量下载短视频软件,批量下载短视频有诀窍

    自媒体批量下载短视频软件,批量下载短视频有诀窍,现在随着短视频的爆火,越来越多的自媒体人和公司都注意到短视频这个平台流量有多大,短视频很容易变现也很容易引流,接下来我们来看看自媒体批量下载短视频软件有 ...

  5. android源码下载方法 批量下载 基于windows os

    安装win版的Gitbash, 在这里 http://msysgit.googlecode.com/files/Git-1.6.0.2-preview20080923.exe. 选择默认安装路径(否则 ...

  6. Google Earth谷歌地球卫片下载器--可下载全球历史卫星,无偏移、高精度

    Google Earth谷歌地球卫片下载器--可下载全球历史卫星,无偏移.高精度 Google Earth谷歌地球卫片下载器 (build662)升级正式发布,水经注万能地图下载器升级正式发布,水经注 ...

  7. GUI 界面的免费音乐下载 支持批量下载

    GUI 界面的免费音乐下载 支持批量下载 导包 import urllib import requests import wx import urllib import requests import ...

  8. python 爬取菜鸟教程python100题,百度贴吧图片反爬虫下载,批量下载

    每天一点点,记录学习 python 爬取菜鸟教程python100题 近期爬虫项目,看完请点赞哦: 1:python 爬取菜鸟教程python100题,百度贴吧图片反爬虫下载,批量下载 2:pytho ...

  9. python批量下载bilibili视频_如何批量下载bilibili的视频?

    貌似现在 you-get 已经支持批量下载了.通过下面命令就可以批量下载了 you-get --playlist 网址 本来是带这个需求来的,看到 Venchi 的答案,装了 Python3 之后发现 ...

  10. CS231n公开课系列1_视频+课件+作业下载+GitHub批量下载工具

    主要内容: PPT download notes download assignment download GitHub批量下载工具 CS231n是斯坦福大学教授针对使用深度学习处理图像(计算机视觉处 ...

最新文章

  1. 根据镜像安装oracle插件,docker镜像alpine中安装oracle客户端
  2. 计算路由汇总的方法(CIDR)
  3. 全flash站制作剖析
  4. Win8怎么查看IP地址
  5. 【linux学习笔记八】常用命令
  6. 全球首款采用离心风扇/90Hz刷新率的电竞手机红魔3发布
  7. 《时代周刊》四份NFT杂志封面拍卖结束,总售价为276 ETH
  8. DataSet的Join操作
  9. Python入门之面向对象module,library,package之间区别
  10. UBUNTU上新建GIT库
  11. 十大硬盘数据恢复软件
  12. 机器人学基础——坐标
  13. 电工/模电/数电/电气控制/PLC/单片机综合实验装置
  14. 拯救你的SD卡,找回丢失的文件
  15. 360众测靶场云文件服务器,360 政企安全官网_帮助应对高级威胁攻击
  16. 基于halcon的HSV颜色匹配实例
  17. Hive有分区文件到时select不到数据问题-----修复分区命令 msck repair table xxxxx
  18. 日计划安排 --- 凡事预则立,不预则废
  19. 《三体》中的经典名句
  20. 【Android 10 源码】healthd 模块 BatteryService 初始化

热门文章

  1. COSCon'22第七届中国开源年会火热筹备中,第一波赞助伙伴已集结,一起上车共赴开源盛宴吧~...
  2. WBTCITRIX上实现安装打印机的几种方法
  3. 若干年后再次的感动 --- 仙剑奇侠传
  4. 网吧无盘服务器游戏盘掉盘,虚拟盘与阵列对无盘网吧游戏性有的影响
  5. 加快提升国有企业合规管理建设
  6. 2022-2027年中国构树行业市场调研及未来发展趋势预测报告
  7. Android之常见安全问题
  8. 苹果cms10好看的模板自适应美化模板简约模板免费下载
  9. 再见我的师大,再见我的爱
  10. 知无涯之C++ typename的起源与用法