斗鱼录播初步完成

This commit is contained in:
suifeng
2023-08-04 11:47:59 +08:00
parent 7d8f566804
commit 4d4a4a6727
43 changed files with 877 additions and 296 deletions

View File

@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />

View File

@@ -1,9 +0,0 @@
<component name="libraryTable">
<library name="Msc">
<CLASSES>
<root url="jar://$PROJECT_DIR$/BarrageModule/lib/Msc.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@@ -3,6 +3,7 @@
<CLASSES>
<root url="jar://$PROJECT_DIR$/BarrageModule/lib/json-jena-1.0.jar!/" />
<root url="jar://$PROJECT_DIR$/BarrageModule/lib/Msc.jar!/" />
<root url="file://F:/MavenWork/repository/org/seleniumhq/selenium" />
</CLASSES>
<JAVADOC />
<SOURCES />

2
.idea/misc.xml generated
View File

@@ -19,7 +19,7 @@
</set>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="ProjectType">

View File

@@ -24,5 +24,10 @@
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -51,5 +51,10 @@
<version>0.11.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -69,6 +69,11 @@
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>

View File

@@ -1,21 +1,21 @@
package org.example;
import org.example.exception.FileCacheException;
import org.example.pojo.configfile.BarrageSaveFile;
import org.example.pojo.download.LoadBarrageConfig;
import org.junit.jupiter.api.Test;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* @author Genius
* @date 2023/05/06 04:07
**/
public class BarrageSaveFileAutoCreateTest {
@Test
public void test() throws FileCacheException {
LoadBarrageConfig loadBarrageConfig = new LoadBarrageConfig("斗鱼","Post","大司马");
BarrageSaveFile barrageSaveFile = new BarrageSaveFile(loadBarrageConfig,new ConcurrentLinkedQueue<>());
}
}
//package org.example;
//
//import org.example.exception.FileCacheException;
//import org.example.pojo.configfile.BarrageSaveFile;
//import org.example.pojo.download.LoadBarrageConfig;
//import org.junit.jupiter.api.Test;
//
//import java.util.concurrent.ConcurrentLinkedQueue;
//
///**
// * @author Genius
// * @date 2023/05/06 04:07
// **/
//public class BarrageSaveFileAutoCreateTest {
//
// @Test
// public void test() throws FileCacheException {
// LoadBarrageConfig loadBarrageConfig = new LoadBarrageConfig("斗鱼","Post","大司马");
// BarrageSaveFile barrageSaveFile = new BarrageSaveFile(loadBarrageConfig,new ConcurrentLinkedQueue<>());
// }
//}

View File

