添加视频下载和 m3u8 文件获取功能
- 新增 m3u8 文件获取和 ts 文件下载功能 - 添加视频控制器,实现视频列表、详情和 m3u8 文件获取接口 - 优化应用配置,增加开发环境配置 - 重构 HTTP 请求组件,支持文件下载 - 新增 JSON 结果封装类,统一接口返回格式
This commit is contained in:
parent
789135eea8
commit
fdd2dd700b
@ -0,0 +1,65 @@
|
||||
package top.yuchat.crawler.video.models.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import top.yuchat.crawler.video.models.entity.ClassifyInfo;
|
||||
import top.yuchat.crawler.video.models.entity.MadouVideoInfo;
|
||||
import top.yuchat.crawler.video.models.service.ClassifyInfoService;
|
||||
import top.yuchat.crawler.video.models.service.MadouVideoService;
|
||||
import top.yuchat.crawler.video.utils.JsonResult;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/video")
|
||||
@RequiredArgsConstructor
|
||||
public class VideoController {
|
||||
|
||||
private final ClassifyInfoService classifyInfoService;
|
||||
private final MadouVideoService madouVideoService;
|
||||
|
||||
@GetMapping("/classify")
|
||||
public JsonResult<List<ClassifyInfo>> getClassifyInfo() {
|
||||
return JsonResult.ok(classifyInfoService.list());
|
||||
}
|
||||
|
||||
@GetMapping("/madou")
|
||||
public JsonResult<IPage<MadouVideoInfo>> getMadouVideo(
|
||||
@RequestParam(defaultValue = "1", required = false) Integer page,
|
||||
@RequestParam(defaultValue = "20", required = false) Integer size,
|
||||
@RequestParam(required = false) String classify,
|
||||
@RequestParam(required = false) String title) {
|
||||
return JsonResult.ok(madouVideoService.pageList(page, size, classify, title));
|
||||
}
|
||||
|
||||
@GetMapping("/madou/{id}")
|
||||
public JsonResult<MadouVideoInfo> getMadouVideoById(@PathVariable Long id) {
|
||||
MadouVideoInfo madouVideoInfo = madouVideoService.getById(id);
|
||||
madouVideoInfo.setM3u8Url("/video/" + id + "/index.m3u8");
|
||||
return JsonResult.ok(madouVideoInfo);
|
||||
}
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/{id}/index.m3u8")
|
||||
public String getM3u8(@PathVariable Long id) throws IOException {
|
||||
return madouVideoService.getM3u8(id);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/{id}/{ts}")
|
||||
public void getM3u8(@PathVariable Long id, @PathVariable String ts) throws IOException {
|
||||
madouVideoService.downloadTs(id, ts);
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -61,6 +62,7 @@ public class MadouVideoService extends ServiceImpl<MadouVideoMapper, MadouVideoI
|
||||
|
||||
private final ClassifyInfoService classifyInfoService;
|
||||
private final HttpRequestComponent httpRequestComponent;
|
||||
private final HttpServletResponse httpServletResponse;
|
||||
|
||||
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(72);
|
||||
|
||||
@ -221,4 +223,41 @@ public class MadouVideoService extends ServiceImpl<MadouVideoMapper, MadouVideoI
|
||||
|
||||
return this.page(new Page<>(page, size), queryWrapper);
|
||||
}
|
||||
|
||||
public String getM3u8(Long id) throws IOException {
|
||||
// https://video.yuchat.top/m3u8/{id}/index.m3u8 去获取内容
|
||||
String url = "https://video.yuchat.top/m3u8/" + id + "/index.m3u8";
|
||||
|
||||
String m3u8 = "";
|
||||
try {
|
||||
m3u8 = httpRequestComponent.get(url);
|
||||
} catch (Exception e) {
|
||||
log.warn("获取m3u8失败,错误信息:{},url:{}", e.getMessage(), url);
|
||||
}
|
||||
if (StringUtils.isNotBlank(m3u8)) {
|
||||
return m3u8;
|
||||
}
|
||||
// 如果是404则去数据可查询原始数据
|
||||
MadouVideoInfo videoInfo = getById(id);
|
||||
if (videoInfo == null) {
|
||||
throw new RuntimeException("视频不存在");
|
||||
}
|
||||
return httpRequestComponent.get(videoInfo.getM3u8Url());
|
||||
}
|
||||
|
||||
public void downloadTs(Long id, String ts) throws IOException {
|
||||
// https://video.yuchat.top/m3u8/{id}/{ts} 去获取内容
|
||||
String url = "https://video.yuchat.top/m3u8/" + id + "/" + ts;
|
||||
try {
|
||||
httpRequestComponent.download(url, httpServletResponse.getOutputStream());
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
log.warn("下载ts失败,错误信息:{},url:{}", e.getMessage(), url);
|
||||
}
|
||||
MadouVideoInfo videoInfo = getById(id);
|
||||
if (videoInfo == null) {
|
||||
throw new RuntimeException("视频不存在");
|
||||
}
|
||||
httpRequestComponent.download(videoInfo.getM3u8Url().replace("index.m3u8", ts), httpServletResponse.getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,9 +18,12 @@ import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyManagementException;
|
||||
@ -109,6 +112,21 @@ public class HttpRequestComponent {
|
||||
Files.copy(entity.getContent(), path);
|
||||
}
|
||||
|
||||
|
||||
public void download(String url, OutputStream os) throws IOException {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
httpGet.setConfig(requestConfig);
|
||||
CloseableHttpResponse response = closeableHttpClient.execute(httpGet);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (HttpStatus.SC_OK != statusCode) {
|
||||
log.error("文件下载失败,状态码:{}", statusCode);
|
||||
throw new RuntimeException("文件下载失败");
|
||||
}
|
||||
HttpEntity entity = response.getEntity();
|
||||
IOUtils.copy(entity.getContent(), os);
|
||||
}
|
||||
|
||||
|
||||
public long getFileSize(String url) throws IOException {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
httpGet.setConfig(requestConfig);
|
||||
|
||||
35
src/main/java/top/yuchat/crawler/video/utils/JsonResult.java
Normal file
35
src/main/java/top/yuchat/crawler/video/utils/JsonResult.java
Normal file
@ -0,0 +1,35 @@
|
||||
package top.yuchat.crawler.video.utils;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class JsonResult<T> {
|
||||
private int code;
|
||||
private String message;
|
||||
private T data;
|
||||
|
||||
public static <T> JsonResult<T> ok(T data) {
|
||||
return new JsonResult<>(200, "请求执行成功!", data);
|
||||
}
|
||||
|
||||
public static <T> JsonResult<T> ok() {
|
||||
return ok(null);
|
||||
}
|
||||
|
||||
public static <T> JsonResult<T> error(int code, String message) {
|
||||
return new JsonResult<>(code, message, null);
|
||||
}
|
||||
|
||||
public static <T> JsonResult<T> error(String message) {
|
||||
return error(500, message);
|
||||
}
|
||||
|
||||
public static <T> JsonResult<T> error(Exception e) {
|
||||
return error(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
url: jdbc:postgresql://pgsql.yuchat.top:5432/postgres
|
||||
url: jdbc:postgresql://yuchat-databases:5432/postgres
|
||||
username: postgres
|
||||
password: longqi@1314
|
||||
|
||||
top:
|
||||
yuchat:
|
||||
download:
|
||||
path: F:\videos
|
||||
# 日志级别,生产环境改为warn
|
||||
logging:
|
||||
level:
|
||||
root: info
|
||||
@ -1,4 +1,5 @@
|
||||
|
||||
|
||||
minio:
|
||||
endpoint: http://minio.yuchat:9000
|
||||
access-key: CGG6QZHvKI0JEuXM5gBJ
|
||||
@ -8,4 +9,7 @@ minio:
|
||||
top:
|
||||
yuchat:
|
||||
download:
|
||||
path: F:\videos
|
||||
path: F:\videos
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
Loading…
x
Reference in New Issue
Block a user