From e19d1cdedae444c2e33d7d77cf65f81fc8987bb0 Mon Sep 17 00:00:00 2001 From: Yutousama <583819556@qq.com> Date: Mon, 15 Aug 2022 02:24:49 +0800 Subject: [PATCH 1/2] =?UTF-8?q?add:=E6=96=B0=E5=A2=9EB=E7=AB=99=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E4=B8=8B=E8=BD=BD=E6=8E=A5=E5=8F=A3=E5=8F=8A=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qqbot/Controllers/BiliBiliController.java | 29 ++++ .../qqbot/models/BiliBili/BiliVideo.java | 142 ++++++++++++++---- .../java/com/yutou/qqbot/utlis/AppTools.java | 12 +- web/bilibili.html | 81 ++++++++++ 4 files changed, 227 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/yutou/qqbot/Controllers/BiliBiliController.java create mode 100644 web/bilibili.html diff --git a/src/main/java/com/yutou/qqbot/Controllers/BiliBiliController.java b/src/main/java/com/yutou/qqbot/Controllers/BiliBiliController.java new file mode 100644 index 0000000..2cad996 --- /dev/null +++ b/src/main/java/com/yutou/qqbot/Controllers/BiliBiliController.java @@ -0,0 +1,29 @@ +package com.yutou.qqbot.Controllers; + +import com.alibaba.fastjson2.JSONObject; +import com.yutou.qqbot.models.BiliBili.BiliVideo; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class BiliBiliController { + @RequestMapping("/bilibili/down.do") + @ResponseBody + public JSONObject downloadBili(String data) { + new Thread(() -> { + JSONObject json = JSONObject.parseObject(data); + System.out.println("json = " + json); + String url = json.getString("url"); + boolean downDanmu = json.containsKey("danmu") && "on".equals(json.getString("danmu")); + boolean merge = json.containsKey("merge") && "on".equals(json.getString("merge")); + BiliVideo video = new BiliVideo(); + video.downVideo(url, downDanmu, merge); + } + ).start(); + JSONObject json = new JSONObject(); + json.put("msg", "ok"); + json.put("code", 0); + return json; + } +} diff --git a/src/main/java/com/yutou/qqbot/models/BiliBili/BiliVideo.java b/src/main/java/com/yutou/qqbot/models/BiliBili/BiliVideo.java index 7394465..e23313b 100644 --- a/src/main/java/com/yutou/qqbot/models/BiliBili/BiliVideo.java +++ b/src/main/java/com/yutou/qqbot/models/BiliBili/BiliVideo.java @@ -1,16 +1,9 @@ package com.yutou.qqbot.models.BiliBili; -import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.TextFormat; -import com.google.protobuf.UnknownFieldSet; -import com.google.protobuf.util.JsonFormat; import com.yutou.qqbot.Annotations.UseModel; import com.yutou.qqbot.bilibili.*; -import com.yutou.qqbot.interfaces.DownloadInterface; import com.yutou.qqbot.interfaces.ObjectInterface; import com.yutou.qqbot.models.Model; import com.yutou.qqbot.utlis.AppTools; @@ -18,22 +11,18 @@ import com.yutou.qqbot.utlis.ConfigTools; import com.yutou.qqbot.utlis.HttpTools; import com.yutou.qqbot.utlis.StringUtils; -import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileWriter; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URLDecoder; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.zip.Inflater; + @UseModel public class BiliVideo extends Model { public String downloadPath = "tmp"; + List danmuDatas = new ArrayList<>(); + long danmuNextTime = 0; @Override public boolean isUserPublic() { @@ -50,7 +39,11 @@ public class BiliVideo extends Model { return "B站视频下载"; } - private void downVideo(String url) { + public void downVideo(String url) { + downVideo(url, true, false); + } + + public void downVideo(String url, boolean downDanmu, boolean merge) { if (!new BiliLogin().testLogin()) { System.err.println("未登录"); return; @@ -58,6 +51,7 @@ public class BiliVideo extends Model { if (!url.contains("?")) { url += "?"; } + danmuDatas.clear(); JSONObject info = getVideoInfo(url); if (info.getInteger("code") == 0) { JSONObject infoData = info.getJSONObject("data"); @@ -96,6 +90,8 @@ public class BiliVideo extends Model { eps.put("cid", infoData.getLong("cid")); } JSONObject json = new JSONObject(); + json.put("danmu", downDanmu); + json.put("merge", merge); json.put("avid", infoData.getLong("aid")); if (eps.containsKey("cid")) { json.put("cid", eps.getLong("cid")); @@ -104,6 +100,11 @@ public class BiliVideo extends Model { json.put("fourk", 1); downVideo(json, eps); } else { + System.out.println("json = " + json); + System.out.println("eps = " + eps); + List list = new ArrayList<>(); + + String root = new File("tmp").getAbsolutePath() + File.separator; for (Object o : eps.getJSONArray("eps")) { JSONObject item = (JSONObject) o; json.put("avid", item.getLong("aid")); @@ -112,17 +113,86 @@ public class BiliVideo extends Model { json.put("fnval", 80); json.put("fourk", 1); item.put("title", eps.getString("title") + "$(File.separator)" + item.getString("title")); + list.add(new File(root + StringUtils.toSaveFileName(item.getString("title") + ".mp4"))); downVideo(json, item); + if (downDanmu && merge) { + long tmp = 0; + for (VideoDanMu.DanmakuElem elem : buildDanmuHttp(json.getLong("cid"), json.getLong("avid"), 1)) { + DanmuData danmuData = new DanmuData(); + danmuData.setDanmu(elem.getContent()); + danmuData.setFontSize(elem.getFontsize()); + danmuData.setTime(elem.getProgress() + danmuNextTime); + danmuData.setFontColor(elem.getColor()); + danmuData.setModel(elem.getMode()); + if (elem.getProgress() > tmp) { + tmp = elem.getProgress(); + } + danmuDatas.add(danmuData); + } + danmuNextTime = tmp; + } + } + if (merge) { + merge(root, StringUtils.toSaveFileName(eps.getString("title")), list); } } } } + private void merge(String root, String name, List files) { + String saveName = root + name; + File fileList = new File(saveName + File.separator + "tmp.txt"); + System.out.println("fileList.getAbsolutePath() = " + fileList.getAbsolutePath()); + StringBuilder builder = new StringBuilder(); + int i = 0; + List tmp = new ArrayList<>(); + for (File file : files) { + System.out.println("file.getName() = " + file.getName()); + file.renameTo(new File(file.getParentFile(), i + ".mp4")); + tmp.add(new File(file.getParentFile(), i + ".mp4")); + builder.append("file '").append(i++).append(".mp4'"); + builder.append("\n"); + } + try { + // boolean b = fileList.createNewFile(); + // System.out.println("b = " + b); + FileWriter fw = new FileWriter(fileList); + fw.write(builder.toString()); + fw.flush(); + fw.close(); + + String exec = String.format("cd \"%s\" && ffmpeg -f concat -i \"%s\" -c copy %s.mp4", saveName, "tmp.txt", name); + System.out.println("exec = " + exec); + AppTools.exec(exec, new ObjectInterface() { + @Override + public void out(String data) { + super.out(data); + // System.out.println(data); + System.out.println("over"); + fileList.delete(); + for (File file : tmp) { + file.delete(); + } + AssTools tools = new AssTools(name); + tools.addDanmu(danmuDatas); + boolean saveDanmu = tools.saveDanmu(saveName); + System.out.println("弹幕保存:" + saveDanmu); + } + }, false, false); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + private void downVideo(JSONObject json, JSONObject eps) { eps.put("title", StringUtils.toSaveFileName(eps.getString("title"))); File tmp = new File(HttpTools.downloadPath + eps.getString("title") + ".mp4"); - downDanmu(json.getLong("cid"), json.getLong("avid"), eps.getString("title"), 1); + if (json.getBooleanValue("danmu") && !json.getBooleanValue("merge")) { + List elems = buildDanmuHttp(json.getLong("cid"), json.getLong("avid"), 1); + downDanmu("tmp", eps.getString("title"), elems); + } if (tmp.exists()) { return; } @@ -148,19 +218,8 @@ public class BiliVideo extends Model { } } - private void downDanmu(long cid, long avid, String title, int segment_index) { - System.out.println("cid = " + cid + ", avid = " + avid + ", title = " + title + ", segment_index = " + segment_index); - JSONObject json = new JSONObject(); - json.put("type", 1); - json.put("oid", cid); - json.put("avid", avid); - json.put("segment_index", segment_index); + private void downDanmu(String savePath, String title, List danmuList) { try { - List tmp, danmuList = new ArrayList<>(); - while (!(tmp = getDanmu(json)).isEmpty()) { - danmuList.addAll(tmp); - json.put("segment_index",++segment_index); - } AssTools tools = new AssTools(title); List list = new ArrayList<>(); for (VideoDanMu.DanmakuElem elem : danmuList) { @@ -173,13 +232,27 @@ public class BiliVideo extends Model { list.add(danmuData); } tools.addDanmu(list); - tools.saveDanmu("tmp"); - + boolean saveDanmu = tools.saveDanmu(savePath); + System.out.println("弹幕保存:" + saveDanmu); } catch (Exception e) { e.printStackTrace(); } } + private List buildDanmuHttp(long cid, long avid, int segment_index) { + List tmp, danmuList = new ArrayList<>(); + JSONObject json = new JSONObject(); + json.put("type", 1); + json.put("oid", cid); + json.put("avid", avid); + json.put("segment_index", segment_index); + while (!(tmp = getDanmu(json)).isEmpty()) { + danmuList.addAll(tmp); + json.put("segment_index", ++segment_index); + } + return danmuList; + } + private List getDanmu(JSONObject json) { try { byte[] http = BiliBiliUtils.http("https://api.bilibili.com/x/v2/dm/web/seg.so?" + HttpTools.toUrlParams(json), BiliBiliUtils.HTTP.GET, null, BiliBiliUtils.RET_MODEL.BYTE); @@ -217,7 +290,6 @@ public class BiliVideo extends Model { @Override public void out(String data) { super.out(data); - System.out.println("data = " + data); videoFile.delete(); audioFile.delete(); } @@ -265,6 +337,8 @@ public class BiliVideo extends Model { public static void main(String[] args) { BiliVideo video = new BiliVideo(); + JSONObject login = new BiliLogin().login(); + System.out.println(login); //岚少 480 //video.downVideo("https://www.bilibili.com/video/BV1Ps411m7pt?spm_id_from=333.999.0.0"); //唐诱 合集 @@ -279,12 +353,14 @@ public class BiliVideo extends Model { //video.downVideo("https://www.bilibili.com/video/BV1qF411T7Vf?spm_id_from=444.41.list.card_archive.click"); //唐诱正片 //video.downVideo("https://www.bilibili.com/video/BV1L44y147zR?spm_id_from=333.999.0.0");// ep1 - //video.downVideo("https://www.bilibili.com/video/BV18L4y1H7rz?spm_id_from=333.999.0.0");// ep5 + video.downVideo("https://www.bilibili.com/video/BV18L4y1H7rz?spm_id_from=333.999.0.0", true, false);// ep5 // video.downVideo("https://www.bilibili.com/video/BV1SL411g7FS/?spm_id_from=333.788.recommend_more_video.0"); //all ig 1\5 // video.downVideo("https://www.bilibili.com/video/BV18L4y1H7rz?spm_id_from=333.999.0.0"); + // video.downVideo("https://www.bilibili.com/video/BV1Pe4y1Q7MX?spm_id_from=444.41.top_right_bar_window_history.content.click"); // int a=16|2048; // System.out.println("a = " + a); //video.downDanmu(428855000L,976216102L,"【都市_情感】《唐可可的诱惑》第一集",1); + System.out.println("事件结束"); } } diff --git a/src/main/java/com/yutou/qqbot/utlis/AppTools.java b/src/main/java/com/yutou/qqbot/utlis/AppTools.java index 9bb9379..0231257 100644 --- a/src/main/java/com/yutou/qqbot/utlis/AppTools.java +++ b/src/main/java/com/yutou/qqbot/utlis/AppTools.java @@ -51,7 +51,7 @@ public class AppTools { printWriter.close(); return writer.toString(); } - public static void exec(String exec, ObjectInterface objectInterface, boolean isOutQQBot, boolean isInput) { + public static String exec(String exec, ObjectInterface objectInterface, boolean isOutQQBot, boolean isInput) { try { Process process; if (AppTools.isRuntimeSystemOfWindow()) { @@ -69,17 +69,20 @@ public class AppTools { } ); } + String ret; if (isInput) { - processOut(process.getInputStream(), objectInterface, isOutQQBot); + ret=processOut(process.getInputStream(), objectInterface, isOutQQBot); processOut(process.getErrorStream(),null,isOutQQBot); } else { - processOut(process.getErrorStream(), objectInterface, isOutQQBot); + ret=processOut(process.getErrorStream(), objectInterface, isOutQQBot); processOut(process.getInputStream(),null,isOutQQBot); } process.destroy(); + return ret; } catch (Exception e) { e.printStackTrace(); } + return ""; } public static boolean isRuntimeSystemOfWindow() { @@ -121,7 +124,7 @@ public class AppTools { public static void processOut(InputStream inputStream) { processOut(inputStream,null,true); } - public static void processOut(InputStream inputStream, ObjectInterface objectInterface, boolean isOutQQBot){ + public static String processOut(InputStream inputStream, ObjectInterface objectInterface, boolean isOutQQBot){ String tmp; StringBuilder str = new StringBuilder(); try { @@ -141,6 +144,7 @@ public class AppTools { if(isOutQQBot) { QQBotManager.getInstance().sendMessage(str.toString()); } + return str.toString(); } public static void sendServer(String title, String msg) { try { diff --git a/web/bilibili.html b/web/bilibili.html new file mode 100644 index 0000000..3321990 --- /dev/null +++ b/web/bilibili.html @@ -0,0 +1,81 @@ + + + + + + BiliBili下载器 + + + + + + + + +
+
BiliBili下载器 +
+ +


+ +
+ +
+
+ +
+ +
+
+
+ +
+ + +
+
+
+
+ + +
+
+
+ +
+
+ + + + + + + + \ No newline at end of file -- 2.43.0 From 6857a1d5ea533410580ead790daed0934fc28276 Mon Sep 17 00:00:00 2001 From: Yutousama <583819556@qq.com> Date: Mon, 15 Aug 2022 02:29:36 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:#6=20=E7=89=88=E6=9C=AC=E5=8F=B7?= =?UTF-8?q?=E6=9C=AA=E6=8F=90=E4=BA=A4=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/yutou/qqbot/QQBotApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/yutou/qqbot/QQBotApplication.java b/src/main/java/com/yutou/qqbot/QQBotApplication.java index 7b87786..828fa5d 100644 --- a/src/main/java/com/yutou/qqbot/QQBotApplication.java +++ b/src/main/java/com/yutou/qqbot/QQBotApplication.java @@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class QQBotApplication { - public static final String version="QQBot v.1.3.4"; + public static final String version="QQBot v.1.3.5"; public static void main(String[] args) { System.out.println("version = " + version); SpringApplication.run(QQBotApplication.class, args); -- 2.43.0