@@ -51,5 +51,10 @@
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,123 +1,123 @@
package org.example.cache;
import org.example.constpool.GlobalFileCache;
import org.example.pojo.Student;
import org.example.pojo.configfile.ChopperBotConfigFile;
import org.example.exception.FileCacheException;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* @author Genius
* @date 2023/04/24 03:30
**/
public class FileCacheTest {
static FileCache cache;
static{
try {
cache = new FileCache<>(
new CommonConfigFile(
"E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\",
"test.json",
new ConcurrentLinkedQueue<Student>()
)
);
FileCacheManagerInstance.getInstance().addFileCache(cache);
} catch (FileCacheException e) {
throw new RuntimeException(e);
}
}
@Test
public void TestFileCache() throws FileCacheException, InterruptedException {
ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
FileCache fileCache = new FileCache(chopperBotConfigFile);
FileCacheManager manager = new FileCacheManager(List.of(fileCache));
manager.start();
Thread.sleep(500000);
}
@Test
public void TestFileCacheManager() throws FileCacheException, InterruptedException {
ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
FileCache fileCache = new FileCache(chopperBotConfigFile);
FileCacheManager manager = new FileCacheManager(List.of(fileCache));
manager.start();
Thread.sleep(500000);
}
@Test
public void TestGet() throws FileCacheException, InterruptedException {
ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
FileCache fileCache = new FileCache(chopperBotConfigFile);
FileCacheManager manager = new FileCacheManager(List.of(fileCache));
manager.start();
fileCache.append(1,"barrage","src");
}
@Test
public void TestAppend() throws FileCacheException, InterruptedException {
FileCacheManagerInstance.getInstance().start();
//追加数组的某个元素
for(int i=0;i<10;i++){
GlobalFileCache.ModuleSrcConfigFile.append(i,"sectionwork","src","0");
}
//追加数组
for(int i=0;i<10;i++){
GlobalFileCache.ModuleSrcConfigFile.append(i,"sectionwork","src","-1");
}
//追加类中的元素
for(int i=0;i<10;i++){
GlobalFileCache.ModuleSrcConfigFile.append(i,"barrage","src");
}
Thread.sleep(500000);
}
@Test
public void TestWrite() throws FileCacheException,InterruptedException{
FileCacheManagerInstance.getInstance().start();
//更改数组元素
for(int i=0;i<10;i++){
GlobalFileCache.ModuleSrcConfigFile.writeKeys(i,"sectionwork","src","0");
}
//追加数组
for(int i=0;i<10;i++){
GlobalFileCache.ModuleSrcConfigFile.writeKeys(i,"sectionwork","src","-1");
}
//更改类中的元素
for(int i=0;i<10;i++){
GlobalFileCache.ModuleSrcConfigFile.writeKeys(i,"barrage","src");
}
Thread.sleep(500000);
}
@Test
public void TestArrayAdd() throws InterruptedException, FileCacheException {
ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
FileCache fileCache = new FileCache(chopperBotConfigFile);
FileCacheManager manager = new FileCacheManager(List.of(fileCache));
manager.start();
}
@Test
public void TestAddCache() throws FileCacheException, InterruptedException {
FileCacheManagerInstance.getInstance().start();
for(int i=0;i<10;i++){
Student student = new Student(Integer.toString(i),i,"jsu"+i,"major"+i,null,null);
cache.writeKeys(student,"-1");
}
Thread.sleep(500000);
}
}
//package org.example.cache;
//
//import org.example.constpool.GlobalFileCache;
//import org.example.pojo.Student;
//import org.example.pojo.configfile.ChopperBotConfigFile;
//import org.example.exception.FileCacheException;
//import org.junit.jupiter.api.Test;
//
//import java.util.List;
//import java.util.concurrent.ConcurrentLinkedQueue;
//
///**
// * @author Genius
// * @date 2023/04/24 03:30
// **/
//
//public class FileCacheTest {
// static FileCache cache;
//
// static{
//
// try {
// cache = new FileCache<>(
// new CommonConfigFile(
// "E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\",
// "test.json",
// new ConcurrentLinkedQueue<Student>()
// )
// );
// FileCacheManagerInstance.getInstance().addFileCache(cache);
// } catch (FileCacheException e) {
// throw new RuntimeException(e);
// }
// }
//
// @Test
// public void TestFileCache() throws FileCacheException, InterruptedException {
// ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
// FileCache fileCache = new FileCache(chopperBotConfigFile);
//
// FileCacheManager manager = new FileCacheManager(List.of(fileCache));
// manager.start();
// Thread.sleep(500000);
// }
//
// @Test
// public void TestFileCacheManager() throws FileCacheException, InterruptedException {
// ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
// FileCache fileCache = new FileCache(chopperBotConfigFile);
// FileCacheManager manager = new FileCacheManager(List.of(fileCache));
// manager.start();
// Thread.sleep(500000);
// }
//
// @Test
// public void TestGet() throws FileCacheException, InterruptedException {
// ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
// FileCache fileCache = new FileCache(chopperBotConfigFile);
//
// FileCacheManager manager = new FileCacheManager(List.of(fileCache));
// manager.start();
//
// fileCache.append(1,"barrage","src");
// }
//
// @Test
// public void TestAppend() throws FileCacheException, InterruptedException {
// FileCacheManagerInstance.getInstance().start();
// //追加数组的某个元素
// for(int i=0;i<10;i++){
// GlobalFileCache.ModuleSrcConfigFile.append(i,"sectionwork","src","0");
// }
// //追加数组
// for(int i=0;i<10;i++){
// GlobalFileCache.ModuleSrcConfigFile.append(i,"sectionwork","src","-1");
// }
// //追加类中的元素
// for(int i=0;i<10;i++){
// GlobalFileCache.ModuleSrcConfigFile.append(i,"barrage","src");
// }
// Thread.sleep(500000);
// }
//
// @Test
// public void TestWrite() throws FileCacheException,InterruptedException{
// FileCacheManagerInstance.getInstance().start();
// //更改数组元素
// for(int i=0;i<10;i++){
// GlobalFileCache.ModuleSrcConfigFile.writeKeys(i,"sectionwork","src","0");
// }
// //追加数组
// for(int i=0;i<10;i++){
// GlobalFileCache.ModuleSrcConfigFile.writeKeys(i,"sectionwork","src","-1");
// }
// //更改类中的元素
// for(int i=0;i<10;i++){
// GlobalFileCache.ModuleSrcConfigFile.writeKeys(i,"barrage","src");
// }
// Thread.sleep(500000);
// }
//
// @Test
// public void TestArrayAdd() throws InterruptedException, FileCacheException {
// ChopperBotConfigFile chopperBotConfigFile = new ChopperBotConfigFile();
// FileCache fileCache = new FileCache(chopperBotConfigFile);
//
// FileCacheManager manager = new FileCacheManager(List.of(fileCache));
// manager.start();
//
// }
//
// @Test
// public void TestAddCache() throws FileCacheException, InterruptedException {
// FileCacheManagerInstance.getInstance().start();
//
// for(int i=0;i<10;i++){
// Student student = new Student(Integer.toString(i),i,"jsu"+i,"major"+i,null,null);
// cache.writeKeys(student,"-1");
// }
// Thread.sleep(500000);
// }
//
//}

