From fdd2dd700b2b2fbcc72e7dd21c1347943b2eb920 Mon Sep 17 00:00:00 2001 From: yanlongqi Date: Sat, 28 Dec 2024 20:11:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A7=86=E9=A2=91=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=92=8C=20m3u8=20=E6=96=87=E4=BB=B6=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 m3u8 文件获取和 ts 文件下载功能 - 添加视频控制器,实现视频列表、详情和 m3u8 文件获取接口 - 优化应用配置,增加开发环境配置 - 重构 HTTP 请求组件,支持文件下载 - 新增 JSON 结果封装类,统一接口返回格式 --- .../models/controller/VideoController.java | 65 +++++++++++++++++++ .../models/service/MadouVideoService.java | 39 +++++++++++ .../video/utils/HttpRequestComponent.java | 18 +++++ .../crawler/video/utils/JsonResult.java | 35 ++++++++++ src/main/resources/application-prod.yml | 10 +-- src/main/resources/application.yml | 6 +- 6 files changed, 167 insertions(+), 6 deletions(-) create mode 100644 src/main/java/top/yuchat/crawler/video/models/controller/VideoController.java create mode 100644 src/main/java/top/yuchat/crawler/video/utils/JsonResult.java diff --git a/src/main/java/top/yuchat/crawler/video/models/controller/VideoController.java b/src/main/java/top/yuchat/crawler/video/models/controller/VideoController.java new file mode 100644 index 0000000..da2bbd3 --- /dev/null +++ b/src/main/java/top/yuchat/crawler/video/models/controller/VideoController.java @@ -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> getClassifyInfo() { + return JsonResult.ok(classifyInfoService.list()); + } + + @GetMapping("/madou") + public JsonResult> 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 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); + } + +} diff --git a/src/main/java/top/yuchat/crawler/video/models/service/MadouVideoService.java b/src/main/java/top/yuchat/crawler/video/models/service/MadouVideoService.java index c8f4bb1..93dbd70 100644 --- a/src/main/java/top/yuchat/crawler/video/models/service/MadouVideoService.java +++ b/src/main/java/top/yuchat/crawler/video/models/service/MadouVideoService.java @@ -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(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()); + } } diff --git a/src/main/java/top/yuchat/crawler/video/utils/HttpRequestComponent.java b/src/main/java/top/yuchat/crawler/video/utils/HttpRequestComponent.java index 487dc14..d1444e1 100644 --- a/src/main/java/top/yuchat/crawler/video/utils/HttpRequestComponent.java +++ b/src/main/java/top/yuchat/crawler/video/utils/HttpRequestComponent.java @@ -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); diff --git a/src/main/java/top/yuchat/crawler/video/utils/JsonResult.java b/src/main/java/top/yuchat/crawler/video/utils/JsonResult.java new file mode 100644 index 0000000..7be75d0 --- /dev/null +++ b/src/main/java/top/yuchat/crawler/video/utils/JsonResult.java @@ -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 { + private int code; + private String message; + private T data; + + public static JsonResult ok(T data) { + return new JsonResult<>(200, "请求执行成功!", data); + } + + public static JsonResult ok() { + return ok(null); + } + + public static JsonResult error(int code, String message) { + return new JsonResult<>(code, message, null); + } + + public static JsonResult error(String message) { + return error(500, message); + } + + public static JsonResult error(Exception e) { + return error(e.getMessage()); + } + +} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index d68bc1f..519af91 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -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 \ No newline at end of file +# 日志级别,生产环境改为warn +logging: + level: + root: info \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c51d550..fc7e4d0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,5 @@ + minio: endpoint: http://minio.yuchat:9000 access-key: CGG6QZHvKI0JEuXM5gBJ @@ -8,4 +9,7 @@ minio: top: yuchat: download: - path: F:\videos \ No newline at end of file + path: F:\videos +spring: + profiles: + active: dev \ No newline at end of file