optimize updates

This commit is contained in:
mubai
2025-03-23 16:30:56 +08:00
parent c1e28380d0
commit 24aa240ab2
40 changed files with 1088 additions and 590 deletions

2
.gitignore vendored
View File

@@ -22,6 +22,8 @@ package-lock.json
.idea/
.idea
.vscode
.vscode/
# 文件保留路径
static/

View File

@@ -16,6 +16,22 @@
## 项目部署
**部署方式**
- [Docker部署](https://github.com/ProudMuBai/GoFilm/blob/main/film/README.md)
- [1Panel部署(可视化面板操作)](https://blog.mubai.link/2024/04/21/Docs/gofilm/)
**使用指南**
- 后端项目路径 `GoFilm/server`, 包含 项目结构说明, 后端程序源码, API接口说明, 本地启动注意事项 [查看](https://github.com/ProudMuBai/GoFilm/tree/main/server)
- 前端项目路径 `GoFilm/client`, 包含 项目结构说明, 前端项目源码, 配置文件说明, 本地启动方式 [查看](https://github.com/ProudMuBai/GoFilm/tree/main/client)
- 部署文件 `GoFilm/film`, 包含项目部署所需的所有文件以及相应的说明文件 [查看](https://github.com/ProudMuBai/GoFilm/tree/main/film)
- 程序使用文档: 提供项目安装部署以及相应的初始化使用步骤说明 [点击前往](https://blog.mubai.link/2024/04/21/Docs/gofilm/)
## 新版本说明
**网站前台**
@@ -24,7 +40,7 @@
- 前台部分对网站名称以及播放源等部分信息与后台数据进行关联, 可通过后台进行修改
- 影片详情部分以及首页导航数据结构发生变化, 样式保持一致
- 默认访问地址: `服务器IP:默认端口 [http://127.0.0.1:3600]`
- 默认访问地址: `服务器IP:默认端口 [http://127.0.0.1/index]`
**管理后台**
@@ -41,14 +57,19 @@
>新增内容:
>
>- 新增详细部署说明文档, 以及 `1Panel部署方式` , [点击查看](https://blog.mubai.link/2024/04/21/Docs/gofilm/)
>- 修复pc端历史记录异常问题, 新增移动端历史记录功能, 以及底部功能组(部分实现)
>- 优化pc以及移动端的卡片内容展示效果
>- 新增移动端观看历史
>- 新增采集失败记录功能 && 基于失败的采集进行重新采集处理
>- 默认定时任务新增定期处理失败采集功能
>- 修复Banner首页轮播横幅参数修改提交异常问题
>- 修复首页一级分类导航无数据问题
>- 修复首页界面影片信息卡片异常显示问题
>- 优化影片详情以及播放页的组件背景显示问题
>
>后续计划:
>
>- 优先针对手机端主页以及导航做修改
>- 同步手机端历史记录功能
>- 新增功能测试 && buf修复
>- 完善历史观看界面功能 && 优化相应UI组件
>- 针对播放器进行优化 OR 更换播放器组件
>- 采集方式细节化, 实现定向采集以及单一影片的实时手动更新功能
## 目录结构

View File

@@ -27,9 +27,8 @@
<template v-if="item.nav.show">
<el-row class="row-bg cus_nav" justify="space-between">
<el-col :span="12" class="title">
<span
:class="`iconfont ${item.nav.name.search('电影') != -1?'icon-film':item.nav.name.search('剧') != -1?'icon-tv':item.nav.name.search('动漫')!= -1?'icon-cartoon':'icon-variety'}`"
style="color: #79bbff;font-size: 32px;margin-right: 10px; line-height: 130%"/>
<span :class="`iconfont ${item.nav.name.search('电影') != -1?'icon-film':item.nav.name.search('剧') != -1?'icon-tv':item.nav.name.search('动漫')!= -1?'icon-cartoon':'icon-variety'}`"
style="color: #79bbff;font-size: 32px;margin-right: 10px; line-height: 130%"/>
<a :href="`/filmClassify?Pid=${item.nav.id}`">{{ item.nav.name }}</a>
</el-col>
<el-col :span="12">

View File

@@ -61,7 +61,7 @@
<el-dialog v-model="data.dialogV.addV" width="680px" title="添加海报">
<el-form :model="data.banner">
<el-form-item label="影片ID&emsp;">
<el-input v-model="data.banner.mid" placeholder="影片唯一ID"/>
<el-input v-model.number="data.banner.mid" placeholder="影片唯一ID"/>
</el-form-item>
<el-form-item label="影片名称">
<el-input v-model="data.banner.name" placeholder="影片名称"/>
@@ -138,7 +138,7 @@
<el-dialog v-model="data.dialogV.editV" width="680px" title="修改海报信息">
<el-form :model="data.banner">
<el-form-item label="影片ID&emsp;">
<el-input v-model="data.banner.mid" placeholder="影片唯一ID"/>
<el-input v-model.number="data.banner.mid" placeholder="影片唯一ID"/>
</el-form-item>
<el-form-item label="影片名称">
<el-input v-model="data.banner.name" placeholder="影片名称"/>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -11,8 +11,8 @@
<meta charset="UTF-8"/>
<title>(╥﹏╥)</title>
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_3992367_d9xdu8zk04f.css">
<script type="module" crossorigin src="/assets/index-c9db717b.js"></script>
<link rel="stylesheet" href="/assets/index-55e1c426.css">
<script type="module" crossorigin src="/assets/index-71fe0e9a.js"></script>
<link rel="stylesheet" href="/assets/index-b0d2aea4.css">
</head>
<body>
<div id="app"></div>

View File

@@ -69,6 +69,8 @@ const (
FilmCrontabKey = "Cron:Task:Film"
// DefaultUpdateSpec 每20分钟执行一次
DefaultUpdateSpec = "0 */20 * * * ?"
// EveryWeekSpec 每周日凌晨4点更新一次
EveryWeekSpec = "0 0 4 * * 0"
// DefaultUpdateTime 每次采集最近 3 小时内更新的影片
DefaultUpdateTime = 3
)
@@ -82,10 +84,11 @@ const (
// -------------------------Database Connection Params-----------------------------------
const (
// SearchTableName 存放检索信息的数据表名
SearchTableName = "search"
UserTableName = "users"
UserIdInitialVal = 10000
FileTableName = "files"
SearchTableName = "search"
UserTableName = "users"
UserIdInitialVal = 10000
FileTableName = "files"
FailureRecordTableName = "failure_records"
//mysql服务配置信息 root:root 设置mysql账户的用户名和密码

View File

@@ -0,0 +1,283 @@
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"server/logic"
"server/model/system"
"server/plugin/spider"
"strconv"
"time"
)
// ------------------------------------------------------ 影视采集 ------------------------------------------------------
// FilmSourceList 采集站点信息
func FilmSourceList(c *gin.Context) {
system.Success(logic.CollectL.GetFilmSourceList(), "影视源站点信息获取成功", c)
return
}
// FindFilmSource 通过ID返回对应的资源站数据
func FindFilmSource(c *gin.Context) {
id := c.Query("id")
if id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
fs := logic.CollectL.GetFilmSource(id)
if fs == nil {
system.Failed("数据异常,资源站信息不存在", c)
return
}
system.Success(fs, "原站点详情信息查找成功", c)
}
// FilmSourceAdd 添加采集源
func FilmSourceAdd(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
// 校验必要参数
if err := validFilmSource(s); err != nil {
system.Failed(err.Error(), c)
return
}
// 如果采集站开启图片同步, 且采集站为附属站点则返回错误提示
if s.SyncPictures && (s.Grade == system.SlaveCollect) {
system.Failed("附属站点无法开启图片同步功能", c)
return
}
// 执行 spider
if err := spider.CollectApiTest(s); err != nil {
system.Failed("资源接口测试失败, 请确认接口有效再添加", c)
return
}
// 测试通过后将资源站信息添加到list
if err := logic.CollectL.SaveFilmSource(s); err != nil {
system.Failed(fmt.Sprint("资源站添加失败: ", err.Error()), c)
return
}
system.SuccessOnlyMsg("添加成功", c)
}
// FilmSourceUpdate 采集站点信息更新
func FilmSourceUpdate(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
// 校验必要参数
if err := validFilmSource(s); err != nil {
system.Failed(err.Error(), c)
return
}
// 如果采集站开启图片同步, 且采集站为附属站点则返回错误提示
if s.SyncPictures && (s.Grade == system.SlaveCollect) {
system.Failed("附属站点无法开启图片同步功能", c)
return
}
// 校验Id信息是否为空
if s.Id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
fs := logic.CollectL.GetFilmSource(s.Id)
if fs == nil {
system.Failed("数据异常,资源站信息不存在", c)
return
}
// 如果 uri发生变更则执行spider测试
if fs.Uri != s.Uri {
// 执行 spider
if err := spider.CollectApiTest(s); err != nil {
system.Failed("资源接口测试失败, 请确认更新的数据接口是否有效", c)
return
}
}
// 更新资源站信息
if err := logic.CollectL.UpdateFilmSource(s); err != nil {
system.Failed(fmt.Sprint("资源站更新失败: ", err.Error()), c)
return
}
system.SuccessOnlyMsg("更新成功", c)
}
// FilmSourceChange 采集站点状态变更
func FilmSourceChange(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
if s.Id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
// 查找对应的资源站点信息
fs := logic.CollectL.GetFilmSource(s.Id)
if fs == nil {
system.Failed("数据异常,资源站信息不存在", c)
return
}
// 如果采集站开启图片同步, 且采集站为附属站点则返回错误提示
if s.SyncPictures && (fs.Grade == system.SlaveCollect) {
system.Failed("附属站点无法开启图片同步功能", c)
return
}
if s.State != fs.State || s.SyncPictures != fs.SyncPictures {
// 执行更新操作
s := system.FilmSource{Id: fs.Id, Name: fs.Name, Uri: fs.Uri, ResultModel: fs.ResultModel,
Grade: fs.Grade, SyncPictures: s.SyncPictures, CollectType: fs.CollectType, State: s.State}
// 更新资源站信息
if err := logic.CollectL.UpdateFilmSource(s); err != nil {
system.Failed(fmt.Sprint("资源站更新失败: ", err.Error()), c)
return
}
}
system.SuccessOnlyMsg("更新成功", c)
}
// FilmSourceDel 采集站点删除
func FilmSourceDel(c *gin.Context) {
id := c.Query("id")
if len(id) <= 0 {
system.Failed("资源站ID信息不能为空", c)
return
}
if err := logic.CollectL.DelFilmSource(id); err != nil {
system.Failed("删除资源站失败", c)
return
}
system.SuccessOnlyMsg("删除成功", c)
}
// FilmSourceTest 测试影视站点数据是否可用
func FilmSourceTest(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
// 校验必要参数
if err := validFilmSource(s); err != nil {
system.Failed(err.Error(), c)
return
}
// 执行 spider
if err := spider.CollectApiTest(s); err != nil {
system.Failed(err.Error(), c)
return
}
system.SuccessOnlyMsg("测试成功!!!", c)
}
// GetNormalFilmSource 获取状态为启用的采集站信息
func GetNormalFilmSource(c *gin.Context) {
// 获取所有的采集站信息
var l []system.FilmTaskOptions
for _, v := range logic.CollectL.GetFilmSourceList() {
if v.State {
l = append(l, system.FilmTaskOptions{Id: v.Id, Name: v.Name})
}
}
system.Success(l, "影视源信息获取成功", c)
}
// ------------------------------------------------------ 失败采集记录 ------------------------------------------------------
// FailureRecordList 失效采集记录分页数据
func FailureRecordList(c *gin.Context) {
// 数据返回对象
var params = system.RecordRequestVo{Paging: &system.Page{}}
var err error
// 获取筛选条件
params.OriginId = c.DefaultQuery("originId", "")
//params.CollectType, err = strconv.Atoi(c.DefaultQuery("collectType", "-1"))
params.Hour, err = strconv.Atoi(c.DefaultQuery("hour", "0"))
params.Status, err = strconv.Atoi(c.DefaultQuery("status", "-1"))
// 处理时间参数
begin := c.DefaultQuery("beginTime", "")
if begin != "" {
beginTime, e := time.ParseInLocation(time.DateTime, begin, time.Local)
if e != nil {
system.Failed("影片分页数据获取失败, 请求参数异常", c)
return
}
params.BeginTime = beginTime
}
end := c.DefaultQuery("endTime", "")
if end != "" {
endTime, e := time.ParseInLocation(time.DateTime, end, time.Local)
if e != nil {
system.Failed("影片分页数据获取失败, 请求参数异常", c)
return
}
params.EndTime = endTime
}
// 分页参数
params.Paging.Current, err = strconv.Atoi(c.DefaultQuery("current", "1"))
params.Paging.PageSize, err = strconv.Atoi(c.DefaultQuery("pageSize", "10"))
if err != nil {
system.Failed("影片分页数据获取失败, 分页参数异常", c)
return
}
// 如果分页数据超出指定范围则设置为默认值
if params.Paging.PageSize <= 0 || params.Paging.PageSize > 500 {
params.Paging.PageSize = 10
}
// 条件筛选select选项参数
options := logic.CollectL.GetRecordOptions()
// 获取满足条件的分页数据
list := logic.CollectL.GetRecordList(params)
system.Success(gin.H{"params": params, "list": list, "options": options}, "影片分页信息获取成功", c)
}
// CollectRecover 对失败的采集进行处理
func CollectRecover(c *gin.Context) {
// 获取记录id
id, err := strconv.Atoi(c.DefaultQuery("id", "0"))
if err != nil && id != 0 {
system.Failed("采集重试开启失败, 采集记录ID参数异常", c)
return
}
// 通过记录id对失败的采集进行恢复重试操作
err = logic.CollectL.CollectRecover(id)
if err != nil {
system.Failed(err.Error(), c)
return
}
system.SuccessOnlyMsg("采集重试已开启, 请勿重复操作", c)
}
// CollectRecoverAll 恢复采集-全量
func CollectRecoverAll(c *gin.Context) {
// 重新采集表中所有失败记录
logic.CollectL.RecoverAll()
system.SuccessOnlyMsg("恢复任务已成功开启!!!", c)
}
// ClearDoneRecord 清理已处理的记录
func ClearDoneRecord(c *gin.Context) {
// 删除表中已处理完成的记录
logic.CollectL.ClearDoneRecord()
system.SuccessOnlyMsg("处理完成的记录信息已删除!!!", c)
}
// ClearAllRecord 删除所有记录
func ClearAllRecord(c *gin.Context) {
// 截断失败采集记录表
logic.CollectL.ClearAllRecord()
system.SuccessOnlyMsg("采集异常记录信息已清空!!!", c)
}

View File

@@ -140,17 +140,34 @@ func validTaskInfo(t system.FilmCollectTask) error {
// 任务添加参数校验
func validTaskAddVo(vo system.FilmCronVo) error {
if vo.Model != 0 && vo.Model != 1 {
switch vo.Model {
case 0:
if vo.Time == 0 {
return errors.New("参数校验失败, 采集时长不能为零值")
}
case 1:
if vo.Time == 0 {
return errors.New("参数校验失败, 采集时长不能为零值")
}
if vo.Ids == nil || len(vo.Ids) <= 0 {
return errors.New("参数校验失败, 自定义更新未绑定任何资源站点")
}
case 2:
break
default:
return errors.New("参数校验失败, 未定义的任务类型")
}
if vo.Time == 0 {
return errors.New("参数校验失败, 采集时长不能为零值")
}
//if vo.Model != 0 && vo.Model != 1 && vo.Model != 2 {
// return errors.New("参数校验失败, 未定义的任务类型")
//}
//if vo.Time == 0 {
// return errors.New("参数校验失败, 采集时长不能为零值")
//}
if err := spider.ValidSpec(vo.Spec); err != nil {
return errors.New(fmt.Sprint("参数校验失败 cron表达式校验失败: ", err.Error()))
}
if vo.Model == 1 && (vo.Ids == nil || len(vo.Ids) <= 0) {
return errors.New("参数校验失败, 自定义更新未绑定任何资源站点")
}
//if vo.Model == 1 && (vo.Ids == nil || len(vo.Ids) <= 0) {
// return errors.New("参数校验失败, 自定义更新未绑定任何资源站点")
//}
return nil
}

View File

@@ -8,7 +8,6 @@ import (
"server/model/system"
"server/plugin/SystemInit"
"server/plugin/common/util"
"server/plugin/spider"
)
func ManageIndex(c *gin.Context) {
@@ -16,184 +15,6 @@ func ManageIndex(c *gin.Context) {
return
}
// ------------------------------------------------------ 影视采集 ------------------------------------------------------
// FilmSourceList 采集站点信息
func FilmSourceList(c *gin.Context) {
system.Success(logic.ML.GetFilmSourceList(), "影视源站点信息获取成功", c)
return
}
// FindFilmSource 通过ID返回对应的资源站数据
func FindFilmSource(c *gin.Context) {
id := c.Query("id")
if id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
fs := logic.ML.GetFilmSource(id)
if fs == nil {
system.Failed("数据异常,资源站信息不存在", c)
return
}
system.Success(fs, "原站点详情信息查找成功", c)
}
// FilmSourceAdd 添加采集源
func FilmSourceAdd(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
// 校验必要参数
if err := validFilmSource(s); err != nil {
system.Failed(err.Error(), c)
return
}
// 如果采集站开启图片同步, 且采集站为附属站点则返回错误提示
if s.SyncPictures && (s.Grade == system.SlaveCollect) {
system.Failed("附属站点无法开启图片同步功能", c)
return
}
// 执行 spider
if err := spider.CollectApiTest(s); err != nil {
system.Failed("资源接口测试失败, 请确认接口有效再添加", c)
return
}
// 测试通过后将资源站信息添加到list
if err := logic.ML.SaveFilmSource(s); err != nil {
system.Failed(fmt.Sprint("资源站添加失败: ", err.Error()), c)
return
}
system.SuccessOnlyMsg("添加成功", c)
}
func FilmSourceUpdate(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
// 校验必要参数
if err := validFilmSource(s); err != nil {
system.Failed(err.Error(), c)
return
}
// 如果采集站开启图片同步, 且采集站为附属站点则返回错误提示
if s.SyncPictures && (s.Grade == system.SlaveCollect) {
system.Failed("附属站点无法开启图片同步功能", c)
return
}
// 校验Id信息是否为空
if s.Id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
fs := logic.ML.GetFilmSource(s.Id)
if fs == nil {
system.Failed("数据异常,资源站信息不存在", c)
return
}
// 如果 uri发生变更则执行spider测试
if fs.Uri != s.Uri {
// 执行 spider
if err := spider.CollectApiTest(s); err != nil {
system.Failed("资源接口测试失败, 请确认更新的数据接口是否有效", c)
return
}
}
// 更新资源站信息
if err := logic.ML.UpdateFilmSource(s); err != nil {
system.Failed(fmt.Sprint("资源站更新失败: ", err.Error()), c)
return
}
system.SuccessOnlyMsg("更新成功", c)
}
func FilmSourceChange(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
if s.Id == "" {
system.Failed("参数异常, 资源站标识不能为空", c)
return
}
// 查找对应的资源站点信息
fs := logic.ML.GetFilmSource(s.Id)
if fs == nil {
system.Failed("数据异常,资源站信息不存在", c)
return
}
// 如果采集站开启图片同步, 且采集站为附属站点则返回错误提示
if s.SyncPictures && (fs.Grade == system.SlaveCollect) {
system.Failed("附属站点无法开启图片同步功能", c)
return
}
if s.State != fs.State || s.SyncPictures != fs.SyncPictures {
// 执行更新操作
s := system.FilmSource{Id: fs.Id, Name: fs.Name, Uri: fs.Uri, ResultModel: fs.ResultModel,
Grade: fs.Grade, SyncPictures: s.SyncPictures, CollectType: fs.CollectType, State: s.State}
// 更新资源站信息
if err := logic.ML.UpdateFilmSource(s); err != nil {
system.Failed(fmt.Sprint("资源站更新失败: ", err.Error()), c)
return
}
}
system.SuccessOnlyMsg("更新成功", c)
}
func FilmSourceDel(c *gin.Context) {
id := c.Query("id")
if len(id) <= 0 {
system.Failed("资源站ID信息不能为空", c)
return
}
if err := logic.ML.DelFilmSource(id); err != nil {
system.Failed("删除资源站失败", c)
return
}
system.SuccessOnlyMsg("删除成功", c)
}
// FilmSourceTest 测试影视站点数据是否可用
func FilmSourceTest(c *gin.Context) {
var s = system.FilmSource{}
// 获取请求参数
if err := c.ShouldBindJSON(&s); err != nil {
system.Failed("请求参数异常", c)
return
}
// 校验必要参数
if err := validFilmSource(s); err != nil {
system.Failed(err.Error(), c)
return
}
// 执行 spider
if err := spider.CollectApiTest(s); err != nil {
system.Failed(err.Error(), c)
return
}
system.SuccessOnlyMsg("测试成功!!!", c)
}
// GetNormalFilmSource 获取状态为启用的采集站信息
func GetNormalFilmSource(c *gin.Context) {
// 获取所有的采集站信息
var l []system.FilmTaskOptions
for _, v := range logic.ML.GetFilmSourceList() {
if v.State {
l = append(l, system.FilmTaskOptions{Id: v.Id, Name: v.Name})
}
}
system.Success(l, "影视源信息获取成功", c)
}
// ------------------------------------------------------ 站点基本配置 ------------------------------------------------------
// SiteBasicConfig 网站基本配置

View File

@@ -111,12 +111,14 @@ func DirectedSpider(c *gin.Context) {
// SingleUpdateSpider 单一影片更新采集
func SingleUpdateSpider(c *gin.Context) {
// 获取影片对应的唯一标识
id := c.Query("id")
if id == "" {
system.Failed("参数异常, 资源标识不能为空", c)
ids := c.Query("ids")
if ids == "" {
system.Failed("参数异常, 资源标识ID信息缺失", c)
return
}
// 通过ID对指定影片进行同步更新
logic.SL.SyncCollect(ids)
system.SuccessOnlyMsg("影片更新任务已成功开启!!!", c)
}
// 校验密码有效性

View File

@@ -46,8 +46,7 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gocolly/colly v1.2.0/go.mod h1:Hof5T3ZswNVsOHYmba1u03W65HDWgpV5HifSuueE0EA=
github.com/gocolly/colly/v2 v2.1.0 h1:k0DuZkDoCsx51bKpRJNEmcxcp+W5N8ziuwGaSDuFoGs=
@@ -205,8 +204,6 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.4.7 h1:rY46lkCspzGHn7+IYsNpSfEv9tA+SU4SkkB+GFX125Y=
gorm.io/driver/mysql v1.4.7/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.6 h1:wy98aq9oFEetsc4CAbKD2SoBCdMzsbSIvSUUFJuHi5s=
gorm.io/gorm v1.24.6/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -0,0 +1,106 @@
package logic
import (
"errors"
"server/model/system"
"server/plugin/spider"
)
type CollectLogic struct {
}
var CollectL *CollectLogic
// ------------------------------------------------------ 采集站点管理 ------------------------------------------------------
// GetFilmSourceList 获取采集站列表数据
func (cl *CollectLogic) GetFilmSourceList() []system.FilmSource {
// 返回当前已添加的采集站列表信息
return system.GetCollectSourceList()
}
// GetFilmSource 获取ID对应的采集源信息
func (cl *CollectLogic) GetFilmSource(id string) *system.FilmSource {
return system.FindCollectSourceById(id)
}
// UpdateFilmSource 更新采集源信息
func (cl *CollectLogic) UpdateFilmSource(s system.FilmSource) error {
return system.UpdateCollectSource(s)
}
// SaveFilmSource 保存采集源信息
func (cl *CollectLogic) SaveFilmSource(s system.FilmSource) error {
return system.AddCollectSource(s)
}
// DelFilmSource 删除采集源信息
func (cl *CollectLogic) DelFilmSource(id string) error {
// 先查找是否存在对应ID的站点信息
s := system.FindCollectSourceById(id)
if s == nil {
return errors.New("当前资源站信息不存在, 请勿重复操作")
}
// 如果是主站点则返回提示禁止直接删除
if s.Grade == system.MasterCollect {
return errors.New("主站点无法直接删除, 请先降级为附属站点再进行删除")
}
system.DelCollectResource(id)
return nil
}
// ------------------------------------------------------ 采集记录管理 ------------------------------------------------------
// GetRecordList 获取采集记录列表
func (cl *CollectLogic) GetRecordList(params system.RecordRequestVo) []system.FailureRecord {
return system.FailureRecordList(params)
}
// GetRecordOptions 获取采集记录筛选参数
func (cl *CollectLogic) GetRecordOptions() system.OptionGroup {
var options = make(system.OptionGroup)
// 获取筛选参数, 采集源(ID:name) | 采集类型 | 状态
options["collectType"] = []system.Option{{"全部", -1}, {"影片详情", 0}, {"文章", 1}, {"演员", 2}, {"角色", 3}, {"网站", 4}}
options["status"] = []system.Option{{"全部", -1}, {"待重试", 1}, {"已处理", 0}}
// 获取全部采集站
var originOptions = []system.Option{{"全部", ""}}
for _, v := range system.GetCollectSourceList() {
originOptions = append(originOptions, system.Option{Name: v.Name, Value: v.Id})
}
options["origin"] = originOptions
return options
}
// CollectRecover 恢复采集
func (cl *CollectLogic) CollectRecover(id int) error {
// 通过ID获取完整的失败记录信息
fr := system.FindRecordById(uint(id))
// 如果获取失败记录信息为空, 则不进行后续操作
if fr == nil {
return errors.New("采集重试执行失败: 失败记录信息获取异常")
}
// 执行恢复采集, 恢复对应的采集数据
go spider.SingleRecoverSpider(fr)
return nil
}
// RecoverAll 恢复重新对所有失效记录进行重新采集处理
func (cl *CollectLogic) RecoverAll() {
// 是否进行身份验证, 暂定无需处理
// 对数据表中的所有待处理记录进行恢复采集
go spider.FullRecoverSpider()
}
// ClearDoneRecord 清除已处理完成的记录信息 (将记录表中已经完成处理的记录删除)
func (cl *CollectLogic) ClearDoneRecord() {
// <逻辑删除 or 真实删除> 为避免ID中断暂定逻辑删除
system.DelDoneRecord()
}
// ClearAllRecord 清除所有记录信息 (直接对记录表直接进行截断处理)
func (cl *CollectLogic) ClearAllRecord() {
// 重置记录表状态, 删除所有数据并将自增ID归零
system.TruncateRecordTable()
}

View File

@@ -40,6 +40,14 @@ func (cl *CronLogic) AddFilmCrontab(cv system.FilmCronVo) error {
}
// 将定时任务Id记录到Task中
task.Cid = cid
case 2:
cid, err := spider.AddFilmRecoverCron(task.Spec)
// 如果任务添加失败则直接返回错误信息
if err != nil {
return errors.New(fmt.Sprint("失败采集处理定时任务添加失败: ", err.Error()))
}
// 将定时任务Id记录到Task中
task.Cid = cid
}
// 如果没有异常则将当前定时任务信息记录到redis中
system.SaveFilmTask(task)

View File

@@ -45,11 +45,26 @@ func (i *IndexLogic) IndexPage() map[string]interface{} {
// 2. 提供用于首页展示的顶级分类影片信息, 每分类 14条数据
var list []map[string]interface{}
for _, c := range tree.Children {
// 生成分页参数
page := system.Page{PageSize: 14, Current: 1}
movies := system.GetMovieListByPid(c.Id, &page)
// 获取当前分类的本月热门影片
HotMovies := system.GetHotMovieByPid(c.Id, &page)
item := map[string]interface{}{"nav": c, "movies": movies, "hot": HotMovies}
// 获取最近上映影片和本月热门影片
var movies []system.MovieBasicInfo
var hotMovies []system.SearchInfo
if c.Children != nil {
// 如果有子分类, 则通过Pid获取对应影片
// 获取当前分类的最新上映影片
movies = system.GetMovieListByPid(c.Id, &page)
// 获取当前分类的本月热门影片
hotMovies = system.GetHotMovieByPid(c.Id, &page)
} else {
// 如果当前分类为一级分类且没有子分类,则通过Cid获取对应数据
// 获取当前分类的最新上映影片
movies = system.GetMovieListByCid(c.Id, &page)
// 获取当前分类的本月热门影片
hotMovies = system.GetHotMovieByCid(c.Id, &page)
}
item := map[string]interface{}{"nav": c, "movies": movies, "hot": hotMovies}
list = append(list, item)
}
Info["content"] = list

View File

@@ -1,7 +1,6 @@
package logic
import (
"errors"
"server/model/system"
)
@@ -10,42 +9,6 @@ type ManageLogic struct {
var ML *ManageLogic
// GetFilmSourceList 获取采集站列表数据
func (ml *ManageLogic) GetFilmSourceList() []system.FilmSource {
// 返回当前已添加的采集站列表信息
return system.GetCollectSourceList()
}
// GetFilmSource 获取ID对应的采集源信息
func (ml *ManageLogic) GetFilmSource(id string) *system.FilmSource {
return system.FindCollectSourceById(id)
}
// UpdateFilmSource 更新采集源信息
func (ml *ManageLogic) UpdateFilmSource(s system.FilmSource) error {
return system.UpdateCollectSource(s)
}
// SaveFilmSource 保存采集源信息
func (ml *ManageLogic) SaveFilmSource(s system.FilmSource) error {
return system.AddCollectSource(s)
}
// DelFilmSource 删除采集源信息
func (ml *ManageLogic) DelFilmSource(id string) error {
// 先查找是否存在对应ID的站点信息
s := system.FindCollectSourceById(id)
if s == nil {
return errors.New("当前资源站信息不存在, 请勿重复操作")
}
// 如果是主站点则返回提示禁止直接删除
if s.Grade == system.MasterCollect {
return errors.New("主站点无法直接删除, 请先降级为附属站点再进行删除")
}
system.DelCollectResource(id)
return nil
}
// GetSiteBasicConfig 获取网站基本配置信息
func (ml *ManageLogic) GetSiteBasicConfig() system.BasicConfig {
return system.GetSiteBasic()

View File

@@ -48,6 +48,11 @@ func (sl *SpiderLogic) ZeroCollect(time int) {
go spider.StarZero(time)
}
// SyncCollect 同步采集
func (sl *SpiderLogic) SyncCollect(ids string) {
go spider.CollectSingleFilm(ids)
}
// FilmClassCollect 影视分类采集, 直接覆盖当前分类数据
func (sl *SpiderLogic) FilmClassCollect() error {
l := system.GetCollectSourceListByGrade(system.MasterCollect)

View File

@@ -0,0 +1,146 @@
package system
import (
"fmt"
"gorm.io/gorm"
"log"
"server/config"
"server/plugin/db"
)
// FailureRecord 失败采集记录信息机构体
type FailureRecord struct {
gorm.Model
OriginId string `json:"originId"` // 采集站唯一ID
OriginName string `json:"originName"` // 采集站唯一ID
Uri string `json:"uri"` // 采集源链接
CollectType ResourceType `json:"collectType"` // 采集类型
PageNumber int `json:"pageNumber"` // 页码
Hour int `json:"hour"` // 采集参数 h 时长
Cause string `json:"cause"` // 失败原因
Status int `json:"status"` // 重试状态
}
// TableName 采集失败记录表表名
func (fr FailureRecord) TableName() string {
return config.FailureRecordTableName
}
// CreateFailureRecordTable 创建失效记录表
func CreateFailureRecordTable() {
var fl = &FailureRecord{}
// 不存在则创建FailureRecord表
if !db.Mdb.Migrator().HasTable(fl) {
if err := db.Mdb.AutoMigrate(fl); err != nil {
log.Println("Create Table failure_record failed:", err)
}
}
}
// SaveFailureRecord 添加采集失效记录
func SaveFailureRecord(fl FailureRecord) {
// 数据量不多但存在并发问题, 开启事务
err := db.Mdb.Transaction(func(tx *gorm.DB) error {
// 将采集失败信息存储到record表中
if err := tx.Create(&fl).Error; err != nil {
log.Println("Add failure record failed:", err)
return err
}
return nil
})
// 如果事务提交失败, 则输出相应信息, (存一份数据到Redis??)
if err != nil {
log.Println("Save failure record affairs failed:", err)
}
}
// FailureRecordList 获取所有的采集失效记录
func FailureRecordList(vo RecordRequestVo) []FailureRecord {
// 通过RecordRequestVo,生成查询条件
qw := db.Mdb.Model(&FailureRecord{})
if vo.OriginId != "" {
qw.Where("origin_id = ?", vo.OriginId)
}
if !vo.BeginTime.IsZero() && !vo.EndTime.IsZero() {
qw.Where("created_at BETWEEN ? AND ? ", vo.BeginTime, vo.EndTime)
}
//if vo.CollectType >= 0 {
// qw.Where("collect_type = ?", vo.CollectType)
//}
//if vo.Hour != 0 {
// qw.Where("hour = ?", vo.Hour)
//}
if vo.Status >= 0 {
qw.Where("status = ?", vo.Status)
}
// 获取分页数据
GetPage(qw, vo.Paging)
// 获取分页查询的数据
var list []FailureRecord
if err := qw.Limit(vo.Paging.PageSize).Offset((vo.Paging.Current - 1) * vo.Paging.PageSize).Order("updated_at DESC").Find(&list).Error; err != nil {
log.Println(err)
return nil
}
return list
}
// FindRecordById 获取id对应的失效记录
func FindRecordById(id uint) *FailureRecord {
var fr FailureRecord
fr.ID = id
// 通过ID查询对应的数据
db.Mdb.First(&fr)
return &fr
}
// PendingRecord 查询所有待处理的记录信息
func PendingRecord() []FailureRecord {
var list []FailureRecord
// 1. 获取 hour > 4320 || hour < 0 && status = 1 的影片信息
db.Mdb.Where("(hour > 4320 OR hour < 0) AND status = 1").Find(&list)
// 2. 获取 hour > 0 && hour < 4320 && status = 1 的影片信息(只获取最早的一条记录)
var fr FailureRecord
db.Mdb.Where("hour > 0 AND hour < 4320 AND status = 1").Order("hour DESC, created_at ASC").First(&fr)
// 3. 将 fr 添加到 list中
list = append(list, fr)
return list
}
// ChangeRecord 修改已完成二次采集的记录状态
func ChangeRecord(fr *FailureRecord, status int) {
switch {
case fr.Hour > 168 && fr.Hour < 360:
db.Mdb.Model(&FailureRecord{}).Where("hour > 168 AND hour < 360 AND created_at >= ?", fr.CreatedAt).Update("status", status)
case fr.Hour < 0, fr.Hour > 4320:
db.Mdb.Model(&FailureRecord{}).Where("id = ?", fr.ID).Update("status", status)
default:
// 其余范围,暂不处理
break
}
}
// RetryRecord 修改重试采集成功的记录
func RetryRecord(id uint, status int64) error {
// 查询id对应的失败记录
fr := FindRecordById(id)
// 将本次更新成功的记录数据状态修改为成功 0
return db.Mdb.Model(&FailureRecord{}).Where("update_at > ?", fr.UpdatedAt).Update("status", 0).Error
}
// DelDoneRecord 删除已处理的记录信息 -- 逻辑删除
func DelDoneRecord() {
if err := db.Mdb.Where("status = ?", 0).Delete(&FailureRecord{}).Error; err != nil {
log.Println("Delete failure record failed:", err)
}
}
// TruncateRecordTable 截断 record table
func TruncateRecordTable() {
var s FailureRecord
err := db.Mdb.Exec(fmt.Sprintf("TRUNCATE Table %s", s.TableName())).Error
if err != nil {
log.Println("TRUNCATE TABLE Error: ", err)
}
}

View File

@@ -19,7 +19,7 @@ type FilmCollectTask struct {
Cid cron.EntryID `json:"cid"` // 定时任务Id
Time int `json:"time"` // 采集时长, 最新x小时更新的内容
Spec string `json:"spec"` // 执行周期 cron表达式
Model int `json:"model"` // 任务类型, 0 - 自动更新已启用站点 || 1 - 更新Ids中的资源站数据
Model int `json:"model"` // 任务类型, 0 - 自动更新已启用站点 || 1 - 更新Ids中的资源站数据 || 2 - 定期清理失败采集记录
State bool `json:"state"` // 状态 开启 | 禁用
Remark string `json:"remark"` // 任务备注信息
}

View File

@@ -73,19 +73,19 @@ func FilmZero() {
db.Rdb.Del(db.Cxt, db.Rdb.Keys(db.Cxt, "OriginalResource*").Val()...)
db.Rdb.Del(db.Cxt, db.Rdb.Keys(db.Cxt, "Search*").Val()...)
// 删除mysql中留存的检索表
var s *SearchInfo
var s SearchInfo
//db.Mdb.Exec(fmt.Sprintf(`drop table if exists %s`, s.TableName()))
// 截断数据表 truncate table users
if ExistSearchTable() {
db.Mdb.Exec(fmt.Sprintf(`TRUNCATE table %s`, s.TableName()))
db.Mdb.Exec(fmt.Sprintf("TRUNCATE table %s", s.TableName()))
}
}
// ResetSearchTable 重置Search表
func ResetSearchTable() {
// 删除 Search 表
var s *SearchInfo
db.Mdb.Exec(fmt.Sprintf(`drop table if exists %s`, s.TableName()))
var s SearchInfo
db.Mdb.Exec(fmt.Sprintf("drop table if exists %s", s.TableName()))
// 重新创建 Search 表
CreateSearchTable()
}
@@ -112,7 +112,7 @@ func SaveSearchTag(search SearchInfo) {
// 获取redis中的searchMap
key := fmt.Sprintf(config.SearchTitle, search.Pid)
searchMap := db.Rdb.HGetAll(db.Cxt, key).Val()
// 是否存对应分类的map, 如果不存在则缓存一份
// 是否存对应分类的map, 如果不存在则缓存一份
if len(searchMap) == 0 {
searchMap = make(map[string]string)
searchMap["Category"] = "类型"
@@ -230,6 +230,7 @@ func CreateSearchTable() {
}
}
// ExistSearchTable 是否存在Search Table
func ExistSearchTable() bool {
// 1. 判断表中是否存在当前表
return db.Mdb.Migrator().HasTable(&SearchInfo{})
@@ -237,7 +238,7 @@ func ExistSearchTable() bool {
// AddSearchIndex search表中数据保存完毕后 将常用字段添加索引提高查询效率
func AddSearchIndex() {
var s *SearchInfo
var s SearchInfo
tableName := s.TableName()
// 添加索引
db.Mdb.Exec(fmt.Sprintf("CREATE UNIQUE INDEX idx_mid ON %s (mid)", tableName))
@@ -331,8 +332,8 @@ func ExistSearchInfo(mid int64) bool {
// TunCateSearchTable 截断SearchInfo数据表
func TunCateSearchTable() {
var searchInfo *SearchInfo
err := db.Mdb.Exec(fmt.Sprint("TRUNCATE TABLE ", searchInfo.TableName())).Error
var searchInfo SearchInfo
err := db.Mdb.Exec(fmt.Sprintf("TRUNCATE TABLE %s", searchInfo.TableName())).Error
if err != nil {
log.Println("TRUNCATE TABLE Error: ", err)
}
@@ -434,7 +435,7 @@ func GetMovieListByCid(cid int64, page *Page) []MovieBasicInfo {
return list
}
// GetHotMovieByPid 获取指定类别的热门影片
// GetHotMovieByPid 获取Pid指定类别的热门影片
func GetHotMovieByPid(pid int64, page *Page) []SearchInfo {
// 返回分页参数
//var count int64
@@ -452,6 +453,24 @@ func GetHotMovieByPid(pid int64, page *Page) []SearchInfo {
return s
}
// GetHotMovieByCid 获取当前分类下的热门影片
func GetHotMovieByCid(cid int64, page *Page) []SearchInfo {
// 返回分页参数
//var count int64
//db.Mdb.Model(&SearchInfo{}).Where("pid", pid).Count(&count)
//page.Total = int(count)
//page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
// 进行具体的信息查询
var s []SearchInfo
// 当前时间偏移一个月
t := time.Now().AddDate(0, -1, 0).Unix()
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("cid=? AND update_stamp > ?", cid, t).Order(" year DESC, hits DESC").Find(&s).Error; err != nil {
log.Println(err)
return nil
}
return s
}
// SearchFilmKeyword 通过关键字搜索库存中满足条件的影片名
func SearchFilmKeyword(keyword string, page *Page) []SearchInfo {
var searchList []SearchInfo

View File

@@ -36,7 +36,7 @@ func CreateUserTable() {
// 如果不存在则创建表 并设置自增ID初始值为10000
if !ExistUserTable() {
err := db.Mdb.AutoMigrate(u)
db.Mdb.Exec(fmt.Sprintf("alter table %s auto_Increment=%d", u.TableName(), config.UserIdInitialVal))
db.Mdb.Exec(fmt.Sprintf("alter table %s auto_Increment = %d", u.TableName(), config.UserIdInitialVal))
if err != nil {
log.Println("Create Table SearchInfo Failed: ", err)
}
@@ -81,6 +81,7 @@ func GetUserByNameOrEmail(userName string) *User {
return u
}
// GetUserById 通过id获取对应的用户信息
func GetUserById(id uint) User {
var user = User{Model: gorm.Model{ID: id}}
db.Mdb.First(&user)

View File

@@ -1,5 +1,7 @@
package system
import "time"
// SearchTagsVO 搜索标签请求参数
type SearchTagsVO struct {
Pid int64 `json:"pid"`
@@ -34,6 +36,12 @@ type FilmTaskOptions struct {
Name string `json:"name"`
}
type Option struct {
Name string `json:"name"`
Value any `json:"value"`
}
type OptionGroup map[string][]Option
// CollectParams 数据采集所需要的参数
type CollectParams struct {
Id string `json:"id"` // 资源站id
@@ -109,7 +117,18 @@ type PlayLinkVo struct {
LinkList []MovieUrlInfo `json:"linkList"`
}
// MovieDetailVo 影片详情数据, 播放源合并版
type MovieDetailVo struct {
MovieDetail
List []PlayLinkVo `json:"list"`
}
type RecordRequestVo struct {
OriginId string `json:"originId"` // 源站点ID
CollectType int `json:"collectType"` // 采集类型
Hour int `json:"hour"` // 采集时长
Status int `json:"status"` // 状态
BeginTime time.Time `json:"beginTime"` // 起始时间
EndTime time.Time `json:"endTime"` // 结束时间
Paging *Page `json:"paging"` // 分页参数
}

View File

@@ -12,4 +12,6 @@ func TableInIt() {
system.CreateSearchTable()
// 创建图片信息管理表
system.CreateFileTable()
// 创建采集失效记录表
system.CreateFailureRecordTable()
}

View File

@@ -21,20 +21,21 @@ func FilmSourceInit() {
return
}
var l []system.FilmSource = []system.FilmSource{
{Id: util.GenerateSalt(), Name: "HD(LZ)", Uri: `https://cj.lzcaiji.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(BF)", Uri: `https://bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true, Interval: 2500},
{Id: util.GenerateSalt(), Name: "HD(FF)", Uri: `http://cj.ffzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(OK)", Uri: `https://okzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(HM)", Uri: `https://json.heimuer.xyz/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(LY)", Uri: `https://360zy.com/api.php/provide/vod/at/json`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(YZ)", Uri: `https://api.1080zyku.com/inc/apijson.php`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(kk)", Uri: `https://kuaikan-api.com/api.php/provide/vod/from/kuaikan/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
{Id: util.GenerateSalt(), Name: "HD(SN)", Uri: `https://suoniapi.com/api.php/provide/vod/from/snm3u8/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true, Interval: 2000},
//{Id: util.GenerateSalt(), Name: "HD(LZ)", Uri: `https://cj.lziapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
//{Id: util.GenerateSalt(), Name: "HD(lzBk)", Uri: `https://cj.lzcaiji.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
//{Id: util.GenerateSalt(), Name: "HD(fs)", Uri: `https://www.feisuzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
//{Id: util.GenerateSalt(), Name: "HD(bfApp)", Uri: `http://app.bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: true},
//Id: util.GenerateSalt(), {Name: "HD(bfBk)", Uri: `http://by.bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false,CollectType:system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(LZ)", Uri: `https://cj.lziapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(BF)", Uri: `https://bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false, Interval: 2500},
{Id: util.GenerateSalt(), Name: "HD(FF)", Uri: `http://cj.ffzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(OK)", Uri: `https://okzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(HM)", Uri: `https://json.heimuer.xyz/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(LY)", Uri: `https://360zy.com/api.php/provide/vod/at/json`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(SN)", Uri: `https://suoniapi.com/api.php/provide/vod/from/snm3u8/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false, Interval: 2000},
{Id: util.GenerateSalt(), Name: "HD(DB)", Uri: `https://caiji.dbzy.tv/api.php/provide/vod/from/dbm3u8/at/josn/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(IK)", Uri: `https://ikunzyapi.com/api.php/provide/vod/at/json`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "WX(T2)", Uri: `https://api.wuxianzy.net/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "OK(BK)", Uri: `https://api.okzy.org/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "HD(HW)", Uri: `https://cjhwba.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false, Interval: 3000},
//{Id: util.GenerateSalt(), Name: "HD(lzBk)", Uri: `https://cj.lzcaiji.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "HD(fs)", Uri: `https://www.feisuzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "HD(bfBk)", Uri: `http://app.bfzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
}
err := system.SaveCollectSourceList(l)
if err != nil {
@@ -67,16 +68,28 @@ func CollectCrontabInit() {
}
// 将定时任务Id记录到Task中
task.Cid = cid
case 2:
cid, err := spider.AddFilmRecoverCron(task.Spec)
// 如果任务添加失败则直接返回错误信息
if err != nil {
log.Println("自动清理失败采集记录定时任务添加失败: ", err.Error())
continue
}
// 将定时任务Id记录到Task中
task.Cid = cid
}
system.UpdateFilmTask(task)
}
} else {
// 如果系统中不存在任何定时任务信息, 则添加默认的定时任务
// 1. 添加一条默认任务, 定时更新所有已启用站点的影片信息
// 生成任务信息
/*
如果系统中不存在任何定时任务信息, 则添加默认的定时任务
1. 添加一条默认任务, 定时更新所有已启用站点的影片信息
2. 添加一条默认任务, 定时处理采集失败的记录
3.生成任务信息
*/
task := system.FilmCollectTask{Id: util.GenerateSalt(), Time: config.DefaultUpdateTime, Spec: config.DefaultUpdateSpec,
Model: 0, State: false, Remark: "每20分钟执行一次已启用站点数据的自动更新"}
// 添加一条定时任务
// 添加一条定时任务-影片定时更新
cid, err := spider.AddAutoUpdateCron(task.Id, task.Spec)
// 如果任务添加失败则直接返回错误信息
if err != nil {
@@ -87,6 +100,21 @@ func CollectCrontabInit() {
task.Cid = cid
// 如果没有异常则将当前定时任务信息记录到redis中
system.SaveFilmTask(task)
// 添加一条定时任务-定期处理失败请求
recoverTask := system.FilmCollectTask{Id: util.GenerateSalt(), Time: 0, Spec: config.EveryWeekSpec,
Model: 2, State: false, Remark: "每周日凌晨4点清理一次采集失败的采集记录"}
// 添加一条定时任务-影片定时更新
cid, err = spider.AddFilmRecoverCron(recoverTask.Spec)
// 如果任务添加失败则直接返回错误信息
if err != nil {
log.Println("失败采集恢复定时任务添加失败: ", err.Error())
return
}
// 将定时任务Id记录到Task中
recoverTask.Cid = cid
// 如果没有异常则将当前定时任务信息记录到redis中
system.SaveFilmTask(recoverTask)
}
// 完成初始化后启动 Cron

View File

@@ -26,6 +26,7 @@ type RequestInfo struct {
Params url.Values `json:"param"` // 请求参数
Header http.Header `json:"header"` // 请求头数据
Resp []byte `json:"resp"` // 响应结果数据
Err string `json:"err"` // 错误信息
}
// RefererUrl 记录上次请求的url
@@ -95,6 +96,7 @@ func ApiGet(r *RequestInfo) {
// 处理请求参数
err := Client.Visit(fmt.Sprintf("%s?%s", r.Uri, r.Params.Encode()))
if err != nil {
r.Err = err.Error()
log.Println("获取数据失败: ", err)
}
}

View File

@@ -3,6 +3,7 @@ package db
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"server/config"
)
@@ -24,7 +25,7 @@ func InitMysql() (err error) {
SingularTable: true, //是否使用 结构体名称作为表名 (关闭自动变复数)
//NameReplacer: strings.NewReplacer("spider_", ""), // 替表名和字段中的 Me 为 空
},
//Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
})
return
}

View File

@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"log"
"math"
"net/url"
"server/config"
"server/model/collect"
@@ -126,7 +127,7 @@ func CollectCategory(s *system.FilmSource) {
}
}
// 影视详情采集
// collectFilm 影视详情采集 (单一源分页全采集)
func collectFilm(s *system.FilmSource, h, pg int) {
// 生成请求参数
r := util.RequestInfo{Uri: s.Uri, Params: url.Values{}}
@@ -139,6 +140,9 @@ func collectFilm(s *system.FilmSource, h, pg int) {
// 执行采集方法 获取影片详情list
list, err := spiderCore.GetFilmDetail(r)
if err != nil || len(list) <= 0 {
// 添加采集失败记录
fr := system.FailureRecord{OriginId: s.Id, OriginName: s.Name, Uri: s.Uri, CollectType: system.CollectVideo, PageNumber: pg, Hour: h, Cause: fmt.Sprintln(err), Status: 1}
system.SaveFailureRecord(fr)
log.Println("GetMovieDetail Error: ", err)
return
}
@@ -163,6 +167,41 @@ func collectFilm(s *system.FilmSource, h, pg int) {
}
}
// collectFilmById 采集指定ID的影片信息
func collectFilmById(ids string, s *system.FilmSource) {
// 生成请求参数
r := util.RequestInfo{Uri: s.Uri, Params: url.Values{}}
// 设置分页页数
r.Params.Set("pg", "1")
// 设置影片IDS参数信息
r.Params.Set("ids", ids)
// 执行采集方法 获取影片详情list
list, err := spiderCore.GetFilmDetail(r)
if err != nil || len(list) <= 0 {
log.Println("GetMovieDetail Error: ", err)
return
}
// 通过采集站 Grade 类型, 执行不同的存储逻辑
switch s.Grade {
case system.MasterCollect:
// 主站点 保存完整影片详情信息到 redis 和 mysql 中
if err = system.SaveDetail(list[0]); err != nil {
log.Println("SaveDetails Error: ", err)
}
// 如果主站点开启了图片同步, 则将图片url以及对应的mid存入ZSet集合中
if s.SyncPictures {
if err = system.SaveVirtualPic(conver.ConvertVirtualPicture(list)); err != nil {
log.Println("SaveVirtualPic Error: ", err)
}
}
case system.SlaveCollect:
// 附属站点 仅保存影片播放信息到redis
if err = system.SaveSitePlayList(s.Id, list); err != nil {
log.Println("SaveDetails Error: ", err)
}
}
}
// ConcurrentPageSpider 并发分页采集, 不限类型
func ConcurrentPageSpider(capacity int, s *system.FilmSource, h int, collectFunc func(s *system.FilmSource, hour, pageNumber int)) {
// 开启协程并发执行
@@ -191,7 +230,7 @@ func ConcurrentPageSpider(capacity int, s *system.FilmSource, h int, collectFunc
}
}()
}
for i := 0; i < config.MAXGoroutine; i++ {
for i := 0; i < GoroutineNum; i++ {
<-waitCh
}
}
@@ -229,7 +268,7 @@ func AutoCollect(h int) {
}
}
// ClearSpider 删除已采集的影片信息
// ClearSpider 删除所有已采集的影片信息
func ClearSpider() {
system.FilmZero()
}
@@ -242,6 +281,80 @@ func StarZero(h int) {
AutoCollect(h)
}
// CollectSingleFilm 通过影片唯一ID获取影片信息
func CollectSingleFilm(ids string) {
// 获取采集站列表信息
fl := system.GetCollectSourceList()
// 循环遍历所有采集站信息
for _, f := range fl {
// 目前仅对主站点进行处理
if f.Grade == system.MasterCollect && f.State {
collectFilmById(ids, &f)
return
}
}
}
// ======================================================= 采集拓展内容 =======================================================
// SingleRecoverSpider 二次采集
func SingleRecoverSpider(fr *system.FailureRecord) {
// 通过采集时长范围执行不同的采集方式
switch {
case fr.Hour > 168 && fr.Hour < 360:
// 将此记录之后的所有同类采集记录变更为已重试
system.ChangeRecord(fr, 0)
// 如果采集的内容是 7~15 天之内更新的内容,则采集此记录之后的所有更新内容
// 获取采集参数h, 采集时长变更为 原采集时长 + 采集记录距现在的时长
h := fr.Hour + int(math.Ceil(time.Since(fr.CreatedAt).Hours()))
// 对当前所有已启用的站点 更新最新 h 小时的内容
AutoCollect(h)
case fr.Hour < 0, fr.Hour > 4320:
// 将此记录状态修改为已重试
system.ChangeRecord(fr, 0)
// 如果采集的是 最近180天内更新的内容 或全部内容, 则只对当前一条记录进行二次采集
s := system.FindCollectSourceById(fr.OriginId)
collectFilm(s, fr.Hour, fr.PageNumber)
default:
// 其余范围,暂不处理
break
}
}
// FullRecoverSpider 扫描记录表中的失败记录, 并进行处理 (用于定时任务定期处理失败采集)
func FullRecoverSpider() {
/*
获取待处理的记录数据
1. 采集时长 > 168h (一周,7天) 状态-1 待处理, | 只获取满足条件的最早的待处理记录
2. 采集时长 > 4320h (半年,180天) 状态-1 待处理, | 获取满足条件的所有数据
*/
list := system.PendingRecord()
// 遍历记录信息切片, 针对不同时长进行不同处理
for _, fr := range list {
switch {
case fr.Hour > 0 && fr.Hour < 4320:
// 将此记录之后的所有同类采集记录变更为已重试
system.ChangeRecord(&fr, 0)
// 如果采集的内容是 0~180 天之内更新的内容,则采集此记录之后的所有更新内容
// 获取采集参数h, 采集时长变更为 原采集时长 + 采集记录距现在的时长
h := fr.Hour + int(math.Ceil(time.Since(fr.CreatedAt).Hours()))
// 对当前所有已启用的站点 更新最新 h 小时的内容
AutoCollect(h)
case fr.Hour < 0, fr.Hour > 4320:
// 将此记录状态修改为已重试
system.ChangeRecord(&fr, 0)
// 如果采集的是 180天之前更新的内容 或全部内容, 则只对当前一条记录进行二次采集
s := system.FindCollectSourceById(fr.OriginId)
collectFilm(s, fr.Hour, fr.PageNumber)
default:
// 其余范围,暂不处理
break
}
}
}
// ======================================================= 公共方法 =======================================================
// CollectApiTest 测试采集接口是否可用

View File

@@ -93,7 +93,7 @@ func (jc *JsonCollect) GetFilmDetail(r util.RequestInfo) (list []system.MovieDet
//details := system.DetailListInfo{}
// 如果返回数据为空则直接结束本次循环
if len(r.Resp) <= 0 {
err = errors.New("response is empty")
err = errors.New(r.Err)
return
}
// 序列化详情数据
@@ -132,6 +132,23 @@ func (jc *JsonCollect) GetSingleFilm(r util.RequestInfo, ids string) {
//
}
// FailureRecord 记录失败采集的相关信息, 用于后续采集重试操作
func (jc *JsonCollect) FailureRecord(r util.RequestInfo) {
// 记录采集失败时的采集参数
// 1. 采集站信息 (ID)
// 2. 采集参数, h 最新x小时影片, pg 页码
// 3. 将失败信息记录到redis ZSet集合中, score - time | member - data
}
// FilmDetailRetry 影片详情重试机制
func (jc *JsonCollect) FilmDetailRetry(r util.RequestInfo) {
}
// ------------------------------------------------- XML Collect -------------------------------------------------
// XmlCollect 处理返回值为XML格式的采集数据

View File

@@ -7,7 +7,6 @@ import (
"log"
"server/config"
"server/model/system"
"time"
)
var (
@@ -19,7 +18,7 @@ func CreateCron() *cron.Cron {
return cron.New(cron.WithSeconds())
}
// AddFilmUpdateCron 添加影片更新定时任务
// AddFilmUpdateCron 添加 指定站点的影片更新定时任务
func AddFilmUpdateCron(id, spec string) (cron.EntryID, error) {
// 校验 spec 表达式的有效性
if err := ValidSpec(spec); err != nil {
@@ -41,7 +40,7 @@ func AddFilmUpdateCron(id, spec string) (cron.EntryID, error) {
})
}
// AddAutoUpdateCron 自动更新定时任务
// AddAutoUpdateCron 添加 所有已启用站点的影片更新定时任务
func AddAutoUpdateCron(id, spec string) (cron.EntryID, error) {
// 校验 spec 表达式的有效性
if err := ValidSpec(spec); err != nil {
@@ -61,6 +60,19 @@ func AddAutoUpdateCron(id, spec string) (cron.EntryID, error) {
})
}
// AddFilmRecoverCron 失败采集记录处理
func AddFilmRecoverCron(spec string) (cron.EntryID, error) {
// 校验 spec 表达式的有效性
if err := ValidSpec(spec); err != nil {
return -99, errors.New(fmt.Sprint("定时任务添加失败,Cron表达式校验失败: ", err.Error()))
}
return CronCollect.AddFunc(spec, func() {
// 执行失败采集记录恢复
FullRecoverSpider()
log.Println("执行一次失败采集恢复任务")
})
}
// RemoveCron 删除定时任务
func RemoveCron(id cron.EntryID) {
// 通过定时任务EntryID移出对应的定时任务
@@ -69,8 +81,8 @@ func RemoveCron(id cron.EntryID) {
// GetEntryById 返回定时任务的相关时间信息
func GetEntryById(id cron.EntryID) cron.Entry {
log.Printf("%+v\n", CronCollect.Entries())
log.Println("", CronCollect.Entry(id).Next.Format(time.DateTime))
//log.Printf("CronInfo: %+v\n", CronCollect.Entries())
//log.Println("Corn Next Execute Time:", CronCollect.Entry(id).Next.Format(time.DateTime))
return CronCollect.Entry(id)
}

View File

@@ -72,6 +72,13 @@ func SetupRouter() *gin.Engine {
//collect.GET(`/star`, controller.CollectFilm)
collect.GET(`/del`, controller.FilmSourceDel)
collect.GET(`/options`, controller.GetNormalFilmSource)
collect.GET(`/record/list`, controller.FailureRecordList)
collect.GET(`/record/retry`, controller.CollectRecover)
collect.GET(`/record/retry/all`, controller.CollectRecoverAll)
collect.GET(`/record/clear/done`, controller.ClearDoneRecord)
collect.GET(`/record/clear/all`, controller.ClearAllRecord)
}
// 定时任务相关
@@ -91,6 +98,7 @@ func SetupRouter() *gin.Engine {
spiderRoute.POST(`/start`, controller.StarSpider)
spiderRoute.GET(`/zero`, controller.SpiderReset)
spiderRoute.GET(`/clear`, controller.ClearAllFilm)
spiderRoute.GET(`/update/single`, controller.SingleUpdateSpider)
spiderRoute.GET(`/class/cover`, controller.CoverFilmClass)
}
// filmManage 影视管理

View File

@@ -45,11 +45,26 @@ func (i *IndexLogic) IndexPage() map[string]interface{} {
// 2. 提供用于首页展示的顶级分类影片信息, 每分类 14条数据
var list []map[string]interface{}
for _, c := range tree.Children {
// 生成分页参数
page := system.Page{PageSize: 14, Current: 1}
movies := system.GetMovieListByPid(c.Id, &page)
// 获取当前分类的本月热门影片
HotMovies := system.GetHotMovieByPid(c.Id, &page)
item := map[string]interface{}{"nav": c, "movies": movies, "hot": HotMovies}
// 获取最近上映影片和本月热门影片
var movies []system.MovieBasicInfo
var hotMovies []system.SearchInfo
if c.Children != nil {
// 如果有子分类, 则通过Pid获取对应影片
// 获取当前分类的最新上映影片
movies = system.GetMovieListByPid(c.Id, &page)
// 获取当前分类的本月热门影片
hotMovies = system.GetHotMovieByPid(c.Id, &page)
} else {
// 如果当前分类为一级分类且没有子分类,则通过Cid获取对应数据
// 获取当前分类的最新上映影片
movies = system.GetMovieListByCid(c.Id, &page)
// 获取当前分类的本月热门影片
hotMovies = system.GetHotMovieByCid(c.Id, &page)
}
item := map[string]interface{}{"nav": c, "movies": movies, "hot": hotMovies}
list = append(list, item)
}
Info["content"] = list

View File

@@ -7,11 +7,12 @@ import (
"server/plugin/SystemInit"
"server/plugin/db"
"server/router"
"time"
)
func init() {
// 执行初始化前等待20s , 让mysql服务完成初始化指令
//time.Sleep(time.Second * 20)
time.Sleep(time.Second * 20)
//初始化redis客户端
err := db.InitRedisConn()
if err != nil {

View File

@@ -39,8 +39,18 @@ func CreateFailureRecordTable() {
// SaveFailureRecord 添加采集失效记录
func SaveFailureRecord(fl FailureRecord) {
if err := db.Mdb.Create(&fl).Error; err != nil {
log.Println("Add failure record failed:", err)
// 数据量不多但存在并发问题, 开启事务
err := db.Mdb.Transaction(func(tx *gorm.DB) error {
// 将采集失败信息存储到record表中
if err := tx.Create(&fl).Error; err != nil {
log.Println("Add failure record failed:", err)
return err
}
return nil
})
// 如果事务提交失败, 则输出相应信息, (存一份数据到Redis??)
if err != nil {
log.Println("Save failure record affairs failed:", err)
}
}

View File

@@ -435,7 +435,7 @@ func GetMovieListByCid(cid int64, page *Page) []MovieBasicInfo {
return list
}
// GetHotMovieByPid 获取指定类别的热门影片
// GetHotMovieByPid 获取Pid指定类别的热门影片
func GetHotMovieByPid(pid int64, page *Page) []SearchInfo {
// 返回分页参数
//var count int64
@@ -453,6 +453,24 @@ func GetHotMovieByPid(pid int64, page *Page) []SearchInfo {
return s
}
// GetHotMovieByCid 获取当前分类下的热门影片
func GetHotMovieByCid(cid int64, page *Page) []SearchInfo {
// 返回分页参数
//var count int64
//db.Mdb.Model(&SearchInfo{}).Where("pid", pid).Count(&count)
//page.Total = int(count)
//page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
// 进行具体的信息查询
var s []SearchInfo
// 当前时间偏移一个月
t := time.Now().AddDate(0, -1, 0).Unix()
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("cid=? AND update_stamp > ?", cid, t).Order(" year DESC, hits DESC").Find(&s).Error; err != nil {
log.Println(err)
return nil
}
return s
}
// SearchFilmKeyword 通过关键字搜索库存中满足条件的影片名
func SearchFilmKeyword(keyword string, page *Page) []SearchInfo {
var searchList []SearchInfo

View File

@@ -36,7 +36,7 @@ func CreateUserTable() {
// 如果不存在则创建表 并设置自增ID初始值为10000
if !ExistUserTable() {
err := db.Mdb.AutoMigrate(u)
db.Mdb.Exec(fmt.Sprintf("alter table %s auto_Increment = %s", u.TableName(), config.UserIdInitialVal))
db.Mdb.Exec(fmt.Sprintf("alter table %s auto_Increment = %d", u.TableName(), config.UserIdInitialVal))
if err != nil {
log.Println("Create Table SearchInfo Failed: ", err)
}
@@ -81,6 +81,7 @@ func GetUserByNameOrEmail(userName string) *User {
return u
}
// GetUserById 通过id获取对应的用户信息
func GetUserById(id uint) User {
var user = User{Model: gorm.Model{ID: id}}
db.Mdb.First(&user)

View File

@@ -29,6 +29,9 @@ func FilmSourceInit() {
{Id: util.GenerateSalt(), Name: "HD(LY)", Uri: `https://360zy.com/api.php/provide/vod/at/json`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(SN)", Uri: `https://suoniapi.com/api.php/provide/vod/from/snm3u8/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false, Interval: 2000},
{Id: util.GenerateSalt(), Name: "HD(DB)", Uri: `https://caiji.dbzy.tv/api.php/provide/vod/from/dbm3u8/at/josn/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{Id: util.GenerateSalt(), Name: "HD(IK)", Uri: `https://ikunzyapi.com/api.php/provide/vod/at/json`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "WX(T2)", Uri: `https://api.wuxianzy.net/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "OK(BK)", Uri: `https://api.okzy.org/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "HD(HW)", Uri: `https://cjhwba.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false, Interval: 3000},
//{Id: util.GenerateSalt(), Name: "HD(lzBk)", Uri: `https://cj.lzcaiji.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
//{Id: util.GenerateSalt(), Name: "HD(fs)", Uri: `https://www.feisuzyapi.com/api.php/provide/vod/`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},

View File

@@ -3,6 +3,7 @@ package db
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"server/config"
)
@@ -24,7 +25,7 @@ func InitMysql() (err error) {
SingularTable: true, //是否使用 结构体名称作为表名 (关闭自动变复数)
//NameReplacer: strings.NewReplacer("spider_", ""), // 替表名和字段中的 Me 为 空
},
//Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
})
return
}