mirror of
https://github.com/ProudMuBai/GoFilm.git
synced 2026-04-10 00:17:30 +08:00
update docker deploy
This commit is contained in:
27
README.md
27
README.md
@@ -114,10 +114,29 @@ GoFilm
|
||||
|
||||
|
||||
|
||||
## 项目说明
|
||||
## 起源
|
||||
|
||||
从正式接触编程语言到第一次动手敲代码, , 当时有动手做一些东西的想法,也正是在那时喜欢追番迷二次元, 曾想过做一个自己的动漫站,
|
||||
|
||||
但因为知识面匮乏, 总是在进行到某一步时就会遇到一些盲区, 从最开始的静态页面到后面的伪数据, 也实现过一些当时能做到的部分,
|
||||
|
||||
后面慢慢学习的过程中也渐渐遗忘了这个想法, 但因为一些偶然的因素, 想要做一个自己的开源项目, 于是就从零开始慢慢实现并完善了这个
|
||||
|
||||
影视站的各个部分, 期间也一点点修改颠覆了一些最开始的思路, 但目前主体功能基本完善, 后续也会定期进行一些bug修复和新功能的更新
|
||||
|
||||
如有发现Bug, 或者有好的建议, 可以进行反馈, 欢迎各位大佬来指点一二
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## JetBrains 开源证书
|
||||
|
||||
感谢Jetbrains提供的免费开源许可, 项目开发中使用GoLang和WebStam让编程变得更加的便捷高效.
|
||||
|
||||
|
||||
|
||||
<a href="https://www.jetbrains.com/?from=GoFilm" target="_blank"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg" alt="JetBrains Logo (Main) logo."></a>
|
||||
|
||||
本项目出于个人对于学习技术栈的一次实践, 也算是完成最初学习时想做却做不了的一个念想
|
||||
|
||||
后续可能会陆续进行一些修改和完善, 项目规范性可能没有那么强, 可能也存在一些问题
|
||||
|
||||
如有发现Bug, 或者有好的建议, 可以进行反馈, 欢迎各位大佬来指定一二
|
||||
|
||||
2
client/components.d.ts
vendored
2
client/components.d.ts
vendored
@@ -21,8 +21,6 @@ declare module '@vue/runtime-core' {
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
FilmList: typeof import('./src/components/FilmList.vue')['default']
|
||||
Footer: typeof import('./src/components/Footer.vue')['default']
|
||||
Header: typeof import('./src/components/Header.vue')['default']
|
||||
|
||||
@@ -1,32 +1,63 @@
|
||||
<template>
|
||||
<div class="c_content">
|
||||
<div class="item" v-for="item in list" :style="{width: `calc(${ list.length <= 12 ? 16 : 14}% - 16px)`}">
|
||||
<a :href="`/filmDetail?link=${item.id}`" class="default_image link_content">
|
||||
<div class="tag_group">
|
||||
<span class="cus_tag ">{{ item.year ? item.year.slice(0, 4) : '未知' }}</span>
|
||||
<span class="cus_tag ">{{ item.cName }}</span>
|
||||
<span class="cus_tag ">{{ item.area.split(',')[0] }}</span>
|
||||
<div class="c_content" v-if="true">
|
||||
<div class="item" v-for="item in d.list" :style="{width: `calc(${d.width-1}%)`}">
|
||||
<div v-if="item.id != -99">
|
||||
<a :href="`/filmDetail?link=${item.id}`" class="default_image link_content">
|
||||
<div class="tag_group">
|
||||
<span class="cus_tag ">{{ item.year ? item.year.slice(0, 4) : '未知' }}</span>
|
||||
<span class="cus_tag ">{{ item.cName }}</span>
|
||||
<span class="cus_tag ">{{ item.area.split(',')[0] }}</span>
|
||||
</div>
|
||||
<span class="cus_remark hidden-md-and-up">{{ item.remarks }}</span>
|
||||
<img :src="item.picture" :alt="item.name?.split('[')[0]" @error="handleImg">
|
||||
</a>
|
||||
<a :href="`/filmDetail?link=${item.id}`" class="content_text_tag">{{ item.name.split("[")[0] }}</a>
|
||||
<span class="cus_remark hidden-md-and-down">{{ item.remarks }}</span>
|
||||
</div>
|
||||
<span class="cus_remark hidden-md-and-up">{{ item.remarks }}</span>
|
||||
<img :src="item.picture" :alt="item.name.split('[')[0]" @error="handleImg">
|
||||
</a>
|
||||
<a :href="`/filmDetail?link=${item.id}`" class="content_text_tag">{{ item.name.split("[")[0] }}</a>
|
||||
<span class="cus_remark hidden-md-and-down">{{ item.remarks }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {defineProps} from 'vue'
|
||||
import {defineProps, onMounted, reactive, watch, watchEffect} from 'vue'
|
||||
|
||||
defineProps({
|
||||
list: Array
|
||||
const props = defineProps({
|
||||
list: Array,
|
||||
col: Number,
|
||||
})
|
||||
const d = reactive({
|
||||
col: 0,
|
||||
list: Array,
|
||||
width: 0,
|
||||
})
|
||||
|
||||
// 图片加载失败事件
|
||||
const handleImg = (e: Event) => {
|
||||
e.target.style.display = "none"
|
||||
}
|
||||
|
||||
// 监听父组件传递的参数的变化
|
||||
watchEffect(()=>{
|
||||
// 首先获取当前设备类型
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
let isMobile = /mobile|android|iphone|ipad|phone/i.test(userAgent)
|
||||
// 如果是PC, 为防止flex布局最后一行元素不足出现错位, 使用空元素补齐list
|
||||
let c = isMobile ? 3 : props.col? props.col: 0
|
||||
let l:any= props.list
|
||||
let len = l.length
|
||||
d.width = isMobile ? 31 : Math.floor(100 / c)
|
||||
if (len % c !=0) {
|
||||
for (let i = 0; i < c - len %c ; i++) {
|
||||
let temp:any = {...l[0] as any}
|
||||
temp.id = -99
|
||||
l.push(temp)
|
||||
}
|
||||
}
|
||||
d.list = l
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -42,12 +73,12 @@ const handleImg = (e: Event) => {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
justify-content: start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.c_content .item {
|
||||
flex-basis: calc(33% - 7px);
|
||||
max-width: 33%;
|
||||
/* flex-basis: calc(33% - 7px);
|
||||
max-width: 33%;*/
|
||||
margin: 0 4px 20px 4px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
@@ -110,11 +141,11 @@ const handleImg = (e: Event) => {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
justify-content: start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.c_content .item {
|
||||
margin: 0 10px 20px 10px;
|
||||
margin-bottom: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="relate_container">
|
||||
<p class="title">相关推荐</p>
|
||||
<FilmList :list="relateList"/>
|
||||
<FilmList :col="7" :list="relateList"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -11,23 +11,23 @@
|
||||
<div class="news">
|
||||
<div class="c_nav">
|
||||
<span class="c_nav_text silver">最新上映</span>
|
||||
<span class="c_nav_more ">更多<b class="iconfont icon-more"/></span>
|
||||
<a :href="`/filmClassifySearch?Pid=${d.title.id}&Sort=release_stamp`" class="c_nav_more ">更多<b class="iconfont icon-more"/></a>
|
||||
</div>
|
||||
<FilmList :list="d.content.news"/>
|
||||
<FilmList :col="7" :list="d.content.news"/>
|
||||
</div>
|
||||
<div class="news">
|
||||
<div class="c_nav">
|
||||
<span class="c_nav_text silver">排行榜</span>
|
||||
<span class="c_nav_more ">更多<b class="iconfont icon-more"/></span>
|
||||
<a :href="`/filmClassifySearch?Pid=${d.title.id}&Sort=hits`" class="c_nav_more ">更多<b class="iconfont icon-more"/></a>
|
||||
</div>
|
||||
<FilmList :list="d.content.top"/>
|
||||
<FilmList :col="7" :list="d.content.top"/>
|
||||
</div>
|
||||
<div class="news">
|
||||
<div class="c_nav">
|
||||
<span class="c_nav_text silver">最近更新</span>
|
||||
<span class="c_nav_more ">更多<b class="iconfont icon-more"/></span>
|
||||
<a :href="`/filmClassifySearch?Pid=${d.title.id}&Sort=update_stamp`" class="c_nav_more ">更多<b class="iconfont icon-more"/></a>
|
||||
</div>
|
||||
<FilmList :list="d.content.recent"/>
|
||||
<FilmList :col="7" :list="d.content.recent"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,7 +61,7 @@ const getFilmData = () => {
|
||||
d.title = resp.data.title
|
||||
d.content = resp.data.content
|
||||
} else {
|
||||
ElMessage.error({message: "请先输入影片名称关键字再进行搜索", duration: 1000})
|
||||
ElMessage.error({message: "影片分类首页数据获取失败,请稍后刷新重试", duration: 1000})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -87,9 +87,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.c_nav_more {
|
||||
//font-size: 14px;
|
||||
background: #25252b;
|
||||
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</div>
|
||||
|
||||
<!--影片列表展示-->
|
||||
<FilmList :list="d.list"/>
|
||||
<FilmList :col="7" :list="d.list"/>
|
||||
<!--分页展示区域-->
|
||||
<div class="pagination_container ">
|
||||
<el-pagination background layout="prev, pager, next"
|
||||
@@ -106,7 +106,7 @@ const getFilmData = () => {
|
||||
d.search = resp.data.search
|
||||
d.searchParams = resp.data.params
|
||||
} else {
|
||||
ElMessage.error({message: "请先输入影片名称关键字再进行搜索", duration: 1000})
|
||||
ElMessage.error({message: "影片搜索结果异常,请稍后刷新重试", duration: 1000})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -164,7 +164,6 @@ onMounted(() => {
|
||||
color: rgba(255,255,255,0.35);
|
||||
border-radius: 6px;
|
||||
margin-right: 12px;
|
||||
//padding: 3px 0;
|
||||
}
|
||||
.t_title b{
|
||||
color: rgba(255,255,255,0.15);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="film" v-show="data.loading">
|
||||
<!-- hidden-sm-and-up 移动端title -->
|
||||
<!-- 移动端title -->
|
||||
<div class="hidden-sm-and-up">
|
||||
<div class="title_mt ">
|
||||
<a class="picture_mt" href="" :style="{backgroundImage: `url('${data.detail.picture}')`}"></a>
|
||||
@@ -30,7 +30,7 @@
|
||||
<h2>{{ data.detail.name }}</h2>
|
||||
<ul class="tags">
|
||||
<li class="t_c">
|
||||
<a :href="`/categoryFilm?pid=${data.detail.pid}`">
|
||||
<a :href="`/filmClassifySearch?Pid=${data.detail.pid}&Category=${data.detail.cid}`">
|
||||
<el-icon>
|
||||
<Promotion/>
|
||||
</el-icon>
|
||||
@@ -98,7 +98,7 @@
|
||||
import {useRouter} from "vue-router";
|
||||
import {onBeforeMount, reactive, ref,} from "vue";
|
||||
import {ApiGet} from "../../utils/request";
|
||||
import {ElMessage, ElLoading} from 'element-plus'
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {Promotion, CaretRight} from "@element-plus/icons-vue";
|
||||
import RelateList from "../../components/RelateList.vue";
|
||||
// 获取路由对象
|
||||
@@ -147,7 +147,6 @@ const data = reactive({
|
||||
const handleLongText = (t: string): string => {
|
||||
let res = ''
|
||||
t.split(',').forEach((s, i) => {
|
||||
console.log(s)
|
||||
if (i < 3) {
|
||||
res += `${s} `
|
||||
}
|
||||
@@ -166,7 +165,6 @@ onBeforeMount(() => {
|
||||
data.relate = resp.data.relate
|
||||
// 处理过长数据
|
||||
data.detail.descriptor.actor = handleLongText(data.detail.descriptor.actor)
|
||||
console.log(handleLongText(data.detail.descriptor.actor))
|
||||
data.detail.descriptor.director = handleLongText(data.detail.descriptor.director)
|
||||
data.loading = true
|
||||
} else {
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="cus_content">
|
||||
<el-col :md="24" :lg="20" :xl="20" class="cus_content">
|
||||
<el-col :md="24" :lg="20" :xl="20" class="cus_content">
|
||||
<!--影片列表-->
|
||||
<FilmList :list="item.movies.slice(0,12)"/>
|
||||
<FilmList :col="6" :list="item.movies.slice(0,12)"/>
|
||||
</el-col>
|
||||
<el-col :md="0" :lg="4" :xl="4" class="hidden-md-and-down content_right">
|
||||
<h3 class="hot_title">🔥热播{{item.nav.name}}</h3>
|
||||
@@ -128,6 +128,7 @@ a {
|
||||
|
||||
.content_right {
|
||||
width: 100%;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.content_right_item {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
film/data/nginx/html/assets/index-de4c7ff5.css
Normal file
1
film/data/nginx/html/assets/index-de4c7ff5.css
Normal file
File diff suppressed because one or more lines are too long
@@ -10,9 +10,9 @@
|
||||
<meta name="referrer" content="never">
|
||||
<meta charset="UTF-8"/>
|
||||
<title>(╥﹏╥)</title>
|
||||
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_3992367_aj8j1lxiqyw.css">
|
||||
<script type="module" crossorigin src="/assets/index-b073fe3a.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-36468467.css">
|
||||
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_3992367_xtm26gd5aa.css">
|
||||
<script type="module" crossorigin src="/assets/index-984712d6.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-de4c7ff5.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
daemonize no
|
||||
requirepass root
|
||||
appendonly yes
|
||||
tcp-keepalive 300
|
||||
tcp-keepalive 300
|
||||
stop-writes-on-bgsave-error no
|
||||
@@ -5,10 +5,11 @@ services:
|
||||
container_name: film_nginx
|
||||
image: nginx
|
||||
ports:
|
||||
- "3600:80"
|
||||
- "80:80"
|
||||
volumes:
|
||||
- /opt/film/data/nginx/html:/usr/share/nginx/html
|
||||
- /opt/film/data/nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
- /opt/film/data/nginx/logs:/var/log/nginx
|
||||
networks:
|
||||
- film-network
|
||||
depends_on:
|
||||
|
||||
@@ -81,3 +81,70 @@ server
|
||||
1. 修改 /server/plugin/db 目录下的 mysql.go 和 redis.go 中的连接地址和用户名密码
|
||||
2. 在 server 目录下执行 `go run main.go`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 数据库信息简介
|
||||
|
||||
#### 1.Mysql
|
||||
|
||||
> 连接信息(以docker compose部署为例) :
|
||||
|
||||
```yaml
|
||||
mysql:
|
||||
ip: 部署的服务器IP
|
||||
port: 3610
|
||||
username: root
|
||||
password: root
|
||||
database: FilmSite
|
||||
```
|
||||
|
||||
> 数据库结构
|
||||
|
||||
- 数据库: FilmSite
|
||||
- 数据表 search
|
||||
|
||||
> search 表 (用于记录影片的相关检索信息, 主要用于影片的 搜索, 分类, 排序 等)
|
||||
|
||||
| 字段名称 | 类型 | 字段释义 |
|
||||
| ------------ | -------- | ---------------------- |
|
||||
| id | bigint | 自增主键 |
|
||||
| created_at | datetime | 记录创建时间 |
|
||||
| updated_at | datetime | 记录更新时间 |
|
||||
| deleted_at | datetime | 逻辑删除字段 |
|
||||
| mid | bigint | 影片ID |
|
||||
| cid | bigint | 二级分类ID |
|
||||
| pid | bigint | 一级分类ID |
|
||||
| name | varchar | 影片名称 |
|
||||
| sub_title | varchar | 子标题(影片别名) |
|
||||
| c_name | varchar | 分类名称 |
|
||||
| class_tag | varchar | 剧情标签 |
|
||||
| area | varchar | 地区 |
|
||||
| language | varchar | 语言 |
|
||||
| year | bigint | 上映年份 |
|
||||
| initial | varchar | 首字母 |
|
||||
| score | double | 豆瓣评分 |
|
||||
| update_stamp | bigint | 影片更新时间戳 |
|
||||
| hits | bigint | 热度(播放次数) |
|
||||
| state | varchar | 状态(正片) |
|
||||
| remarks | varchar | 更新状态(完结 \| xx集) |
|
||||
| release_data | bigint | 上映时间戳 |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#### 2.Redis
|
||||
|
||||
> 连接信息(以docker compose部署为例) :
|
||||
|
||||
```yaml
|
||||
## 部署时默认使用如下信息
|
||||
redis:
|
||||
ip: 部署的服务器IP
|
||||
port: 3620
|
||||
password: root
|
||||
DB: 0 ##使用的redis数据库为0号库
|
||||
```
|
||||
|
||||
|
||||
@@ -10,6 +10,18 @@ const (
|
||||
// MAXGoroutine max goroutine, 执行spider中对协程的数量限制
|
||||
MAXGoroutine = 10
|
||||
|
||||
// CornMovieUpdate 影片更新定时任务间隔
|
||||
CornMovieUpdate = "0 0/20 * * * ?"
|
||||
// UpdateInterval 获取最近几小时更新的影片 (h 小时) 默认3小时
|
||||
UpdateInterval = "3"
|
||||
// CornUpdateAll 每月28执行一次清库更新
|
||||
CornUpdateAll = "0 0 2 28 * ?"
|
||||
|
||||
// SpiderCipher 设置Spider触发指令
|
||||
SpiderCipher = "Life in a different world from zero"
|
||||
|
||||
// -------------------------redis key-----------------------------------
|
||||
|
||||
// CategoryTreeKey 分类树 key
|
||||
CategoryTreeKey = "CategoryTree"
|
||||
CategoryTreeExpired = time.Hour * 24 * 90
|
||||
@@ -35,18 +47,12 @@ const (
|
||||
// SearchInfoTemp redis暂存检索数据信息
|
||||
SearchInfoTemp = "Search:SearchInfoTemp"
|
||||
|
||||
// CornMovieUpdate 影片更新定时任务间隔
|
||||
CornMovieUpdate = "0 0/20 * * * ?"
|
||||
// UpdateInterval 获取最近几小时更新的影片 (h 小时) 默认3小时
|
||||
UpdateInterval = "3"
|
||||
// CornUpdateAll 每月28执行一次清库更新
|
||||
CornUpdateAll = "0 0 2 28 * ?"
|
||||
|
||||
// SpiderCipher 设置Spider触发指令
|
||||
SpiderCipher = "Life in a different world from zero"
|
||||
SearchTitle = "Search:Pid%d:Title"
|
||||
SearchTag = "Search:Pid%d:%s"
|
||||
)
|
||||
|
||||
/*API相关redis key*/
|
||||
|
||||
const (
|
||||
IndexCacheKey = "IndexCache"
|
||||
)
|
||||
@@ -62,4 +68,4 @@ const (
|
||||
RedisAddr = `redis:6379`
|
||||
RedisPassword = `root`
|
||||
RedisDBNo = 0
|
||||
)
|
||||
)
|
||||
@@ -113,7 +113,81 @@ func SearchFilm(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// FilmCategory 获取指定分类的影片分页数据,
|
||||
// FilmTagSearch 通过tag获取满足条件的对应影片
|
||||
func FilmTagSearch(c *gin.Context) {
|
||||
params := model.SearchTagsVO{}
|
||||
pidStr := c.DefaultQuery("Pid", "")
|
||||
cidStr := c.DefaultQuery("Category", "")
|
||||
yStr := c.DefaultQuery("Year", "")
|
||||
if pidStr == "" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusFailed,
|
||||
"message": "缺少分类信息",
|
||||
})
|
||||
return
|
||||
}
|
||||
params.Pid, _ = strconv.ParseInt(pidStr, 10, 64)
|
||||
params.Cid, _ = strconv.ParseInt(cidStr, 10, 64)
|
||||
params.Plot = c.DefaultQuery("Plot", "")
|
||||
params.Area = c.DefaultQuery("Area", "")
|
||||
params.Language = c.DefaultQuery("Language", "")
|
||||
params.Year, _ = strconv.ParseInt(yStr, 10, 64)
|
||||
params.Sort = c.DefaultQuery("Sort", "update_stamp")
|
||||
|
||||
// 设置分页信息
|
||||
currentStr := c.DefaultQuery("current", "1")
|
||||
current, _ := strconv.Atoi(currentStr)
|
||||
page := model.Page{PageSize: 49, Current: current}
|
||||
logic.IL.GetFilmsByTags(params, &page)
|
||||
// 获取当前分类Title
|
||||
// 返回对应信息
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"title": logic.IL.GetPidCategory(params.Pid).Category,
|
||||
"list": logic.IL.GetFilmsByTags(params, &page),
|
||||
"search": logic.IL.SearchTags(params.Pid),
|
||||
"params": map[string]string{
|
||||
"Pid": pidStr,
|
||||
"Category": cidStr,
|
||||
"Plot": params.Plot,
|
||||
"Area": params.Area,
|
||||
"Language": params.Language,
|
||||
"Year": yStr,
|
||||
"Sort": params.Sort,
|
||||
},
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
}
|
||||
|
||||
// FilmClassify 影片分类首页数据展示
|
||||
func FilmClassify(c *gin.Context) {
|
||||
pidStr := c.DefaultQuery("Pid", "")
|
||||
if pidStr == "" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusFailed,
|
||||
"message": "缺少分类信息",
|
||||
})
|
||||
return
|
||||
}
|
||||
// 1. 顶部Title数据
|
||||
pid, _ := strconv.ParseInt(pidStr, 10, 64)
|
||||
title := logic.IL.GetPidCategory(pid)
|
||||
// 2. 设置分页信息
|
||||
page := model.Page{PageSize: 21, Current: 1}
|
||||
// 3. 获取当前分类下的 最新上映, 排行榜, 最近更新 影片信息
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"title": title,
|
||||
"content": logic.IL.GetFilmClassify(pid, &page),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
}
|
||||
|
||||
// FilmCategory 获取指定分类的影片分页数据,(已弃用)
|
||||
func FilmCategory(c *gin.Context) {
|
||||
// 1.1 首先获取Cid 二级分类id是否存在
|
||||
cidStr := c.DefaultQuery("cid", "")
|
||||
@@ -142,6 +216,7 @@ func FilmCategory(c *gin.Context) {
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(pid, "pid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
@@ -154,7 +229,10 @@ func FilmCategory(c *gin.Context) {
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(cid, "cid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
|
||||
// 获取请求参数
|
||||
}
|
||||
|
||||
@@ -150,6 +150,12 @@ func (i *IndexLogic) RelateMovie(detail model.MovieDetail, page *model.Page) []m
|
||||
return model.GetRelateMovieBasicInfo(search, page)
|
||||
}
|
||||
|
||||
// SearchTags 整合对应分类的搜索tag
|
||||
func (i *IndexLogic) SearchTags(pid int64) map[string]interface{} {
|
||||
// 通过pid 获取对应分类的 tags
|
||||
return model.GetSearchTag(pid)
|
||||
}
|
||||
|
||||
/*
|
||||
将多个站点的对应影视播放源追加到主站点播放列表中
|
||||
1. 将主站点影片的name 和 subtitle 进行处理添加到用于匹配对应播放源的map中
|
||||
@@ -192,3 +198,25 @@ func multipleSource(detail *model.MovieDetail) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// GetFilmsByTags 通过searchTag 返回满足条件的分页影片信息
|
||||
func (i *IndexLogic) GetFilmsByTags(st model.SearchTagsVO, page *model.Page) []model.MovieBasicInfo {
|
||||
// 获取满足条件的影片id 列表
|
||||
sl := model.GetSearchInfosByTags(st, page)
|
||||
// 通过key 获取对应影片的基本信息
|
||||
return model.GetBasicInfoBySearchInfos(sl...)
|
||||
}
|
||||
|
||||
// GetFilmClassify 通过Pid返回当前所属分类下的首页展示数据
|
||||
func (i *IndexLogic) GetFilmClassify(pid int64, page *model.Page) map[string]interface{} {
|
||||
res := make(map[string]interface{})
|
||||
// 最新上映 (上映时间)
|
||||
res["news"] = model.GetMovieListBySort(0, pid, page)
|
||||
// 排行榜 (暂定为热度排行)
|
||||
res["top"] = model.GetMovieListBySort(1, pid, page)
|
||||
// 最近更新 (更新时间)
|
||||
res["recent"] = model.GetMovieListBySort(2, pid, page)
|
||||
|
||||
return res
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import (
|
||||
"server/plugin/db"
|
||||
"server/plugin/spider"
|
||||
"server/router"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 执行初始化前等待20s , 让mysql服务完成初始化指令
|
||||
//time.Sleep(time.Second * 20)
|
||||
time.Sleep(time.Second * 20)
|
||||
//初始化redis客户端
|
||||
err := db.InitRedisConn()
|
||||
if err != nil {
|
||||
|
||||
@@ -41,3 +41,15 @@ func ExistsCategoryTree() bool {
|
||||
}
|
||||
return exists == 1
|
||||
}
|
||||
|
||||
// GetChildrenTree 根据影片Id获取对应分类的子分类信息
|
||||
func GetChildrenTree(id int64) []*CategoryTree {
|
||||
tree := GetCategoryTree()
|
||||
for _, t := range tree.Children {
|
||||
if t.Id == id {
|
||||
return t.Children
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
@@ -89,27 +89,7 @@ type MovieDetail struct {
|
||||
MovieDescriptor `json:"descriptor"` //影片描述信息
|
||||
}
|
||||
|
||||
// SaveMoves 保存影片分页请求list
|
||||
func SaveMoves(list []Movie) (err error) {
|
||||
// 整合数据
|
||||
for _, m := range list {
|
||||
//score, _ := time.ParseInLocation(time.DateTime, m.Time, time.Local)
|
||||
movie, _ := json.Marshal(m)
|
||||
// 以Cid为目录为集合进行存储, 便于后续搜索, 以影片id为分值进行存储 例 MovieList:Cid%d
|
||||
err = db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.MovieListInfoKey, m.Cid), redis.Z{Score: float64(m.Id), Member: movie}).Err()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// AllMovieInfoKey 获取redis中所有的影视列表信息key MovieList:Cid
|
||||
func AllMovieInfoKey() []string {
|
||||
return db.Rdb.Keys(db.Cxt, fmt.Sprint("MovieList:Cid*")).Val()
|
||||
}
|
||||
|
||||
// GetMovieListByKey 获取指定分类的影片列表数据
|
||||
func GetMovieListByKey(key string) []string {
|
||||
return db.Rdb.ZRange(db.Cxt, key, 0, -1).Val()
|
||||
}
|
||||
// ===================================Redis数据交互========================================================
|
||||
|
||||
// SaveDetails 保存影片详情信息到redis中 格式: MovieDetail:Cid?:Id?
|
||||
func SaveDetails(list []MovieDetail) (err error) {
|
||||
@@ -122,15 +102,13 @@ func SaveDetails(list []MovieDetail) (err error) {
|
||||
err = db.Rdb.Set(db.Cxt, fmt.Sprintf(config.MovieDetailKey, detail.Cid, detail.Id), data, config.CategoryTreeExpired).Err()
|
||||
// 2. 同步保存简略信息到redis中
|
||||
SaveMovieBasicInfo(detail)
|
||||
// 3. 保存Search检索信息到redis, 暂时搁置
|
||||
//if err == nil {
|
||||
// // 转换 detail信息
|
||||
// searchInfo := ConvertSearchInfo(detail)
|
||||
// // 放弃redis进行检索, 多条件处理不方便
|
||||
// //err = AddSearchInfo(searchInfo)
|
||||
// // 只存储用于检索对应影片的关键字信息
|
||||
// SearchKeyword(searchInfo)
|
||||
//}
|
||||
// 3. 保存 Search tag redis中
|
||||
if err == nil {
|
||||
// 转换 detail信息
|
||||
searchInfo := ConvertSearchInfo(detail)
|
||||
// 只存储用于检索对应影片的关键字信息
|
||||
SaveSearchTag(searchInfo)
|
||||
}
|
||||
|
||||
}
|
||||
// 保存一份search信息到mysql, 批量存储
|
||||
@@ -175,7 +153,7 @@ func SaveSitePlayList(siteName string, list []MovieDetail) (err error) {
|
||||
continue
|
||||
}
|
||||
// 如果DbId不为0, 则以dbID作为key进行hash额外存储一次
|
||||
if d.DbId > 0 {
|
||||
if d.DbId != 0 {
|
||||
res[GenerateHashKey(d.DbId)] = string(data)
|
||||
}
|
||||
res[GenerateHashKey(d.Name)] = string(data)
|
||||
@@ -189,108 +167,6 @@ func SaveSitePlayList(siteName string, list []MovieDetail) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// AddSearchInfo 将影片关键字信息整合后存入search 集合中
|
||||
func AddSearchInfo(searchInfo SearchInfo) (err error) {
|
||||
// 片名 Name 分类 CName 类别标签 classTag 地区 Area 语言 Language 年份 Year 首字母 Initial, 排序
|
||||
data, _ := json.Marshal(searchInfo)
|
||||
// 时间排序 score -->时间戳 DbId 排序 --> 热度, 评分排序 DbScore
|
||||
err = db.Rdb.ZAdd(db.Cxt, fmt.Sprintf("%s:Pid%d", config.SearchTimeListKey, searchInfo.Pid), redis.Z{Score: float64(searchInfo.UpdateStamp), Member: data}).Err()
|
||||
err = db.Rdb.ZAdd(db.Cxt, fmt.Sprintf("%s:Pid%d", config.SearchScoreListKey, searchInfo.Pid), redis.Z{Score: searchInfo.Score, Member: data}).Err()
|
||||
err = db.Rdb.ZAdd(db.Cxt, fmt.Sprintf("%s:Pid%d", config.SearchHeatListKey, searchInfo.Pid), redis.Z{Score: float64(searchInfo.Hits), Member: data}).Err()
|
||||
// 添加搜索关键字信息
|
||||
SearchKeyword(searchInfo)
|
||||
return
|
||||
}
|
||||
|
||||
// SearchKeyword 设置search关键字集合
|
||||
func SearchKeyword(search SearchInfo) {
|
||||
// 首先获取redis中的search 关键字信息
|
||||
key := fmt.Sprintf("%s:Pid%d", config.SearchKeys, search.Pid)
|
||||
keyword := db.Rdb.HGetAll(db.Cxt, key).Val()
|
||||
if keyword["Year"] == "" {
|
||||
currentYear := time.Now().Year()
|
||||
year := ""
|
||||
for i := 0; i < 12; i++ {
|
||||
// 提供当前年份前推十二年的搜索
|
||||
year = fmt.Sprintf("%s,%d", year, currentYear-i)
|
||||
}
|
||||
initial := ""
|
||||
for i := 65; i <= 90; i++ {
|
||||
initial = fmt.Sprintf("%s,%c", initial, i)
|
||||
}
|
||||
keyword = map[string]string{
|
||||
//"Name": "",
|
||||
"Category": "",
|
||||
"Tag": "",
|
||||
"Area": "",
|
||||
"Language": "",
|
||||
"Year": strings.Trim(year, ","),
|
||||
"Initial": strings.Trim(initial, ","),
|
||||
"Sort": "Time,Db,Score", // 默认,一般不修改
|
||||
}
|
||||
}
|
||||
// 分类标签处理
|
||||
if !strings.Contains(keyword["Category"], search.CName) {
|
||||
keyword["Category"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Category"], search.CName), ",")
|
||||
}
|
||||
// 影视内容分类处理
|
||||
if strings.Contains(search.ClassTag, "/") {
|
||||
for _, t := range strings.Split(search.ClassTag, "/") {
|
||||
if !strings.Contains(keyword["Tag"], t) {
|
||||
keyword["Tag"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Tag"], t), ",")
|
||||
}
|
||||
}
|
||||
} else if strings.Contains(search.ClassTag, ",") {
|
||||
for _, t := range strings.Split(search.ClassTag, ",") {
|
||||
if !strings.Contains(keyword["Tag"], t) {
|
||||
keyword["Tag"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Tag"], t), ",")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(keyword["Tag"], search.ClassTag) {
|
||||
keyword["Tag"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Tag"], search.ClassTag), ",")
|
||||
}
|
||||
}
|
||||
// 如果地区中包含 / 分隔符 则先进行切分处理
|
||||
if strings.Contains(search.Area, "/") {
|
||||
for _, s := range strings.Split(search.Area, "/") {
|
||||
if !strings.Contains(keyword["Area"], strings.TrimSpace(s)) {
|
||||
keyword["Area"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Area"], s), ",")
|
||||
}
|
||||
}
|
||||
} else if strings.Contains(search.Area, ",") {
|
||||
for _, s := range strings.Split(search.Area, ",") {
|
||||
if !strings.Contains(keyword["Area"], strings.TrimSpace(s)) {
|
||||
keyword["Area"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Area"], s), ",")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(keyword["Area"], search.Area) {
|
||||
keyword["Area"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Area"], search.Area), ",")
|
||||
}
|
||||
}
|
||||
// 语言处理
|
||||
if strings.Contains(search.Language, "/") {
|
||||
for _, l := range strings.Split(search.Language, "/") {
|
||||
if !strings.Contains(keyword["Language"], l) {
|
||||
keyword["Language"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Language"], l), ",")
|
||||
}
|
||||
}
|
||||
|
||||
} else if strings.Contains(search.Language, ",") {
|
||||
for _, l := range strings.Split(search.Language, ",") {
|
||||
if !strings.Contains(keyword["Language"], l) {
|
||||
keyword["Language"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Language"], l), ",")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(keyword["Language"], search.Language) {
|
||||
keyword["Language"] = strings.Trim(fmt.Sprintf("%s,%s", keyword["Language"], search.Language), ",")
|
||||
}
|
||||
}
|
||||
_ = db.Rdb.HMSet(db.Cxt, key, keyword).Err()
|
||||
}
|
||||
|
||||
// BatchSaveSearchInfo 批量保存Search信息
|
||||
func BatchSaveSearchInfo(list []MovieDetail) {
|
||||
var infoList []SearchInfo
|
||||
@@ -333,8 +209,8 @@ func ConvertSearchInfo(detail MovieDetail) SearchInfo {
|
||||
UpdateStamp: stamp.Unix(),
|
||||
State: detail.State,
|
||||
Remarks: detail.Remarks,
|
||||
// releaseDate 部分影片缺失该参数, 所以使用添加时间作为上映时间排序
|
||||
ReleaseDate: detail.AddTime,
|
||||
// ReleaseDate 部分影片缺失该参数, 所以使用添加时间作为上映时间排序
|
||||
ReleaseStamp: detail.AddTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,6 +232,18 @@ func GetDetailByKey(key string) MovieDetail {
|
||||
return detail
|
||||
}
|
||||
|
||||
// GetBasicInfoBySearchInfos 通过searchInfo 获取影片的基本信息
|
||||
func GetBasicInfoBySearchInfos(infos ...SearchInfo) []MovieBasicInfo {
|
||||
var list []MovieBasicInfo
|
||||
for _, s := range infos {
|
||||
data := []byte(db.Rdb.Get(db.Cxt, fmt.Sprintf(config.MovieBasicInfoKey, s.Cid, s.Mid)).Val())
|
||||
basic := MovieBasicInfo{}
|
||||
_ = json.Unmarshal(data, &basic)
|
||||
list = append(list, basic)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/*
|
||||
对附属播放源入库时的name|dbID进行处理,保证唯一性
|
||||
1. 去除name中的所有空格
|
||||
@@ -383,3 +271,27 @@ func GenerateHashKey[K string | ~int | int64](key K) string {
|
||||
}
|
||||
return fmt.Sprint(h.Sum32())
|
||||
}
|
||||
|
||||
// ============================采集方案.v1 遗留==================================================
|
||||
|
||||
// SaveMoves 保存影片分页请求list
|
||||
func SaveMoves(list []Movie) (err error) {
|
||||
// 整合数据
|
||||
for _, m := range list {
|
||||
//score, _ := time.ParseInLocation(time.DateTime, m.Time, time.Local)
|
||||
movie, _ := json.Marshal(m)
|
||||
// 以Cid为目录为集合进行存储, 便于后续搜索, 以影片id为分值进行存储 例 MovieList:Cid%d
|
||||
err = db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.MovieListInfoKey, m.Cid), redis.Z{Score: float64(m.Id), Member: movie}).Err()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// AllMovieInfoKey 获取redis中所有的影视列表信息key MovieList:Cid
|
||||
func AllMovieInfoKey() []string {
|
||||
return db.Rdb.Keys(db.Cxt, fmt.Sprint("MovieList:Cid*")).Val()
|
||||
}
|
||||
|
||||
// GetMovieListByKey 获取指定分类的影片列表数据
|
||||
func GetMovieListByKey(key string) []string {
|
||||
return db.Rdb.ZRange(db.Cxt, key, 0, -1).Val()
|
||||
}
|
||||
|
||||
11
film/server/model/RequestParams.go
Normal file
11
film/server/model/RequestParams.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
type SearchTagsVO struct {
|
||||
Pid int64
|
||||
Cid int64
|
||||
Plot string
|
||||
Area string
|
||||
Language string
|
||||
Year int64
|
||||
Sort string
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"server/config"
|
||||
"server/plugin/common/param"
|
||||
"server/plugin/db"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -18,23 +19,23 @@ import (
|
||||
// SearchInfo 存储用于检索的信息
|
||||
type SearchInfo struct {
|
||||
gorm.Model
|
||||
Mid int64 `json:"mid" gorm:"uniqueIndex:idx_mid"` //影片ID
|
||||
Cid int64 `json:"cid"` //分类ID
|
||||
Pid int64 `json:"pid"` //上级分类ID
|
||||
Name string `json:"name"` // 片名
|
||||
SubTitle string `json:"subTitle"` // 影片子标题
|
||||
CName string `json:"CName"` // 分类名称
|
||||
ClassTag string `json:"classTag"` //类型标签
|
||||
Area string `json:"area"` // 地区
|
||||
Language string `json:"language"` // 语言
|
||||
Year int64 `json:"year"` // 年份
|
||||
Initial string `json:"initial"` // 首字母
|
||||
Score float64 `json:"score"` //评分
|
||||
UpdateStamp int64 `json:"updateStamp"` // 更新时间
|
||||
Hits int64 `json:"hits"` // 热度排行
|
||||
State string `json:"state"` //状态 正片|预告
|
||||
Remarks string `json:"remarks"` // 完结 | 更新至x集
|
||||
ReleaseDate int64 `json:"releaseDate"` //上映时间 时间戳
|
||||
Mid int64 `json:"mid"` //影片ID gorm:"uniqueIndex:idx_mid"
|
||||
Cid int64 `json:"cid"` //分类ID
|
||||
Pid int64 `json:"pid"` //上级分类ID
|
||||
Name string `json:"name"` // 片名
|
||||
SubTitle string `json:"subTitle"` // 影片子标题
|
||||
CName string `json:"CName"` // 分类名称
|
||||
ClassTag string `json:"classTag"` //类型标签
|
||||
Area string `json:"area"` // 地区
|
||||
Language string `json:"language"` // 语言
|
||||
Year int64 `json:"year"` // 年份
|
||||
Initial string `json:"initial"` // 首字母
|
||||
Score float64 `json:"score"` //评分
|
||||
UpdateStamp int64 `json:"updateStamp"` // 更新时间
|
||||
Hits int64 `json:"hits"` // 热度排行
|
||||
State string `json:"state"` //状态 正片|预告
|
||||
Remarks string `json:"remarks"` // 完结 | 更新至x集
|
||||
ReleaseStamp int64 `json:"releaseStamp"` //上映时间 时间戳
|
||||
}
|
||||
|
||||
// Page 分页信息结构体
|
||||
@@ -46,6 +47,12 @@ type Page struct {
|
||||
//List []interface{} `json:"list"` // 数据
|
||||
}
|
||||
|
||||
// Tag 影片分类标签结构体
|
||||
type Tag struct {
|
||||
Name string `json:"name"`
|
||||
Value interface{} `json:"value"`
|
||||
}
|
||||
|
||||
func (s *SearchInfo) TableName() string {
|
||||
return config.SearchTableName
|
||||
}
|
||||
@@ -96,6 +103,125 @@ func DelMtPlay(keys []string) {
|
||||
db.Rdb.Del(db.Cxt, keys...)
|
||||
}
|
||||
|
||||
/*
|
||||
SearchKeyword 设置search关键字集合(影片分类检索类型数据)
|
||||
类型, 剧情 , 地区, 语言, 年份, 首字母, 排序
|
||||
1. 在影片详情缓存到redis时将影片的相关数据进行记录, 存在相同类型则分值加一
|
||||
2. 通过分值对类型进行排序类型展示到页面
|
||||
*/
|
||||
|
||||
func SaveSearchTag(search SearchInfo) {
|
||||
// 声明用于存储采集的影片的分类检索信息
|
||||
//searchMap := make(map[string][]map[string]int)
|
||||
|
||||
// Redis中的记录形式 Search:SearchKeys:Pid1:Title Hash
|
||||
// Redis中的记录形式 Search:SearchKeys:Pid1:xxx Hash
|
||||
|
||||
// 获取redis中的searchMap
|
||||
key := fmt.Sprintf(config.SearchTitle, search.Pid)
|
||||
searchMap := db.Rdb.HGetAll(db.Cxt, key).Val()
|
||||
// 是否存储对应分类的map, 如果不存在则缓存一份
|
||||
if len(searchMap) == 0 {
|
||||
searchMap = make(map[string]string)
|
||||
searchMap["Category"] = "类型"
|
||||
searchMap["Plot"] = "剧情"
|
||||
searchMap["Area"] = "地区"
|
||||
searchMap["Language"] = "语言"
|
||||
searchMap["Year"] = "年份"
|
||||
searchMap["Initial"] = "首字母"
|
||||
searchMap["Sort"] = "排序"
|
||||
db.Rdb.HMSet(db.Cxt, key, searchMap)
|
||||
}
|
||||
// 对searchMap中的各个类型进行处理
|
||||
for k, _ := range searchMap {
|
||||
tagKey := fmt.Sprintf(config.SearchTag, search.Pid, k)
|
||||
tagCount := db.Rdb.ZCard(db.Cxt, tagKey).Val()
|
||||
switch k {
|
||||
case "Category":
|
||||
// 获取 Category 数据, 如果不存在则缓存一份
|
||||
if tagCount == 0 {
|
||||
for _, t := range GetChildrenTree(search.Pid) {
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k),
|
||||
redis.Z{Score: float64(-t.Id), Member: fmt.Sprintf("%v:%v", t.Name, t.Id)})
|
||||
}
|
||||
}
|
||||
case "Year":
|
||||
// 获取 Year 数据, 如果不存在则缓存一份
|
||||
if tagCount == 0 {
|
||||
currentYear := time.Now().Year()
|
||||
for i := 0; i < 12; i++ {
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k),
|
||||
redis.Z{Score: float64(currentYear - i), Member: fmt.Sprintf("%v:%v", currentYear-i, currentYear-i)})
|
||||
}
|
||||
}
|
||||
case "Initial":
|
||||
// 如果不存在 首字母 Tag 数据, 则缓存一份
|
||||
if tagCount == 0 {
|
||||
for i := 65; i <= 90; i++ {
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k),
|
||||
redis.Z{Score: float64(90 - i), Member: fmt.Sprintf("%c:%c", i, i)})
|
||||
}
|
||||
}
|
||||
case "Sort":
|
||||
if tagCount == 0 {
|
||||
tags := []redis.Z{
|
||||
{3, "时间排序:update_stamp"},
|
||||
{2, "人气排序:hits"},
|
||||
{1, "评分排序:score"},
|
||||
{0, "最新上映:release_stamp"},
|
||||
}
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k), tags...)
|
||||
}
|
||||
case "Plot":
|
||||
HandleSearchTags(search.ClassTag, tagKey)
|
||||
case "Area":
|
||||
HandleSearchTags(search.Area, tagKey)
|
||||
case "Language":
|
||||
HandleSearchTags(search.Language, tagKey)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func HandleSearchTags(preTags string, k string) {
|
||||
// 先处理字符串中的空白符 然后对处理前的tag字符串进行分割
|
||||
preTags = regexp.MustCompile(`[\s\n\r]+`).ReplaceAllString(preTags, "")
|
||||
f := func(sep string) {
|
||||
for _, t := range strings.Split(preTags, sep) {
|
||||
// 获取 tag对应的score
|
||||
score := db.Rdb.ZScore(db.Cxt, k, fmt.Sprintf("%v:%v", t, t)).Val()
|
||||
// 在原score的基础上+1 重新存入redis中
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: score + 1, Member: fmt.Sprintf("%v:%v", t, t)})
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(preTags, "/"):
|
||||
f("/")
|
||||
case strings.Contains(preTags, ","):
|
||||
f(",")
|
||||
case strings.Contains(preTags, ","):
|
||||
f(",")
|
||||
case strings.Contains(preTags, "、"):
|
||||
f("、")
|
||||
default:
|
||||
// 获取 tag对应的score
|
||||
if len(preTags) == 0 || preTags == "其它" {
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: 0, Member: fmt.Sprintf("%v:%v", preTags, preTags)})
|
||||
} else {
|
||||
score := db.Rdb.ZScore(db.Cxt, k, fmt.Sprintf("%v:%v", preTags, preTags)).Val()
|
||||
db.Rdb.ZAdd(db.Cxt, k, redis.Z{Score: score + 1, Member: fmt.Sprintf("%v:%v", preTags, preTags)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BatchHandleSearchTag(infos ...SearchInfo) {
|
||||
for _, info := range infos {
|
||||
SaveSearchTag(info)
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= Spider 数据处理(mysql) =================================
|
||||
|
||||
// CreateSearchTable 创建存储检索信息的数据表
|
||||
@@ -111,6 +237,20 @@ func CreateSearchTable() {
|
||||
}
|
||||
}
|
||||
|
||||
// AddSearchIndex search表中数据保存完毕后 将常用字段添加索引提高查询效率
|
||||
func AddSearchIndex() {
|
||||
var s *SearchInfo
|
||||
tableName := s.TableName()
|
||||
// 添加索引
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE UNIQUE INDEX idx_mid ON %s (mid)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_time ON %s (update_stamp DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_hits ON %s (hits DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_score ON %s (score DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_release ON %s (release_stamp DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_year ON %s (year DESC)", tableName))
|
||||
|
||||
}
|
||||
|
||||
// BatchSave 批量保存影片search信息
|
||||
func BatchSave(list []SearchInfo) {
|
||||
tx := db.Mdb.Begin()
|
||||
@@ -125,29 +265,23 @@ func BatchSave(list []SearchInfo) {
|
||||
tx.Rollback()
|
||||
return
|
||||
}
|
||||
// 插入成功后输出一下成功信息
|
||||
//log.Println("BatchSave SearchInfo Successful, Count: ", len(list))
|
||||
// 保存成功后将相应tag数据缓存到redis中
|
||||
BatchHandleSearchTag(list...)
|
||||
tx.Commit()
|
||||
}
|
||||
|
||||
// BatchSaveOrUpdate 判断数据库中是否存在对应mid的数据, 如果存在则更新, 否则插入
|
||||
func BatchSaveOrUpdate(list []SearchInfo) {
|
||||
tx := db.Mdb.Begin()
|
||||
// 失败则回滚事务
|
||||
//defer func() {
|
||||
// if r := recover(); r != nil {
|
||||
// tx.Rollback()
|
||||
// }
|
||||
//}()
|
||||
for _, info := range list {
|
||||
var count int64
|
||||
// 通过当前影片id 对应的记录数
|
||||
tx.Model(&SearchInfo{}).Where("mid", info.Mid).Count(&count)
|
||||
// 如果存在对应数据则进行更新, 否则进行删除
|
||||
// 如果存在对应数据则进行更新, 否则保存相应数据
|
||||
if count > 0 {
|
||||
// 记录已经存在则执行更新部分内容
|
||||
err := tx.Model(&SearchInfo{}).Where("mid", info.Mid).Updates(SearchInfo{UpdateStamp: info.UpdateStamp, Hits: info.Hits, State: info.State,
|
||||
Remarks: info.Remarks, Score: info.Score, ReleaseDate: info.ReleaseDate}).Error
|
||||
Remarks: info.Remarks, Score: info.Score, ReleaseStamp: info.ReleaseStamp}).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
@@ -156,6 +290,8 @@ func BatchSaveOrUpdate(list []SearchInfo) {
|
||||
if err := tx.Create(&info).Error; err != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
// 插入成功后保存一份tag信息到redis中
|
||||
BatchHandleSearchTag(info)
|
||||
}
|
||||
}
|
||||
// 提交事务
|
||||
@@ -189,6 +325,14 @@ func TunCateSearchTable() {
|
||||
}
|
||||
}
|
||||
|
||||
// GetPage 获取分页相关数据
|
||||
func GetPage(db *gorm.DB, page *Page) {
|
||||
var count int64
|
||||
db.Count(&count)
|
||||
page.Total = int(count)
|
||||
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
|
||||
}
|
||||
|
||||
// ================================= API 数据接口信息处理 =================================
|
||||
|
||||
// GetMovieListByPid 通过Pid 分类ID 获取对应影片的数据信息
|
||||
@@ -213,6 +357,28 @@ func GetMovieListByPid(pid int64, page *Page) []MovieBasicInfo {
|
||||
return list
|
||||
}
|
||||
|
||||
// GetMovieListByCid 通过Cid查找对应的影片分页数据, 不适合GetMovieListByPid 糅合
|
||||
func GetMovieListByCid(cid int64, page *Page) []MovieBasicInfo {
|
||||
// 返回分页参数
|
||||
var count int64
|
||||
db.Mdb.Model(&SearchInfo{}).Where("cid", cid).Count(&count)
|
||||
page.Total = int(count)
|
||||
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
|
||||
// 进行具体的信息查询
|
||||
var s []SearchInfo
|
||||
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("cid", cid).Order("year DESC, update_stamp DESC").Find(&s).Error; err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
// 通过影片ID去redis中获取id对应数据信息
|
||||
var list []MovieBasicInfo
|
||||
for _, v := range s {
|
||||
// 通过key搜索指定的影片信息 , MovieDetail:Cid6:Id15441
|
||||
list = append(list, GetBasicInfoByKey(fmt.Sprintf(config.MovieBasicInfoKey, v.Cid, v.Mid)))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// GetHotMovieByPid 获取指定类别的热门影片
|
||||
func GetHotMovieByPid(pid int64, page *Page) []SearchInfo {
|
||||
// 返回分页参数
|
||||
@@ -245,28 +411,6 @@ func SearchFilmKeyword(keyword string, page *Page) []SearchInfo {
|
||||
return searchList
|
||||
}
|
||||
|
||||
// GetMovieListByCid 通过Cid查找对应的影片分页数据, 不适合GetMovieListByPid 糅合
|
||||
func GetMovieListByCid(cid int64, page *Page) []MovieBasicInfo {
|
||||
// 返回分页参数
|
||||
var count int64
|
||||
db.Mdb.Model(&SearchInfo{}).Where("cid", cid).Count(&count)
|
||||
page.Total = int(count)
|
||||
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
|
||||
// 进行具体的信息查询
|
||||
var s []SearchInfo
|
||||
if err := db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).Where("cid", cid).Order("year DESC, update_stamp DESC").Find(&s).Error; err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
// 通过影片ID去redis中获取id对应数据信息
|
||||
var list []MovieBasicInfo
|
||||
for _, v := range s {
|
||||
// 通过key搜索指定的影片信息 , MovieDetail:Cid6:Id15441
|
||||
list = append(list, GetBasicInfoByKey(fmt.Sprintf(config.MovieBasicInfoKey, v.Cid, v.Mid)))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// GetRelateMovieBasicInfo GetRelateMovie 根据SearchInfo获取相关影片
|
||||
func GetRelateMovieBasicInfo(search SearchInfo, page *Page) []MovieBasicInfo {
|
||||
/*
|
||||
@@ -338,6 +482,157 @@ func GetMultiplePlay(siteName, key string) []MovieUrlInfo {
|
||||
return playList
|
||||
}
|
||||
|
||||
// GetSearchTag 通过影片分类 Pid 返回对应分类的tag信息
|
||||
func GetSearchTag(pid int64) map[string]interface{} {
|
||||
// 整合searchTag相关内容
|
||||
res := make(map[string]interface{})
|
||||
titles := db.Rdb.HGetAll(db.Cxt, fmt.Sprintf(config.SearchTitle, pid)).Val()
|
||||
res["titles"] = titles
|
||||
// 处理单一分类的数据格式
|
||||
tagMap := make(map[string]interface{})
|
||||
for t, _ := range titles {
|
||||
tagMap[t] = HandleTagStr(t, GetTagsByTitle(pid, t)...)
|
||||
}
|
||||
res["tags"] = tagMap
|
||||
// 分类列表展示的顺序
|
||||
res["sortList"] = []string{"Category", "Plot", "Area", "Language", "Year", "Sort"}
|
||||
return res
|
||||
}
|
||||
|
||||
// GetTagsByTitle 返回Pid和title对应的用于检索的tag
|
||||
func GetTagsByTitle(pid int64, t string) []string {
|
||||
// 通过 k 获取对应的 tag , 并以score进行排序
|
||||
var tags []string
|
||||
// 过滤分类tag
|
||||
switch t {
|
||||
case "Category":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, -1).Val()
|
||||
case "Plot":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, 10).Val()
|
||||
case "Area":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, 11).Val()
|
||||
case "Language":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, 6).Val()
|
||||
case "Year", "Initial", "Sort":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, -1).Val()
|
||||
default:
|
||||
break
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// HandleTagStr 处理tag数据格式
|
||||
func HandleTagStr(title string, tags ...string) []map[string]string {
|
||||
var r []map[string]string
|
||||
if !strings.EqualFold(title, "Sort") {
|
||||
r = append(r, map[string]string{
|
||||
"Name": "全部",
|
||||
"Value": "",
|
||||
})
|
||||
}
|
||||
for _, t := range tags {
|
||||
if sl := strings.Split(t, ":"); len(sl) > 0 {
|
||||
r = append(r, map[string]string{
|
||||
"Name": sl[0],
|
||||
"Value": sl[1],
|
||||
})
|
||||
}
|
||||
}
|
||||
if !strings.EqualFold(title, "Sort") && !strings.EqualFold(title, "Year") && !strings.EqualFold(title, "Category") {
|
||||
r = append(r, map[string]string{
|
||||
"Name": "其它",
|
||||
"Value": "其它",
|
||||
})
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// GetSearchInfosByTags 查询满足searchTag条件的影片分页数据
|
||||
func GetSearchInfosByTags(st SearchTagsVO, page *Page) []SearchInfo {
|
||||
// 准备查询语句的条件
|
||||
qw := db.Mdb.Model(&SearchInfo{})
|
||||
// 通过searchTags的非空属性值, 拼接对应的查询条件
|
||||
t := reflect.TypeOf(st)
|
||||
v := reflect.ValueOf(st)
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
// 如果字段值不为空
|
||||
value := v.Field(i).Interface()
|
||||
if !param.IsEmpty(value) {
|
||||
// 如果value是 其它 则进行特殊处理
|
||||
var ts []string
|
||||
if v, flag := value.(string); flag && strings.EqualFold(v, "其它") {
|
||||
for _, s := range GetTagsByTitle(st.Pid, t.Field(i).Name) {
|
||||
ts = append(ts, strings.Split(s, ":")[1])
|
||||
}
|
||||
}
|
||||
k := strings.ToLower(t.Field(i).Name)
|
||||
switch k {
|
||||
case "pid", "cid", "year":
|
||||
qw = qw.Where(fmt.Sprintf("%s = ?", k), value)
|
||||
case "area", "language":
|
||||
if strings.EqualFold(value.(string), "其它") {
|
||||
qw = qw.Where(fmt.Sprintf("%s NOT IN ?", k), ts)
|
||||
break
|
||||
}
|
||||
qw = qw.Where(fmt.Sprintf("%s = ?", k), value)
|
||||
case "plot":
|
||||
if strings.EqualFold(value.(string), "其它") {
|
||||
for _, t := range ts {
|
||||
qw = qw.Where("class_tag NOT LIKE ?", fmt.Sprintf("%%%v%%", t))
|
||||
}
|
||||
break
|
||||
}
|
||||
qw = qw.Where("class_tag LIKE ?", fmt.Sprintf("%%%v%%", value))
|
||||
case "sort":
|
||||
if strings.EqualFold(value.(string), "release_stamp") {
|
||||
qw.Order(fmt.Sprintf("year DESC ,%v Desc", value))
|
||||
break
|
||||
}
|
||||
qw.Order(fmt.Sprintf("%v Desc", value))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回分页参数
|
||||
GetPage(qw, page)
|
||||
//
|
||||
var sl []SearchInfo
|
||||
if err := qw.Limit(page.PageSize).Offset((page.Current - 1) * page.PageSize).Find(&sl).Error; err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
return sl
|
||||
|
||||
}
|
||||
|
||||
// GetMovieListBySort 通过排序类型返回对应的影片基本信息
|
||||
func GetMovieListBySort(t int, pid int64, page *Page) []MovieBasicInfo {
|
||||
var sl []SearchInfo
|
||||
qw := db.Mdb.Model(&SearchInfo{}).Where("pid", pid).Limit(page.PageSize).Offset((page.Current) - 10*page.PageSize)
|
||||
// 针对不同排序类型返回对应的分页数据
|
||||
switch t {
|
||||
case 0:
|
||||
// 最新上映 (上映时间)
|
||||
qw.Order("year DESC, release_stamp DESC")
|
||||
case 1:
|
||||
// 排行榜 (暂定为热度排行)
|
||||
qw.Order("year DESC, hits DESC")
|
||||
case 2:
|
||||
// 最近更新 (更新时间)
|
||||
qw.Order("year DESC, update_stamp DESC")
|
||||
}
|
||||
if err := qw.Find(&sl).Error; err != nil {
|
||||
log.Println(err)
|
||||
return nil
|
||||
}
|
||||
return GetBasicInfoBySearchInfos(sl...)
|
||||
|
||||
}
|
||||
|
||||
// ================================= 接口数据缓存 =================================
|
||||
|
||||
// DataCache API请求 数据缓存
|
||||
func DataCache(key string, data map[string]interface{}) {
|
||||
val, _ := json.Marshal(data)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package common
|
||||
package dp
|
||||
|
||||
import (
|
||||
"server/model"
|
||||
@@ -1,4 +1,4 @@
|
||||
package common
|
||||
package dp
|
||||
|
||||
import (
|
||||
"server/model"
|
||||
38
film/server/plugin/common/param/SimpleParam.go
Normal file
38
film/server/plugin/common/param/SimpleParam.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package param
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
/*
|
||||
简单参数处理
|
||||
*/
|
||||
|
||||
// IsEmpty 判断各种基本类型是否为空
|
||||
func IsEmpty(target any) bool {
|
||||
switch target.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
|
||||
return target == reflect.Zero(reflect.TypeOf(target)).Interface()
|
||||
case string:
|
||||
return target == ""
|
||||
case bool:
|
||||
return target.(bool)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func IsEmptyRe[T ~int | ~uint | float32 | float64 | string | bool](target T) bool {
|
||||
v := reflect.ValueOf(target)
|
||||
switch v.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32,
|
||||
reflect.Float64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return v.Interface() == 0
|
||||
case reflect.String:
|
||||
return v.String() == ""
|
||||
case reflect.Bool:
|
||||
return v.Bool()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ func InitRedisConn() error {
|
||||
Addr: config.RedisAddr,
|
||||
Password: config.RedisPassword,
|
||||
DB: config.RedisDBNo,
|
||||
PoolSize: 10, // 默认连接数
|
||||
PoolSize: 10, // 最大连接数
|
||||
DialTimeout: time.Second * 10, // 超时时间
|
||||
})
|
||||
// 测试连接是否正常
|
||||
@@ -31,7 +31,7 @@ func InitRedisConn() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 关闭redis连接
|
||||
// CloseRedis 关闭redis连接
|
||||
func CloseRedis() error {
|
||||
return Rdb.Close()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"net/url"
|
||||
"server/config"
|
||||
"server/model"
|
||||
"server/plugin/common"
|
||||
"server/plugin/common/dp"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
*/
|
||||
|
||||
const (
|
||||
MainSite = "https://www.feisuzyapi.com/api.php/provide/vod/"
|
||||
MainSite = "https://cj.lzcaiji.com/api.php/provide/vod/"
|
||||
)
|
||||
|
||||
type Site struct {
|
||||
@@ -39,14 +39,17 @@ type Site struct {
|
||||
|
||||
// SiteList 播放源采集站
|
||||
var SiteList = []Site{
|
||||
//{"tk", "https://api.tiankongapi.com/api.php/provide/vod"},
|
||||
//{"yh", "https://m3u8.apiyhzy.com/api.php/provide/vod/"},
|
||||
//{"zk", "https://api.1080zyku.com/inc/apijson.php"}, 数据格式不规范,不采用
|
||||
// 备用采集站
|
||||
//{"lz_bk", "https://cj.lzcaiji.com/api.php/provide/vod/"},
|
||||
//{"fs", "https://www.feisuzyapi.com/api.php/provide/vod/"},
|
||||
//{"su", "https://subocaiji.com/api.php/provide/vod/at/json"},
|
||||
//{"bf", "https://bfzyapi.com/api.php/provide/vod/"},
|
||||
//{"ff", "https://svip.ffzyapi8.com/api.php/provide/vod/"},
|
||||
|
||||
{"lz", "https://cj.lziapi.com/api.php/provide/vod/"},
|
||||
//{"lz", "https://cj.lziapi.com/api.php/provide/vod/"},
|
||||
{"kk", "https://kuaikan-api.com/api.php/provide/vod/from/kuaikan"},
|
||||
{"bf", "http://by.bfzyapi.com/api.php/provide/vod/"},
|
||||
{"ff", "https://cj.ffzyapi.com/api.php/provide/vod/"},
|
||||
{"su", "https://subocaiji.com/api.php/provide/vod/at/json"},
|
||||
}
|
||||
|
||||
// StartSpider 执行多源spider
|
||||
@@ -57,15 +60,16 @@ func StartSpider() {
|
||||
// 爬取主站点数据
|
||||
MainSiteSpider()
|
||||
log.Println("MainSiteSpider 主站点影片信息保存完毕")
|
||||
// 查找并创建search数据库
|
||||
// 查找并创建search数据库, 保存search信息, 添加索引
|
||||
time.Sleep(time.Second * 10)
|
||||
model.CreateSearchTable()
|
||||
SearchInfoToMdb()
|
||||
model.AddSearchIndex()
|
||||
log.Println("SearchInfoToMdb 影片检索信息保存完毕")
|
||||
// 获取其他站点数据
|
||||
//获取其他站点数据13
|
||||
go MtSiteSpider()
|
||||
log.Println("Spider End , 数据保存执行完成")
|
||||
//time.Sleep(time.Second * 10)
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
|
||||
// CategoryList 获取分类数据
|
||||
@@ -86,7 +90,7 @@ func CategoryList() {
|
||||
// 获取分类列表信息
|
||||
classList := movieListInfo.Class
|
||||
// 组装分类数据信息树形结构
|
||||
categoryTree := common.CategoryTree(classList)
|
||||
categoryTree := dp.CategoryTree(classList)
|
||||
// 序列化tree
|
||||
data, _ := json.Marshal(categoryTree)
|
||||
// 保存 tree 到redis
|
||||
@@ -287,7 +291,7 @@ func StartSpiderRe() {
|
||||
func GetPageCount(r RequestInfo) (count int, err error) {
|
||||
// 发送请求获取pageCount
|
||||
r.Params.Set("ac", "detail")
|
||||
r.Params.Set("pg", "1")
|
||||
r.Params.Set("pg", "2")
|
||||
ApiGet(&r)
|
||||
// 判断请求结果是否为空, 如果为空直接输出错误并终止
|
||||
if len(r.Resp) <= 0 {
|
||||
@@ -328,6 +332,6 @@ func GetMovieDetail(pageNumber int, r RequestInfo) (list []model.MovieDetail, er
|
||||
return
|
||||
}
|
||||
// 处理details信息
|
||||
list = common.ProcessMovieDetailList(details.List)
|
||||
list = dp.ProcessMovieDetailList(details.List)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ var (
|
||||
// RequestInfo 请求参数结构体
|
||||
type RequestInfo struct {
|
||||
Uri string `json:"uri"` // 请求url地址
|
||||
Params url.Values `json:"params"` // 请求参数
|
||||
Params url.Values `json:"param"` // 请求参数
|
||||
Header http.Header `json:"header"` // 请求头数据
|
||||
Resp []byte `json:"resp"` // 响应结果数据
|
||||
}
|
||||
@@ -30,6 +30,10 @@ var RefererUrl string
|
||||
// CreateClient 初始化请求客户端
|
||||
func CreateClient() *colly.Collector {
|
||||
c := colly.NewCollector()
|
||||
|
||||
// 设置请求使用clash的socks5代理
|
||||
//setProxy(c)
|
||||
|
||||
// 设置代理信息
|
||||
//if proxy, err := proxy.RoundRobinProxySwitcher("127.0.0.1:7890"); err != nil {
|
||||
// c.SetProxyFunc(proxy)
|
||||
@@ -46,6 +50,7 @@ func CreateClient() *colly.Collector {
|
||||
c.OnRequest(func(request *colly.Request) {
|
||||
// 设置一些请求头信息
|
||||
request.Headers.Set("Content-Type", "application/json;charset=UTF-8")
|
||||
request.Headers.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
|
||||
//request.Headers.Set("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
|
||||
// 请求完成后设置请求头Referer
|
||||
if len(RefererUrl) <= 0 || !strings.Contains(RefererUrl, request.URL.Host) {
|
||||
@@ -89,3 +94,9 @@ func ApiGet(r *RequestInfo) {
|
||||
log.Println("获取数据失败: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 本地代理测试
|
||||
func setProxy(c *colly.Collector) {
|
||||
proxyUrl, _ := url.Parse("socks5://127.0.0.1:7890")
|
||||
c.WithTransport(&http.Transport{Proxy: http.ProxyURL(proxyUrl)})
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@ func SetupRouter() *gin.Engine {
|
||||
r.GET(`/filmDetail`, controller.FilmDetail)
|
||||
r.GET(`/filmPlayInfo`, controller.FilmPlayInfo)
|
||||
r.GET(`/searchFilm`, controller.SearchFilm)
|
||||
r.GET(`/filmCategory`, controller.FilmCategory)
|
||||
r.GET(`/filmClassify`, controller.FilmClassify)
|
||||
r.GET(`/filmClassifySearch`, controller.FilmTagSearch)
|
||||
// 弃用
|
||||
//r.GET(`/filmCategory`, controller.FilmCategory)
|
||||
|
||||
// 触发spider
|
||||
spiderRoute := r.Group(`/spider`)
|
||||
|
||||
@@ -113,56 +113,7 @@ func SearchFilm(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// FilmCategory 获取指定分类的影片分页数据,
|
||||
func FilmCategory(c *gin.Context) {
|
||||
// 1.1 首先获取Cid 二级分类id是否存在
|
||||
cidStr := c.DefaultQuery("cid", "")
|
||||
// 1.2 如果pid也不存在直接返回错误信息
|
||||
pidStr := c.DefaultQuery("pid", "")
|
||||
if pidStr == "" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusFailed,
|
||||
"message": "缺少分类信息",
|
||||
})
|
||||
return
|
||||
}
|
||||
// 1.3 获取pid对应的分类信息
|
||||
pid, _ := strconv.ParseInt(pidStr, 10, 64)
|
||||
category := logic.IL.GetPidCategory(pid)
|
||||
|
||||
// 2 设置分页信息
|
||||
currentStr := c.DefaultQuery("current", "1")
|
||||
current, _ := strconv.Atoi(currentStr)
|
||||
page := model.Page{PageSize: 49, Current: current}
|
||||
// 2.1 如果不存在cid则根据Pid进行查询
|
||||
if cidStr == "" {
|
||||
// 2.2 如果存在pid则根据pid进行查找
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(pid, "pid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
return
|
||||
}
|
||||
// 2.2 如果存在cid 则根据具体的cid去查询数据
|
||||
cid, _ := strconv.ParseInt(cidStr, 10, 64)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(cid, "cid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
|
||||
// 获取请求参数
|
||||
}
|
||||
|
||||
// FilmTagSearch 通过tag获取满足条件的对应影片
|
||||
func FilmTagSearch(c *gin.Context) {
|
||||
params := model.SearchTagsVO{}
|
||||
pidStr := c.DefaultQuery("Pid", "")
|
||||
@@ -235,3 +186,53 @@ func FilmClassify(c *gin.Context) {
|
||||
"page": page,
|
||||
})
|
||||
}
|
||||
|
||||
// FilmCategory 获取指定分类的影片分页数据,(已弃用)
|
||||
func FilmCategory(c *gin.Context) {
|
||||
// 1.1 首先获取Cid 二级分类id是否存在
|
||||
cidStr := c.DefaultQuery("cid", "")
|
||||
// 1.2 如果pid也不存在直接返回错误信息
|
||||
pidStr := c.DefaultQuery("pid", "")
|
||||
if pidStr == "" {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusFailed,
|
||||
"message": "缺少分类信息",
|
||||
})
|
||||
return
|
||||
}
|
||||
// 1.3 获取pid对应的分类信息
|
||||
pid, _ := strconv.ParseInt(pidStr, 10, 64)
|
||||
category := logic.IL.GetPidCategory(pid)
|
||||
|
||||
// 2 设置分页信息
|
||||
currentStr := c.DefaultQuery("current", "1")
|
||||
current, _ := strconv.Atoi(currentStr)
|
||||
page := model.Page{PageSize: 49, Current: current}
|
||||
// 2.1 如果不存在cid则根据Pid进行查询
|
||||
if cidStr == "" {
|
||||
// 2.2 如果存在pid则根据pid进行查找
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(pid, "pid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
return
|
||||
}
|
||||
// 2.2 如果存在cid 则根据具体的cid去查询数据
|
||||
cid, _ := strconv.ParseInt(cidStr, 10, 64)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusOk,
|
||||
"data": gin.H{
|
||||
"list": logic.IL.GetFilmCategory(cid, "cid", &page),
|
||||
"category": category,
|
||||
"search": logic.IL.SearchTags(pid),
|
||||
},
|
||||
"page": page,
|
||||
})
|
||||
|
||||
// 获取请求参数
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import (
|
||||
"server/plugin/db"
|
||||
"server/plugin/spider"
|
||||
"server/router"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 执行初始化前等待20s , 让mysql服务完成初始化指令
|
||||
//time.Sleep(time.Second * 20)
|
||||
time.Sleep(time.Second * 20)
|
||||
//初始化redis客户端
|
||||
err := db.InitRedisConn()
|
||||
if err != nil {
|
||||
@@ -23,7 +24,6 @@ func init() {
|
||||
}
|
||||
func main() {
|
||||
start()
|
||||
//spider.MtSiteSpider()
|
||||
}
|
||||
|
||||
func start() {
|
||||
|
||||
@@ -209,8 +209,8 @@ func ConvertSearchInfo(detail MovieDetail) SearchInfo {
|
||||
UpdateStamp: stamp.Unix(),
|
||||
State: detail.State,
|
||||
Remarks: detail.Remarks,
|
||||
// releaseDate 部分影片缺失该参数, 所以使用添加时间作为上映时间排序
|
||||
ReleaseDate: detail.AddTime,
|
||||
// ReleaseDate 部分影片缺失该参数, 所以使用添加时间作为上映时间排序
|
||||
ReleaseStamp: detail.AddTime,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,23 +19,23 @@ import (
|
||||
// SearchInfo 存储用于检索的信息
|
||||
type SearchInfo struct {
|
||||
gorm.Model
|
||||
Mid int64 `json:"mid" gorm:"uniqueIndex:idx_mid"` //影片ID
|
||||
Cid int64 `json:"cid"` //分类ID
|
||||
Pid int64 `json:"pid"` //上级分类ID
|
||||
Name string `json:"name"` // 片名
|
||||
SubTitle string `json:"subTitle"` // 影片子标题
|
||||
CName string `json:"CName"` // 分类名称
|
||||
ClassTag string `json:"classTag"` //类型标签
|
||||
Area string `json:"area"` // 地区
|
||||
Language string `json:"language"` // 语言
|
||||
Year int64 `json:"year"` // 年份
|
||||
Initial string `json:"initial"` // 首字母
|
||||
Score float64 `json:"score"` //评分
|
||||
UpdateStamp int64 `json:"updateStamp"` // 更新时间
|
||||
Hits int64 `json:"hits"` // 热度排行
|
||||
State string `json:"state"` //状态 正片|预告
|
||||
Remarks string `json:"remarks"` // 完结 | 更新至x集
|
||||
ReleaseDate int64 `json:"releaseDate"` //上映时间 时间戳
|
||||
Mid int64 `json:"mid"` //影片ID gorm:"uniqueIndex:idx_mid"
|
||||
Cid int64 `json:"cid"` //分类ID
|
||||
Pid int64 `json:"pid"` //上级分类ID
|
||||
Name string `json:"name"` // 片名
|
||||
SubTitle string `json:"subTitle"` // 影片子标题
|
||||
CName string `json:"CName"` // 分类名称
|
||||
ClassTag string `json:"classTag"` //类型标签
|
||||
Area string `json:"area"` // 地区
|
||||
Language string `json:"language"` // 语言
|
||||
Year int64 `json:"year"` // 年份
|
||||
Initial string `json:"initial"` // 首字母
|
||||
Score float64 `json:"score"` //评分
|
||||
UpdateStamp int64 `json:"updateStamp"` // 更新时间
|
||||
Hits int64 `json:"hits"` // 热度排行
|
||||
State string `json:"state"` //状态 正片|预告
|
||||
Remarks string `json:"remarks"` // 完结 | 更新至x集
|
||||
ReleaseStamp int64 `json:"releaseStamp"` //上映时间 时间戳
|
||||
}
|
||||
|
||||
// Page 分页信息结构体
|
||||
@@ -165,9 +165,10 @@ func SaveSearchTag(search SearchInfo) {
|
||||
case "Sort":
|
||||
if tagCount == 0 {
|
||||
tags := []redis.Z{
|
||||
{2, "时间排序:update_stamp"},
|
||||
{1, "人气排序:hits"},
|
||||
{0, "评分排序:score"},
|
||||
{3, "时间排序:update_stamp"},
|
||||
{2, "人气排序:hits"},
|
||||
{1, "评分排序:score"},
|
||||
{0, "最新上映:release_stamp"},
|
||||
}
|
||||
db.Rdb.ZAdd(db.Cxt, fmt.Sprintf(config.SearchTag, search.Pid, k), tags...)
|
||||
}
|
||||
@@ -236,6 +237,20 @@ func CreateSearchTable() {
|
||||
}
|
||||
}
|
||||
|
||||
// AddSearchIndex search表中数据保存完毕后 将常用字段添加索引提高查询效率
|
||||
func AddSearchIndex() {
|
||||
var s *SearchInfo
|
||||
tableName := s.TableName()
|
||||
// 添加索引
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE UNIQUE INDEX idx_mid ON %s (mid)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_time ON %s (update_stamp DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_hits ON %s (hits DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_score ON %s (score DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_release ON %s (release_stamp DESC)", tableName))
|
||||
db.Mdb.Exec(fmt.Sprintf("CREATE INDEX idx_year ON %s (year DESC)", tableName))
|
||||
|
||||
}
|
||||
|
||||
// BatchSave 批量保存影片search信息
|
||||
func BatchSave(list []SearchInfo) {
|
||||
tx := db.Mdb.Begin()
|
||||
@@ -266,7 +281,7 @@ func BatchSaveOrUpdate(list []SearchInfo) {
|
||||
if count > 0 {
|
||||
// 记录已经存在则执行更新部分内容
|
||||
err := tx.Model(&SearchInfo{}).Where("mid", info.Mid).Updates(SearchInfo{UpdateStamp: info.UpdateStamp, Hits: info.Hits, State: info.State,
|
||||
Remarks: info.Remarks, Score: info.Score, ReleaseDate: info.ReleaseDate}).Error
|
||||
Remarks: info.Remarks, Score: info.Score, ReleaseStamp: info.ReleaseStamp}).Error
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
@@ -475,28 +490,8 @@ func GetSearchTag(pid int64) map[string]interface{} {
|
||||
res["titles"] = titles
|
||||
// 处理单一分类的数据格式
|
||||
tagMap := make(map[string]interface{})
|
||||
for k, _ := range titles {
|
||||
// 通过 k 获取对应的 tag , 并以score进行排序
|
||||
// 过滤分类tag
|
||||
switch k {
|
||||
case "Category":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, -1).Val()
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Plot":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, 10).Val()
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Area":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, 11).Val()
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Language":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, 6).Val()
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
case "Year", "Initial", "Sort":
|
||||
tags := db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, k), 0, -1).Val()
|
||||
tagMap[k] = HandleTagStr(k, tags...)
|
||||
default:
|
||||
break
|
||||
}
|
||||
for t, _ := range titles {
|
||||
tagMap[t] = HandleTagStr(t, GetTagsByTitle(pid, t)...)
|
||||
}
|
||||
res["tags"] = tagMap
|
||||
// 分类列表展示的顺序
|
||||
@@ -504,6 +499,28 @@ func GetSearchTag(pid int64) map[string]interface{} {
|
||||
return res
|
||||
}
|
||||
|
||||
// GetTagsByTitle 返回Pid和title对应的用于检索的tag
|
||||
func GetTagsByTitle(pid int64, t string) []string {
|
||||
// 通过 k 获取对应的 tag , 并以score进行排序
|
||||
var tags []string
|
||||
// 过滤分类tag
|
||||
switch t {
|
||||
case "Category":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, -1).Val()
|
||||
case "Plot":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, 10).Val()
|
||||
case "Area":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, 11).Val()
|
||||
case "Language":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, 6).Val()
|
||||
case "Year", "Initial", "Sort":
|
||||
tags = db.Rdb.ZRevRange(db.Cxt, fmt.Sprintf(config.SearchTag, pid, t), 0, -1).Val()
|
||||
default:
|
||||
break
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// HandleTagStr 处理tag数据格式
|
||||
func HandleTagStr(title string, tags ...string) []map[string]string {
|
||||
var r []map[string]string
|
||||
@@ -521,7 +538,7 @@ func HandleTagStr(title string, tags ...string) []map[string]string {
|
||||
})
|
||||
}
|
||||
}
|
||||
if !strings.EqualFold(title, "Sort") && !strings.EqualFold(title, "Year") {
|
||||
if !strings.EqualFold(title, "Sort") && !strings.EqualFold(title, "Year") && !strings.EqualFold(title, "Category") {
|
||||
r = append(r, map[string]string{
|
||||
"Name": "其它",
|
||||
"Value": "其它",
|
||||
@@ -541,21 +558,40 @@ func GetSearchInfosByTags(st SearchTagsVO, page *Page) []SearchInfo {
|
||||
// 如果字段值不为空
|
||||
value := v.Field(i).Interface()
|
||||
if !param.IsEmpty(value) {
|
||||
cName := strings.ToLower(t.Field(i).Name)
|
||||
switch cName {
|
||||
case "pid", "cid", "area", "language", "year":
|
||||
qw = qw.Where(fmt.Sprintf("%s = ?", cName), value)
|
||||
// 如果value是 其它 则进行特殊处理
|
||||
var ts []string
|
||||
if v, flag := value.(string); flag && strings.EqualFold(v, "其它") {
|
||||
for _, s := range GetTagsByTitle(st.Pid, t.Field(i).Name) {
|
||||
ts = append(ts, strings.Split(s, ":")[1])
|
||||
}
|
||||
}
|
||||
k := strings.ToLower(t.Field(i).Name)
|
||||
switch k {
|
||||
case "pid", "cid", "year":
|
||||
qw = qw.Where(fmt.Sprintf("%s = ?", k), value)
|
||||
case "area", "language":
|
||||
if strings.EqualFold(value.(string), "其它") {
|
||||
qw = qw.Where(fmt.Sprintf("%s NOT IN ?", k), ts)
|
||||
break
|
||||
}
|
||||
qw = qw.Where(fmt.Sprintf("%s = ?", k), value)
|
||||
case "plot":
|
||||
if strings.EqualFold(value.(string), "其它") {
|
||||
for _, t := range ts {
|
||||
qw = qw.Where("class_tag NOT LIKE ?", fmt.Sprintf("%%%v%%", t))
|
||||
}
|
||||
break
|
||||
}
|
||||
qw = qw.Where("class_tag LIKE ?", fmt.Sprintf("%%%v%%", value))
|
||||
case "sort":
|
||||
if strings.EqualFold(value.(string), "release_stamp") {
|
||||
qw.Order(fmt.Sprintf("year DESC ,%v Desc", value))
|
||||
break
|
||||
}
|
||||
qw.Order(fmt.Sprintf("%v Desc", value))
|
||||
default:
|
||||
break
|
||||
}
|
||||
//// 处理特殊条件
|
||||
//if strings.EqualFold(cName, "sort") {
|
||||
// qw.Order(fmt.Sprintf("year Desc, %v Desc", cName))
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,7 +615,7 @@ func GetMovieListBySort(t int, pid int64, page *Page) []MovieBasicInfo {
|
||||
switch t {
|
||||
case 0:
|
||||
// 最新上映 (上映时间)
|
||||
qw.Order("year DESC, release_date DESC")
|
||||
qw.Order("year DESC, release_stamp DESC")
|
||||
case 1:
|
||||
// 排行榜 (暂定为热度排行)
|
||||
qw.Order("year DESC, hits DESC")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package param
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
func IsEmpty(target any) bool {
|
||||
switch target.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
|
||||
log.Println(`target == 0`, target == 0)
|
||||
return target == reflect.Zero(reflect.TypeOf(target)).Interface()
|
||||
case string:
|
||||
return target == ""
|
||||
|
||||
@@ -29,8 +29,7 @@ import (
|
||||
*/
|
||||
|
||||
const (
|
||||
MainSite = "https://cj.lziapi.com/api.php/provide/vod/"
|
||||
//MainSite = "https://cj.lzcaiji.com/api.php/provide/vod/"
|
||||
MainSite = "https://cj.lzcaiji.com/api.php/provide/vod/"
|
||||
)
|
||||
|
||||
type Site struct {
|
||||
@@ -41,15 +40,16 @@ type Site struct {
|
||||
// SiteList 播放源采集站
|
||||
var SiteList = []Site{
|
||||
// 备用采集站
|
||||
//{"lz_bk", "https://cj.lzcaiji.com/api.php/provide/vod/"},
|
||||
//{"fs", "https://www.feisuzyapi.com/api.php/provide/vod/"},
|
||||
//{"su", "https://subocaiji.com/api.php/provide/vod/at/json"},
|
||||
//{"bf", "https://bfzyapi.com/api.php/provide/vod/"},
|
||||
//{"ff", "https://cj.ffzyapi.com/api.php/provide/vod/"},
|
||||
//{"ff", "https://svip.ffzyapi8.com/api.php/provide/vod/"},
|
||||
|
||||
//{"lz", "https://cj.lziapi.com/api.php/provide/vod/"},
|
||||
{"fs", "https://www.feisuzyapi.com/api.php/provide/vod/"},
|
||||
{"bf", "http://by.bfzyapi.com/api.php/provide/vod/"},
|
||||
{"kk", "https://kuaikan-api.com/api.php/provide/vod/from/kuaikan"},
|
||||
{"bf", "http://by.bfzyapi.com/api.php/provide/vod/"},
|
||||
{"ff", "https://cj.ffzyapi.com/api.php/provide/vod/"},
|
||||
}
|
||||
|
||||
// StartSpider 执行多源spider
|
||||
@@ -60,15 +60,16 @@ func StartSpider() {
|
||||
// 爬取主站点数据
|
||||
MainSiteSpider()
|
||||
log.Println("MainSiteSpider 主站点影片信息保存完毕")
|
||||
// 查找并创建search数据库
|
||||
// 查找并创建search数据库, 保存search信息, 添加索引
|
||||
time.Sleep(time.Second * 10)
|
||||
model.CreateSearchTable()
|
||||
SearchInfoToMdb()
|
||||
model.AddSearchIndex()
|
||||
log.Println("SearchInfoToMdb 影片检索信息保存完毕")
|
||||
// 获取其他站点数据13
|
||||
//go MtSiteSpider()
|
||||
//log.Println("Spider End , 数据保存执行完成")
|
||||
//time.Sleep(time.Second * 10)
|
||||
//获取其他站点数据13
|
||||
go MtSiteSpider()
|
||||
log.Println("Spider End , 数据保存执行完成")
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
|
||||
// CategoryList 获取分类数据
|
||||
|
||||
@@ -18,9 +18,10 @@ func SetupRouter() *gin.Engine {
|
||||
r.GET(`/filmDetail`, controller.FilmDetail)
|
||||
r.GET(`/filmPlayInfo`, controller.FilmPlayInfo)
|
||||
r.GET(`/searchFilm`, controller.SearchFilm)
|
||||
r.GET(`/filmCategory`, controller.FilmCategory)
|
||||
r.GET(`/filmClassify`, controller.FilmClassify)
|
||||
r.GET(`/filmClassifySearch`, controller.FilmTagSearch)
|
||||
// 弃用
|
||||
//r.GET(`/filmCategory`, controller.FilmCategory)
|
||||
|
||||
// 触发spider
|
||||
spiderRoute := r.Group(`/spider`)
|
||||
|
||||
Reference in New Issue
Block a user