View File

@@ -1,24 +1,24 @@
package org.example.util;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* @author Genius
* @date 2023/04/20 14:15
**/
public class FileUtilTest {
@Test
public void testDelete() throws IOException {
FileUtil.deleteDirectory("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\trash");
}
@Test
public void testCreate() throws IOException {
Files.createDirectories(Paths.get("./Hello"));
}
}
//package org.example.util;
//
//import org.junit.jupiter.api.Test;
//
//import java.io.IOException;
//import java.nio.file.Files;
//import java.nio.file.Paths;
//
///**
// * @author Genius
// * @date 2023/04/20 14:15
// **/
//public class FileUtilTest {
//
// @Test
// public void testDelete() throws IOException {
// FileUtil.deleteDirectory("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\trash");
// }
//
// @Test
// public void testCreate() throws IOException {
// Files.createDirectories(Paths.get("./Hello"));
// }
//}

View File

@@ -1,82 +1,82 @@
package org.example.util;
import org.example.pojo.Student;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
/**
* @author Genius
* @date 2023/04/20 11:43
**/
public class JsonFileUtilTest {
@Test
public void writeMapObj() throws IOException {
Student student = new Student(
"Genius",
18,
"HUST",
"CS",
List.of("Coding", "Reading", "Playing"),
Map.of("QQ", "123456789", "WeChat", "987654321")
);
JsonFileUtil.writeJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json",
Map.of("Student", student,"hello","11234"));
Map<String, Object> stringObjectMap = JsonFileUtil.readJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json");
stringObjectMap.forEach(
(k,v)->{
System.out.println(k);
System.out.println(v.getClass());
}
);
}
@Test
public void writeClassInJsonFile() {
Student student = new Student(
"Genius",
18,
"HUST",
"CS",
List.of("Coding", "Reading", "Playing"),
Map.of("QQ", "123456789", "WeChat", "987654321")
);
JsonFileUtil.writeJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "student.json", student);
JsonFileUtil.writeBigJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json", List.of(student));
JsonFileUtil.writeJsonFileIsExist("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student3.json", student);
System.out.println(JsonFileUtil.readJsonFileToObject("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student.json", Student.class));
System.out.println(JsonFileUtil.readJsonFileToObject("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json",List.class));
}
@Test
public void readJsonFile() {
Map maps = JsonFileUtil.readJsonFile("../config/", "moduleConfig.json");
Object test = maps.get("module");
System.out.println(test);
System.out.println(maps);
}
@Test
public void writeJsonFile() {
Map maps = JsonFileUtil.readJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "test.json");
JsonFileUtil.writeJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "test2.json", maps);
JsonFileUtil.writeJsonFileIsExist("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\test2.json", maps);
}
@Test
public void writeJsonFileByJsonWriter() throws IOException {
Map maps = JsonFileUtil.readJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "test.json");
Path dir = Paths.get("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\test2.json");
JsonFileUtil.writeBigJsonFile(dir.toString(),maps);
}
}
//package org.example.util;
//
//import org.example.pojo.Student;
//import org.junit.jupiter.api.Test;
//
//import java.io.IOException;
//import java.nio.file.Path;
//import java.nio.file.Paths;
//import java.util.List;
//import java.util.Map;
//
///**
// * @author Genius
// * @date 2023/04/20 11:43
// **/
//
//public class JsonFileUtilTest {
//
// @Test
// public void writeMapObj() throws IOException {
// Student student = new Student(
// "Genius",
// 18,
// "HUST",
// "CS",
// List.of("Coding", "Reading", "Playing"),
// Map.of("QQ", "123456789", "WeChat", "987654321")
// );
// JsonFileUtil.writeJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json",
// Map.of("Student", student,"hello","11234"));
// Map<String, Object> stringObjectMap = JsonFileUtil.readJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json");
// stringObjectMap.forEach(
// (k,v)->{
// System.out.println(k);
// System.out.println(v.getClass());
// }
// );
// }
//
//
// @Test
// public void writeClassInJsonFile() {
// Student student = new Student(
// "Genius",
// 18,
// "HUST",
// "CS",
// List.of("Coding", "Reading", "Playing"),
// Map.of("QQ", "123456789", "WeChat", "987654321")
// );
// JsonFileUtil.writeJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "student.json", student);
// JsonFileUtil.writeBigJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json", List.of(student));
// JsonFileUtil.writeJsonFileIsExist("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student3.json", student);
//
// System.out.println(JsonFileUtil.readJsonFileToObject("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student.json", Student.class));
// System.out.println(JsonFileUtil.readJsonFileToObject("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\student2.json",List.class));
// }
//
// @Test
// public void readJsonFile() {
// Map maps = JsonFileUtil.readJsonFile("../config/", "moduleConfig.json");
// Object test = maps.get("module");
// System.out.println(test);
// System.out.println(maps);
// }
//
// @Test
// public void writeJsonFile() {
// Map maps = JsonFileUtil.readJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "test.json");
// JsonFileUtil.writeJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "test2.json", maps);
// JsonFileUtil.writeJsonFileIsExist("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\test2.json", maps);
// }
//
// @Test
// public void writeJsonFileByJsonWriter() throws IOException {
// Map maps = JsonFileUtil.readJsonFile("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\", "test.json");
// Path dir = Paths.get("E:\\Project\\ChopperBot\\FileModule\\src\\main\\resources\\test2.json");
// JsonFileUtil.writeBigJsonFile(dir.toString(),maps);
// }
//
//
//}

