collect failed manage

This commit is contained in:
mubai
2025-02-25 23:24:24 +08:00
parent b5b0889abe
commit a2f6e017b9
16 changed files with 574 additions and 236 deletions

View File

@@ -22,6 +22,7 @@
<span>采集管理</span>
</template>
<el-menu-item index="/manage/collect/index">影视采集</el-menu-item>
<el-menu-item index="/manage/collect/record">失效记录</el-menu-item>
</el-sub-menu>
<el-sub-menu index="/manage/cron">
<template #title>

View File

@@ -27,6 +27,7 @@ import FilmAdd from "../views/manage/film/FilmAdd.vue";
import CustomPlay from "../views/index/CustomPlay.vue";
import Banners from "../views/manage/system/Banners.vue";
import FilmHistory from "../views/index/FilmHistory.vue";
import FailureRecord from "../views/manage/collect/FailureRecord.vue";
// 2. 定义一个路由
@@ -54,6 +55,7 @@ const routes = [
children: [
{path: 'index', component: ManageIndex},
{path: 'collect/index', component: CollectManage},
{path: 'collect/record', component: FailureRecord},
{path: 'system/webSite', component: SiteConfig},
{path: 'system/banners', component: Banners},
{path: 'cron/index', component: CronManage},

View File

@@ -0,0 +1,180 @@
<template>
<div class="container">
<div class="content">
<el-table
:data="data.records" style="width: 100%" border size="default"
table-layout="auto" max-height="calc(68vh - 20px)"
row-key="id" fit
:row-class-name="'cus-tr'">
<el-table-column type="index" align="left" min-width="35px" label="序列">
<template #default="scope">
<span style="color: #8b40ff">{{ scope.row.ID }}</span>
</template>
</el-table-column>
<el-table-column prop="originId" align="center" label="采集站">
<template #default="scope">
<el-tag type="primary" disable-transitions>{{ scope.row.originName }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="originId" align="center" min-width="100px" label="采集源ID">
<template #default="scope">
<el-tag type="success" disable-transitions>{{ scope.row.originId }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="collectType" align="center" label="采集类型" show-overflow-tooltip>
<template #default="scope">
<el-tag type="success" disable-transitions>{{ scope.row.collectType == 0 ? '影片详情' : '未知' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="pageNumber" align="center" label="分页页码">
<template #default="scope">
<el-tag type="warning" disable-transitions>{{ scope.row.pageNumber }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="hour" align="center" label="采集时长">
<template #default="scope">
<el-tag type="warning" disable-transitions>{{ scope.row.hour }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="cause" align="center" label="失败原因" min-width="150px" >
<template #default="scope">
<el-tag type="danger" disable-transitions>{{ scope.row.cause }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" align="center" label="状态">
<template #default="scope">
<el-tag v-if="scope.row.status == 1" type="warning">待重试</el-tag>
<el-tag v-else type="success">已处理</el-tag>
</template>
</el-table-column>
<el-table-column prop="UpdatedAt" align="center" label="执行时间" min-width="100px" >
<template #default="scope">
<el-tag :type="`${scope.row.status == 1 ? 'warning':'success' }`" disable-transitions>{{ scope.row.timeFormat }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" min-width="100px">
<template #default="scope">
<el-tooltip content="采集重试" placement="top"><el-button type="success" :icon="RefreshRight" @click="collectRecover(scope.row.ID)" plain circle/></el-tooltip>
<el-tooltip content="删除记录" placement="top"><el-button type="danger" :icon="Delete" @click="delRecord(scope.row.ID)" plain circle/></el-tooltip>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination :page-sizes="[10, 20, 50, 100, 500]" background layout="prev, pager, next, sizes, total, jumper"
:total="data.page.total" v-model:page-size="data.page.pageSize"
v-model:current-page="data.page.current"
@change="getRecords" hide-on-single-page/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {Aim, Delete, Edit, RefreshRight} from "@element-plus/icons-vue";
import {fmt} from "../../../utils/format";
import {onMounted, reactive} from "vue";
import {ApiGet} from "../../../utils/request";
import {ElMessage} from "element-plus";
const data = reactive({
records: [],
page: {current: 1, pageCount: 0, pageSize: 10, total: 0},
params: {},
})
// 获取影片分页信息
const getRecords = () => {
let {current, pageSize} = data.page
let params = data.params
ApiGet(`/manage/collect/record/list`, {...params, current, pageSize}).then((resp: any) => {
if (resp.code === 0) {
resp.data.list.map((item: any) => {
// 对数据进行格式化处理
item.timeFormat = fmt.dateFormat(new Date(item.UpdatedAt).getTime())
return item
})
data.records = resp.data.list
data.page = resp.data.params.paging
} else {
ElMessage.error({message: resp.msg})
}
})
}
// 恢复采集, 对已采集失败的记录进行重试操作
const collectRecover = (id:number)=>{
ApiGet(`/manage/collect/record/retry`, {id:id}).then((resp: any) => {
if(resp.code === 0){
ElMessage.success({message: resp.msg})
} else{
ElMessage.error({message: resp.msg})
}
})
}
// 删除当前记录, 貌似不合理
const delRecord = (id:number)=>{
}
// 清除所有失败采集记录
const clearAllRecord = ()=>{
}
onMounted(() => {
// 获取分页数据
getRecords()
console.log(data)
})
</script>
<style scoped>
.content {
border: 1px solid #9b49e733;
background: var(--bg-light);
--el-color-primary: var(--paging-parmary-color);
}
.pagination {
margin: 20px auto;
max-width: 100%;
text-align: center;
padding-right: 50px;
}
:deep(.el-pagination) {
width: 100% !important;
justify-content: end;
--el-color-primary: var(--paging-parmary-color);
}
:deep(.el-pager li) {
--el-pagination-button-bg-color: var(--btn-bg-linght);
border: 1px solid var(--border-gray-color);
}
:deep(.el-pagination button) {
--el-disabled-bg-color: var(--btn-bg-linght);
--el-pagination-button-bg-color: var(--btn-bg-linght);
border: 1px solid var(--border-gray-color);
}
</style>

View File

@@ -51,7 +51,7 @@
table-layout="auto" max-height="calc(68vh - 20px)"
row-key="id"
:row-class-name="'cus-tr'">
<el-table-column type="index" min-width="50px" align="left" label="序号">
<el-table-column type="index" min-width="40px" align="left" label="序号">
<template #default="scope">
<span style="color: #8b40ff">{{ serialNum(scope.$index) }}</span>
</template>

View File

@@ -71,11 +71,6 @@ const (
DefaultUpdateSpec = "0 */20 * * * ?"
// DefaultUpdateTime 每次采集最近 3 小时内更新的影片
DefaultUpdateTime = 3
// FailureAllCollectKey 失败采集记录-全量采集记录
FailureAllCollectKey = "CollectRecord:Fail:%s"
// FailureUpdateCollectKey 失败采集记录-更新失败记录
FailureUpdateCollectKey = "CollectRecord:Fail:%s"
)
// -------------------------Web API相关redis key-----------------------------------

View File

@@ -0,0 +1,238 @@
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"server/logic"
"server/model/system"
"server/plugin/spider"
"strconv"
)
// ------------------------------------------------------ 影视采集 ------------------------------------------------------
// 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"))
// 分页参数
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
}
// 获取满足条件的分页数据
list := logic.CollectL.GetRecordList(params)
system.Success(gin.H{"params": params, "list": list}, "影片分页信息获取成功", 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)
}

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

@@ -0,0 +1,71 @@
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)
}
// 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
}

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

@@ -11,6 +11,7 @@ import (
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"` // 页码
@@ -43,14 +44,27 @@ func SaveFailureRecord(fl FailureRecord) {
}
// FailureRecordList 获取所有的采集失效记录
func FailureRecordList(page *Page) []FailureRecord {
var count int64
db.Mdb.Model(&FailureRecord{}).Count(&count)
page.Total = int(count)
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
func FailureRecordList(vo RecordRequestVo) []FailureRecord {
// 通过RecordRequestVo,生成查询条件
qw := db.Mdb.Model(&FailureRecord{})
if vo.OriginId != "" {
qw.Where("origin_id = ?", vo.OriginId)
}
//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 := db.Mdb.Limit(page.PageSize).Offset((page.Current - 1) * page.PageSize).Find(&list).Error; err != nil {
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
}
@@ -62,10 +76,23 @@ func FindRecordById(id uint) *FailureRecord {
var fr FailureRecord
fr.ID = id
// 通过ID查询对应的数据
db.Mdb.First(fr)
db.Mdb.First(&fr)
return &fr
}
// 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对应的失败记录

View File

@@ -109,7 +109,16 @@ 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"` // 状态
Paging *Page `json:"paging"` // 分页参数
}

View File

@@ -27,14 +27,12 @@ func FilmSourceInit() {
{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(YZ)", Uri: `https://api.1080zyku.com/inc/apijson.php`, ResultModel: system.JsonResult, Grade: system.SlaveCollect, SyncPictures: false, CollectType: system.CollectVideo, State: false},
{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: 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(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(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(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(bfApp)", Uri: `http://app.bfzyapi.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://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(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 {

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

@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"log"
"math"
"net/url"
"server/config"
"server/model/collect"
@@ -140,7 +141,7 @@ func collectFilm(s *system.FilmSource, h, pg int) {
list, err := spiderCore.GetFilmDetail(r)
if err != nil || len(list) <= 0 {
// 添加采集失败记录
fr := system.FailureRecord{OriginId: s.Id, Uri: s.Uri, CollectType: system.CollectVideo, PageNumber: pg, Hour: h, Cause: err.Error(), Status: 1}
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
@@ -294,6 +295,33 @@ func CollectSingleFilm(ids string) {
}
}
// ======================================================= 采集拓展内容 =======================================================
// 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
}
}
// ======================================================= 公共方法 =======================================================
// 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
}
// 序列化详情数据

View File

@@ -72,6 +72,9 @@ 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)
}
// 定时任务相关