View File

@@ -29,5 +29,10 @@
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -12,7 +12,7 @@ import java.util.List;
**/
@Data
@AllArgsConstructor
public class HotModuleSetting {
public class HotModuleSetting {
private String platform; //平台

Binary file not shown.

View File

@@ -58,12 +58,117 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.19</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>CreeperModule</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-api</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-devtools-v113</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-devtools-v114</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-devtools-v115</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-devtools-v85</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-edge-driver</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-ie-driver</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-safari-driver</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-support</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>com.browserup</groupId>
<artifactId>browserup-proxy-core</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>net.lightbody.bmp</groupId>
<artifactId>browsermob-core</artifactId>
<version>2.1.5</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@@ -1,14 +1,14 @@
package org.example;
import org.example.core.manager.TaskManager;
import org.example.pojo.liveConfig.BilibiliLiveConfig;
import org.example.pojo.live.BilibiliLiveConfig;
public class LiveStreamTest {
private static final int THREAD_NUM = 10;
public static void main(String[] args) {
// 创建直播配置
BilibiliLiveConfig liveConfig = new BilibiliLiveConfig("732", "F:\\");
BilibiliLiveConfig liveConfig = new BilibiliLiveConfig("732", "D:\\", "猪猪公主");
// 创建下载任务管理器
TaskManager taskManager = new TaskManager(THREAD_NUM);

View File

@@ -0,0 +1,41 @@
package org.example.api;
import org.example.core.component.M3U8Handle;
import org.example.core.component.SimpleRequest;
import org.example.core.parser.impl.DouyuM3u8UrlParser;
import org.example.pojo.live.DouyuRecordConfig;
import org.example.pojo.record.RecordList;
/**
* 斗鱼录播api
* @author 燧枫
* @date 2023/8/1 21:53
*/
public class DouyuRecordApi {
// 根据主播id首次获取录播列表(默认为第一页每页数量为20)
public static RecordList getRecordList(String upId) {
return getRecordList(upId, 1);
}
// 指定页数获取录播列表
public static RecordList getRecordList(String upId, int index) {
return SimpleRequest.getRecordList(upId, index);
}
// 根据vid获取一场录播的M3U8下载链接
public static String getM3U8ByVid(String vid) {
return new DouyuM3u8UrlParser().getUrl(new DouyuRecordConfig(vid, null, null, null,null));
}
// 根据M3U8链接,开始时间,结束时间,保存位置,文件名下载一个录播视频
public static void downloadVideoByM3U8(String url, String startTime, String endTime, String downloadLocation, String outputFileName) {
M3U8Handle.downloadAndCutVideo(url, startTime, endTime, downloadLocation, outputFileName);
}
public static void main(String[] args) {
String vid = "wLjGvLxr8yPvmO90";
String url = getM3U8ByVid(vid);
downloadVideoByM3U8(url, "00:00:00", "00:10:00", "D://", "test.mp4");
}
}

View File

@@ -0,0 +1,53 @@
package org.example.core.component;
import org.example.pool.ConstPool;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Paths;
/**
* M3U8流处理器
* @author 燧枫
* @date 2023/8/3 12:47
*/
public class M3U8Handle {
// 指定开始时间与结束时间下载某个m3u8视频
public static void downloadAndCutVideo(String url, String startTime, String endTime, String downloadLocation, String outputFileName) {
String outputFilePath = Paths.get(downloadLocation, outputFileName).toString();
handleProcess(url, startTime, endTime, outputFilePath);
}
public static void downloadAndCutVideo(String url, long startTime, long endTime, String downloadLocation, String outputFileName) {
String outputFilePath = Paths.get(downloadLocation, outputFileName).toString();
handleProcess(url, String.valueOf(startTime), String.valueOf(endTime), outputFilePath);
}
private static void handleProcess(String url, String startTime, String endTime, String outputFilePath) {
System.out.println("Starting video download and processing...");
ProcessBuilder processBuilder = new ProcessBuilder(
ConstPool.FFMEPEG_PATH,
"-i", url,
"-ss", startTime,
"-to", endTime,
"-c", "copy",
"-y",
outputFilePath
);
processBuilder.redirectErrorStream(true);
try {
Process process = processBuilder.start();
try (BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = inputReader.readLine()) != null) {
System.out.println("FFmpeg output: " + line);
}
}
int exitCode = process.waitFor();
System.out.println("Exit code: " + exitCode);
} catch (IOException | InterruptedException e) {
System.err.println("Error during video processing: " + e.getMessage());
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,73 @@
package org.example.core.component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.example.pojo.record.RecordDayEntry;
import org.example.pojo.record.RecordEntry;
import org.example.pojo.record.RecordList;
import org.example.utils.HttpClientUtil;
import java.util.ArrayList;
import java.util.List;
/**
* 简单请求
* @author 燧枫
* @date 2023/8/1 22:19
*/
public class SimpleRequest {
// 斗鱼录播列表请求url
private static String DOUYU_RECORD_LIST = "https://v.douyu.com/wgapi/vod/center/authorShowVideoList?page=%S&limit=20&up_id=%s";
// 斗鱼指定天的录播列表
private static String DOUYU_RECORD_DAY_LIST = "https://v.douyu.com/wgapi/vod/center/getShowReplayList?vid=%s&up_id=%s";
// 指定页数获取录播列表
public static RecordList getRecordList(String upId, int index) {
String url = String.format(DOUYU_RECORD_LIST, index, upId);
JSONObject data = JSON.parseObject(HttpClientUtil.get(url)).getJSONObject("data");
JSONArray recordListArray = data.getJSONArray("list");
int count = data.getInteger("count");
List<RecordDayEntry> recordDayEntryList = new ArrayList<>();
recordListArray.forEach(o -> {
// 更新每天的数据
JSONObject enter = (JSONObject) o;
RecordDayEntry recordDayEntry = new RecordDayEntry();
recordDayEntry.setTitle(enter.getString("title"));
JSONObject temp = (JSONObject) enter.getJSONArray("video_list").get(0);
recordDayEntry.setAuthor(temp.getString("author"));
String hash_id = temp.getString("hash_id");
recordDayEntry.setHashId(hash_id);
// 再更新单场的列表
List<RecordEntry> recordEntryList = new ArrayList<>();
String day_url = String.format(DOUYU_RECORD_DAY_LIST, hash_id, upId);
JSONObject day = JSON.parseObject(HttpClientUtil.get(day_url)).getJSONObject("data");
recordDayEntry.setDate(day.getString("date"));
JSONArray recordDayListArray = day.getJSONArray("list");
recordDayListArray.forEach(single -> {
JSONObject one = (JSONObject) single;
RecordEntry recordEntry = new RecordEntry();
recordEntry.setDuration(one.getString("video_duration"));
recordEntry.setViewNum(one.getInteger("view_num"));
recordEntry.setCover(one.getString("cover"));
recordEntry.setShowRemark(one.getString("show_remark"));
recordEntry.setShowId(one.getString("show_id"));
recordEntry.setAuthor(one.getString("nickname"));
recordEntry.setTitle(one.getString("title"));
recordEntry.setHashId(one.getString("hash_id"));
recordEntryList.add(recordEntry);
});
recordDayEntry.setRecordEntryList(recordEntryList);
recordDayEntryList.add(recordDayEntry);
});
RecordList recordList = new RecordList();
recordList.setRecordDayCount(count);
recordList.setRecordDayEntryList(recordDayEntryList);
return recordList;
}
}

View File

@@ -1,10 +1,10 @@
package org.example.core.factory;
import org.example.core.parser.PlatformFlvUrlParser;
import org.example.core.parser.PlatformVideoUrlParser;
import org.example.core.parser.impl.BilibiliFlvUrlParser;
import org.example.core.component.LiveStreamTask;
import org.example.pojo.liveConfig.BilibiliLiveConfig;
import org.example.pojo.liveConfig.LiveConfig;
import org.example.pojo.live.BilibiliLiveConfig;
import org.example.pojo.live.LiveConfig;
import java.util.HashMap;
import java.util.Map;
@@ -16,7 +16,7 @@ import java.util.Map;
*/
public class LiveTaskFactory {
private final Map<Class<? extends LiveConfig>, PlatformFlvUrlParser> parserMap;
private final Map<Class<? extends LiveConfig>, PlatformVideoUrlParser> parserMap;
public LiveTaskFactory() {
this.parserMap = new HashMap<>();
@@ -27,12 +27,12 @@ public class LiveTaskFactory {
// 根据LiveConfig去创建下载任务
public LiveStreamTask create(LiveConfig liveConfig) {
PlatformFlvUrlParser parser = this.parserMap.get(liveConfig.getClass());
PlatformVideoUrlParser parser = this.parserMap.get(liveConfig.getClass());
if (parser == null) {
throw new IllegalArgumentException("Unsupported live config type: " + liveConfig.getClass());
}
try {
String flvUrl = parser.getFlvUrl(liveConfig);
String flvUrl = parser.getUrl(liveConfig);
LiveStreamTask task = new LiveStreamTask();
task.setUrl(flvUrl);
// 为任务添加请求头

View File

@@ -3,7 +3,7 @@ package org.example.core.manager;
import org.example.core.component.LiveStreamTask;
import org.example.core.component.StatusMonitor;
import org.example.core.factory.LiveTaskFactory;
import org.example.pojo.liveConfig.LiveConfig;
import org.example.pojo.live.LiveConfig;
import org.example.utils.VideoConverter;
import java.io.FileNotFoundException;

View File

@@ -1,13 +0,0 @@
package org.example.core.parser;
import org.example.pojo.liveConfig.LiveConfig;
/**
* 全直播平台flv链接解析接口
* @author 燧枫
* @date 2023/5/19 17:09
*/
public interface PlatformFlvUrlParser {
String getFlvUrl(LiveConfig liveConfig) throws Exception;
}

View File

@@ -0,0 +1,13 @@
package org.example.core.parser;
import org.example.pojo.live.LiveConfig;
/**
* 全直播平台flv链接解析接口
* @author 燧枫
* @date 2023/5/19 17:09
*/
public interface PlatformVideoUrlParser {
String getUrl(LiveConfig liveConfig) throws Exception;
}

View File

@@ -1,8 +1,8 @@
package org.example.core.parser.impl;
import org.example.core.parser.PlatformFlvUrlParser;
import org.example.pojo.liveConfig.BilibiliLiveConfig;
import org.example.pojo.liveConfig.LiveConfig;
import org.example.core.parser.PlatformVideoUrlParser;
import org.example.pojo.live.BilibiliLiveConfig;
import org.example.pojo.live.LiveConfig;
import org.example.utils.HttpClientUtil;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -12,12 +12,12 @@ import org.json.JSONObject;
* @author 燧枫
* @date 2023/5/16 20:42
*/
public class BilibiliFlvUrlParser implements PlatformFlvUrlParser {
public class BilibiliFlvUrlParser implements PlatformVideoUrlParser {
String urlFormat = "https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo?room_id=%s&protocol=0,1&format=0,1,2&codec=0,1&qn=%d&platform=web&ptype=8";
// 通过房间号roomId,clarity(画质,10000为原画画质),得到flv链接
public String getFlvUrl(LiveConfig liveConfig) throws Exception {
public String getUrl(LiveConfig liveConfig) throws Exception {
BilibiliLiveConfig bilibiliLiveConfig = (BilibiliLiveConfig) liveConfig;
String roomId = bilibiliLiveConfig.getRoomId();
int clarity = bilibiliLiveConfig.getClarity();

View File

@@ -0,0 +1,76 @@
package org.example.core.parser.impl;
import org.example.core.parser.PlatformVideoUrlParser;
import org.example.pojo.live.LiveConfig;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v115.network.Network;
import org.openqa.selenium.devtools.v115.network.model.Response;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.edge.EdgeOptions;
import java.util.Optional;
import java.util.logging.Logger;
/**
* 斗鱼M3u8链接解析
* @author 燧枫
* @date 2023/8/3 21:52
*/
public class DouyuM3u8UrlParser implements PlatformVideoUrlParser {
private static String DOUYE_RECORD_M3U8 = "https://v.douyu.com/show/%s";
private static final Logger logger = Logger.getLogger(DouyuM3u8UrlParser.class.getName());
@Override
public String getUrl(LiveConfig liveConfig) {
// 设置 WebDriver 的路径
System.setProperty("webdriver.edge.driver", "E:\\edgDriver\\msedgedriver.exe");
// 创建 EdgeOptions 实例
EdgeOptions edgeOptions = new EdgeOptions();
// 设置为无头模式
edgeOptions.addArguments("--headless");
// 创建 WebDriver
EdgeDriver driver = new EdgeDriver(edgeOptions);
// 创建 DevTools 并建立会话
DevTools devTools = driver.getDevTools();
devTools.createSession();
// 启用 Network
devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
// 创建一个数组来存储获取到的视频链接
final String[] videoUrl = new String[1];
// 添加监听器,监听 HTTP 响应
devTools.addListener(Network.responseReceived(), response -> {
Response responseReceived = response.getResponse();
String url = responseReceived.getUrl();
if (url.contains("https://play-tx-recpub.douyucdn2.cn/live/") && url.contains("m3u8")) {
videoUrl[0] = url;
}
});
// 打开网页
driver.get(String.format(DOUYE_RECORD_M3U8, liveConfig.getRoomId()));
logger.info("成功打开网页");
// 添加延迟以便获取链接
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 关闭浏览器和驱动
driver.quit();
logger.info("获取到视频链接: " + videoUrl[0]);
return videoUrl[0];
}
}

View File

@@ -1,4 +1,4 @@
package org.example.pojo.liveConfig;
package org.example.pojo.live;
import lombok.Data;
@@ -13,13 +13,13 @@ public class BilibiliLiveConfig extends LiveConfig {
// 清晰度,10000为原画画质
private int clarity;
public BilibiliLiveConfig(String roomId, int clarity, String videoPath, boolean convertToMp4) {
super(roomId, videoPath, convertToMp4);
public BilibiliLiveConfig(String roomId, int clarity, String videoPath, String videoName, boolean convertToMp4) {
super(roomId, videoPath, videoName, convertToMp4);
this.clarity = clarity;
}
public BilibiliLiveConfig(String roomId, String videoPath) {
super(roomId, videoPath, true);
public BilibiliLiveConfig(String roomId, String videoPath, String videoName) {
super(roomId, videoPath, videoName, true);
this.clarity = 10000;
}
}

View File

@@ -0,0 +1,22 @@
package org.example.pojo.live;
import lombok.Data;
/**
*
* @author 燧枫
* @date 2023/8/3 22:23
*/
@Data
public class DouyuRecordConfig extends LiveConfig {
private String startTime;
private String endTime;
public DouyuRecordConfig(String roomId, String videoPath, String videoName, String startTime, String endTime) {
super(roomId, videoPath, videoName, false);
this.startTime = startTime;
this.endTime = endTime;
}
}

View File

@@ -1,4 +1,4 @@
package org.example.pojo.liveConfig;
package org.example.pojo.live;
import lombok.Data;
@@ -16,12 +16,16 @@ public class LiveConfig {
// 视频保存路径
private String videoPath;
// 视频保存名称
private String videoName;
// 是否自动转换为mp4格式
private boolean convertToMp4;
public LiveConfig(String roomId, String videoPath, boolean convertToMp4) {
public LiveConfig(String roomId, String videoPath, String videoName, boolean convertToMp4) {
this.roomId = roomId;
this.videoPath = videoPath;
this.videoName = videoName;
this.convertToMp4 = convertToMp4;
}
}

View File

@@ -0,0 +1,29 @@
package org.example.pojo.record;
import lombok.Data;
import java.util.List;
/**
* 单天录播
* @author 燧枫
* @date 2023/8/1 22:09
*/
@Data
public class RecordDayEntry {
// 主播名
private String author;
// 录播的hashId
private String hashId;
// 录播的标题
private String title;
// 录播的日期时间
private String date;
// 当天的列表
private List<RecordEntry> recordEntryList;
}

View File

@@ -0,0 +1,36 @@
package org.example.pojo.record;
import lombok.Data;
/**
* 单场录播
* @author 燧枫
* @date 2023/8/2 12:47
*/
@Data
public class RecordEntry {
// 主播名
private String author;
// 录播的hashId
private String hashId;
// show_id
private String showId;
// 标题
private String title;
// 场次
private String showRemark;
// 时长
private String duration;
// 封面
private String cover;
// 观看人次
private int viewNum;
}

View File

@@ -0,0 +1,20 @@
package org.example.pojo.record;
import lombok.Data;
import java.util.List;
/**
* 录播列表
* @author 燧枫
* @date 2023/8/1 21:59
*/
@Data
public class RecordList {
// 主播录播总天数
private int recordDayCount = 0;
// 录播列表
private List<RecordDayEntry> recordDayEntryList;
}

View File

@@ -0,0 +1,11 @@
package org.example.pool;
/**
* 常量池
* @author 燧枫
* @date 2023/8/3 14:03
*/
public class ConstPool {
public static String FFMEPEG_PATH = "D:\\test\\ffmpeg.exe";
}

View File

@@ -0,0 +1,25 @@
package org.example.utils;
import java.util.Random;
/**
*
* @author 燧枫
* @date 2023/8/3 21:33
*/
public class DriverUtil {
static Random random = new Random();
// 随机暂停一段时间
public static void randomSleep(int minTimeInSeconds, int maxTimeInSeconds) {
try {
int sleepTimeInMillis = (minTimeInSeconds + random.nextInt(maxTimeInSeconds - minTimeInSeconds + 1)) * 1000;
Thread.sleep(sleepTimeInMillis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,31 @@
package org.example.utils;
import java.time.Duration;
import java.util.regex.Pattern;
/**
* 格式工具类
* @author 燧枫
* @date 2023/8/3 12:51
*/
public class FromatUtil {
private static final Pattern TIME_PATTERN = Pattern.compile("^\\d{2}:\\d{2}:\\d{2}$");
// 00:25:44->154401:45:24->6324
public static long convertToSeconds(String timeString) {
if (TIME_PATTERN.matcher(timeString).matches()) {
String[] parts = timeString.split(":");
long hours = Long.parseLong(parts[0]);
long minutes = Long.parseLong(parts[1]);
long seconds = Long.parseLong(parts[2]);
return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds).getSeconds();
} else {
try {
return Long.parseLong(timeString);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid time format: " + timeString);
}
}
}
}

View File

@@ -1,5 +1,7 @@
package org.example.utils;
import org.example.pool.ConstPool;
import java.io.IOException;
/**
@@ -10,7 +12,7 @@ import java.io.IOException;
public class VideoConverter {
public static void convertFlvToMp4(String inputPath, String outputPath) {
ProcessBuilder processBuilder = new ProcessBuilder("ffmpeg", "-i", inputPath, "-codec", "copy", outputPath);
ProcessBuilder processBuilder = new ProcessBuilder(ConstPool.FFMEPEG_PATH, "-i", inputPath, "-codec", "copy", outputPath);
try {
Process process = processBuilder.start();
process.waitFor();

View File

@@ -24,5 +24,10 @@
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -108,5 +108,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -24,5 +24,10 @@
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -24,5 +24,10 @@
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -20,6 +20,7 @@ public class ConstPool {
public static final String SECTION_WORK = "SectionWork";
public static final String HOT = "Hot";
public static final String PUBLISH = "Publish";
public static final String LIVE_RECORD = "liveRecord";
/**其他**/
public static final String NULL_TIME = "nil";

View File

@@ -53,6 +53,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -59,5 +59,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.akamai.edgegrid</groupId>
<artifactId>edgegrid-signer-core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
</project>