mirror of
https://github.com/ProudMuBai/GoFilm.git
synced 2026-04-08 06:07:34 +08:00
optimize player
This commit is contained in:
@@ -11,10 +11,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@videojs-player/vue": "^1.0.0",
|
||||
"axios": "^1.3.4",
|
||||
"element-plus": "^2.3.2",
|
||||
"vue": "^3.2.47",
|
||||
"vue3-video-play": "^1.3.1-beta.6"
|
||||
"video.js": "^8.0.4",
|
||||
"vue": "^3.2.47"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</div>
|
||||
<div class="play_list">
|
||||
<h2 class="hidden-md-and-down">播放列表:(右侧切换播放源)</h2>
|
||||
<el-tabs type="card" class="plya_tabs" tab-transition="fade" tab-animation="300" lazy>
|
||||
<el-tabs type="card" class="play_tabs">
|
||||
<el-tab-pane v-for="(p,i) in data.detail.playList" :label="`播放地址${i+1}`" >
|
||||
<div class="play_content">
|
||||
<a v-for="(item,index) in p" href="javascript:;"
|
||||
@@ -136,7 +136,7 @@ const showContent = (flag: boolean) => {
|
||||
</script>
|
||||
|
||||
<!--移动端适配-->
|
||||
<style>
|
||||
<style scoped>
|
||||
@media (max-width: 650px) {
|
||||
.title_mt {
|
||||
padding: 0 3px;
|
||||
@@ -190,6 +190,13 @@ const showContent = (flag: boolean) => {
|
||||
font-size: 12px;
|
||||
padding: 6px 12px !important;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
width: 70px;
|
||||
height: 35px!important;
|
||||
margin: 17px 5px 0 0 !important;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -236,9 +243,16 @@ const showContent = (flag: boolean) => {
|
||||
margin: 8px 12px;
|
||||
background: #888888;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.plya_tabs {
|
||||
|
||||
.play_active {
|
||||
color: orange !important;
|
||||
background: #424242 !important;
|
||||
}
|
||||
|
||||
.play_content .play_tabs {
|
||||
background: #2e2e2e;
|
||||
}
|
||||
|
||||
@@ -252,7 +266,7 @@ const showContent = (flag: boolean) => {
|
||||
margin-bottom: 0;
|
||||
border-bottom: none !important;
|
||||
background: rgb(34, 34, 34);
|
||||
height: 65px !important;
|
||||
height: 50px !important;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav) {
|
||||
@@ -269,8 +283,8 @@ const showContent = (flag: boolean) => {
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
height: 65px;
|
||||
line-height: 65px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
margin-left: 2px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
border: none !important;
|
||||
@@ -278,8 +292,6 @@ const showContent = (flag: boolean) => {
|
||||
background: #2e2e2e;
|
||||
}
|
||||
|
||||
:deep(.el-tab-pane) {
|
||||
}
|
||||
|
||||
/*顶部影片信息显示区域*/
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<template>
|
||||
<div class="player_area" v-show="data.loading">
|
||||
<div class="player_p" >
|
||||
<videoPlay class="player" v-bind="data.options" poster='/src/assets/image/play.png'
|
||||
/>
|
||||
</div>
|
||||
<div class="player_p">
|
||||
<video-player @mounted="handleBtn" :src="data.options.src" poster="https://s2.loli.net/2023/04/10/H23F6qDXlnwmPG9.png" controls :loop="false"
|
||||
@keydown="handlePlay"
|
||||
:volume="data.options.volume"
|
||||
crossorigin="anonymous" playsinline class="video-player"
|
||||
:playback-rates="[0.5, 1.0, 1.5, 2.0]" />
|
||||
</div>
|
||||
<div class="current_play_info">
|
||||
<div class="play_info_left">
|
||||
<h3 class="current_play_title">{{ `${data.detail.name} ${data.current.episode}` }}</h3>
|
||||
@@ -23,12 +26,13 @@
|
||||
<!-- 播放选集 -->
|
||||
<div class="play_list">
|
||||
<h2 class="hidden-md-and-down">播放列表:(右侧切换播放源)</h2>
|
||||
<el-tabs type="card" v-model="data.currentTabName" class="plya_tabs" >
|
||||
<el-tabs type="card" v-model="data.currentTabName" class="plya_tabs">
|
||||
<el-tab-pane v-for="(p,i) in data.detail.playList"
|
||||
:name="`tab-${i}`"
|
||||
:label="`播放列表${i+1}`">
|
||||
<div class="play_content">
|
||||
<a v-for="(item,index) in p" href="javascript:void(false)" @click="playChange({sourceIndex: i, episodeIndex: index, target: this})"
|
||||
<a v-for="(item,index) in p" href="javascript:void(false)"
|
||||
@click="playChange({sourceIndex: i, episodeIndex: index, target: this})"
|
||||
:class="item.link == data.current.link?'play_active':''">{{ item.episode }}</a>
|
||||
|
||||
</div>
|
||||
@@ -47,12 +51,57 @@
|
||||
import {onBeforeMount, onMounted, reactive, ref, withDirectives} from "vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {ApiGet} from "../../utils/request";
|
||||
import {ElMessage} from "element-plus";
|
||||
import RelateList from "../../components/RelateList.vue";
|
||||
import {Promotion} from "@element-plus/icons-vue";
|
||||
// 引入视频播放器组件
|
||||
import 'vue3-video-play/dist/style.css'
|
||||
import {videoPlay } from 'vue3-video-play'
|
||||
import {ElMessage} from "element-plus";
|
||||
import {VideoPlayer} from '@videojs-player/vue'
|
||||
import 'video.js/dist/video-js.css'
|
||||
const handlePlay = (e:any)=>{
|
||||
e.preventDefault()
|
||||
switch (e.keyCode) {
|
||||
case 32:
|
||||
console.log(e.target.paused)
|
||||
if(e.target.paused) {
|
||||
e.target.play()
|
||||
} else {
|
||||
e.target.pause()
|
||||
}
|
||||
break
|
||||
case 37:
|
||||
e.target.currentTime = e.target.currentTime-5 < 0 ? 0 : e.target.currentTime-5
|
||||
break
|
||||
case 39:
|
||||
e.target.currentTime = e.target.currentTime+5 > e.target.duration ? e.target.duration : e.target.currentTime+5
|
||||
break
|
||||
case 38:
|
||||
data.options.volume = data.options.volume + 0.05 > 1 ? 1 : data.options.volume + 0.05
|
||||
break
|
||||
case 40:
|
||||
data.options.volume = data.options.volume - 0.05 < 0 ? 0 : data.options.volume - 0.05
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
// 主动触发快捷键
|
||||
const tiggerKeyMap = (keyCode:number)=>{
|
||||
let player = document.getElementsByTagName("video")[0]
|
||||
player.focus()
|
||||
const event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('keydown', true, false);
|
||||
event.keyCode = keyCode; // 设置键码
|
||||
player.dispatchEvent(event)
|
||||
}
|
||||
const handleBtn = (e:any)=> {
|
||||
let btns = document.getElementsByClassName('vjs-button')
|
||||
for (let el of btns) {
|
||||
el.addEventListener('keydown', function (t:any){
|
||||
t.preventDefault()
|
||||
tiggerKeyMap(t.keyCode)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 播放页所需数据
|
||||
@@ -64,23 +113,12 @@ const data = reactive({
|
||||
currentPlayFrom: 0,
|
||||
currentEpisode: 0,
|
||||
relate: [{}],
|
||||
// vue3-video-play 播放属性设置
|
||||
// @videojs-player 播放属性设置
|
||||
options: {
|
||||
width: '100%', //播放器高度
|
||||
height: '100%', //播放器高度
|
||||
color: "rgba(155,73,231,0.72)", //主题色
|
||||
title: "", //视频名称
|
||||
src: "", //视频源
|
||||
type: 'm3u8', //视频类型
|
||||
muted: false, //静音
|
||||
webFullScreen: false,
|
||||
speedRate: ["0.75", "1.0", "1.25", "1.5", "2.0"], //播放倍速
|
||||
autoPlay: false, //自动播放
|
||||
loop: false, //循环播放
|
||||
mirror: false, //镜像画面
|
||||
ligthOff: false, //关灯模式
|
||||
volume: 0.3, //默认音量大小
|
||||
control: true, //是否显示控制器
|
||||
volume: 0.6, // 音量
|
||||
currentTime: 0,
|
||||
}
|
||||
|
||||
})
|
||||
@@ -108,32 +146,54 @@ onBeforeMount(() => {
|
||||
})
|
||||
|
||||
// 点击播集数播放对应影片
|
||||
const playChange = (play: { sourceIndex: number, episodeIndex: number, target:any }) => {
|
||||
const playChange = (play: { sourceIndex: number, episodeIndex: number, target: any }) => {
|
||||
let currPlay = data.detail.playList[play.sourceIndex][play.episodeIndex]
|
||||
data.current = {index: play.episodeIndex, episode: currPlay.episode, link: currPlay.link}
|
||||
data.options.src = currPlay.link
|
||||
data.options.title = `${data.detail.name} ${currPlay.episode} `
|
||||
data.options.title = data.detail.name + " " + currPlay.episode
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/*vue3-video-play 相关设置*/
|
||||
/*//播放器控件区域大小*/
|
||||
:deep(#refPlayerWrap) {
|
||||
.video-player {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border-radius: 6px;
|
||||
position: absolute;
|
||||
}
|
||||
/*将鼠标右键触发元素的层级降低,回避触发右键视频菜单信息*/
|
||||
:deep(.d-player-contextmenu){
|
||||
z-index: -100!important;
|
||||
border-radius: 6px;
|
||||
|
||||
}
|
||||
|
||||
:deep(.vjs-big-play-button){
|
||||
line-height: 2em;
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: rgba(0,0,0,0.65);
|
||||
}
|
||||
:deep(.vjs-control-bar){
|
||||
background: rgba(0,0,0,0.32);
|
||||
}
|
||||
/*取消video被选中的白边*/
|
||||
:deep(video:focus) {
|
||||
border: none!important;
|
||||
outline: none;
|
||||
}
|
||||
:deep(.data-vjs-player:focus){
|
||||
border: none!important;
|
||||
outline: none;
|
||||
}
|
||||
:deep(.vjs-tech){
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
:deep(img) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/*当前播放的影片信息展示*/
|
||||
.current_play_info {
|
||||
@@ -177,6 +237,7 @@ const playChange = (play: { sourceIndex: number, episodeIndex: number, target:an
|
||||
margin: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.play_content a {
|
||||
font-size: 12px;
|
||||
flex-basis: calc(10% - 24px);
|
||||
@@ -196,7 +257,6 @@ const playChange = (play: { sourceIndex: number, episodeIndex: number, target:an
|
||||
margin: 0;
|
||||
padding-bottom: 56.25% !important;
|
||||
position: relative;
|
||||
background: red;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
}
|
||||
@@ -228,7 +288,6 @@ const playChange = (play: { sourceIndex: number, episodeIndex: number, target:an
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*集数选中效果*/
|
||||
.play_active {
|
||||
color: orange !important;
|
||||
@@ -290,6 +349,7 @@ const playChange = (play: { sourceIndex: number, episodeIndex: number, target:an
|
||||
.player_area {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.tags b {
|
||||
padding: 5px 10px;
|
||||
background-color: rgba(155, 73, 231, 0.72);
|
||||
@@ -308,6 +368,7 @@ const playChange = (play: { sourceIndex: number, episodeIndex: number, target:an
|
||||
font-size: 12px;
|
||||
padding: 6px 12px !important;
|
||||
}
|
||||
|
||||
.tags span {
|
||||
padding: 6px 10px;
|
||||
background-color: #404042;
|
||||
@@ -316,10 +377,11 @@ const playChange = (play: { sourceIndex: number, episodeIndex: number, target:an
|
||||
margin: 0 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
:deep(.el-tabs__item){
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
width: 70px;
|
||||
height: 35px;
|
||||
margin: 17px 5px 0 0!important;
|
||||
margin: 17px 5px 0 0 !important;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,29 +7,29 @@ import {ElementPlusResolver} from "unplugin-vue-components/resolvers";
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
// 本地测试环境
|
||||
// server: {
|
||||
// host: '0.0.0.0',
|
||||
// port: 3600,
|
||||
// proxy: {
|
||||
// "/api": {
|
||||
// target: `http://127.0.0.1:3601`,
|
||||
// changeOrigin: true, // 允许跨域
|
||||
// rewrite: path => path.replace(/^\/api/,'')
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// nginx发布构建时使用此配置
|
||||
server: {
|
||||
host: 'localhost',
|
||||
host: '0.0.0.0',
|
||||
port: 3600,
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: `http://localhost`,
|
||||
target: `http://127.0.0.1:3601`,
|
||||
changeOrigin: true, // 允许跨域
|
||||
rewrite: path => path.replace(/^\/api/,'')
|
||||
}
|
||||
},
|
||||
},
|
||||
// nginx发布构建时使用此配置
|
||||
// server: {
|
||||
// host: 'localhost',
|
||||
// port: 3600,
|
||||
// proxy: {
|
||||
// "/api": {
|
||||
// target: `http://localhost`,
|
||||
// changeOrigin: true, // 允许跨域
|
||||
// rewrite: path => path.replace(/^\/api/,'')
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
|
||||
plugins: [
|
||||
vue(),
|
||||
|
||||
118
film/data/nginx/html/assets/index-4e26142c.js
Normal file
118
film/data/nginx/html/assets/index-4e26142c.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
film/data/nginx/html/assets/index-bf20f8e3.css
Normal file
1
film/data/nginx/html/assets/index-bf20f8e3.css
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 MiB |
BIN
film/data/nginx/html/favicon.ico
Normal file
BIN
film/data/nginx/html/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -11,8 +11,8 @@
|
||||
<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-be062d0f.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-aa1f0a70.css">
|
||||
<script type="module" crossorigin src="/assets/index-4e26142c.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index-bf20f8e3.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -53,7 +53,7 @@ const (
|
||||
|
||||
//mysql服务配置信息 root:root 设置mysql账户的用户名和密码
|
||||
|
||||
//MysqlDsn = "root:root@(192.168.20.10:3307)/FilmSite?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
// MysqlDsn = "root:root@(192.168.20.10:3307)/FilmSite?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
|
||||
// MysqlDsn docker compose 环境下的链接信息 mysql:3306 为 docker compose 中 mysql服务对应的网络名称和端口
|
||||
MysqlDsn = "root:root@(mysql:3306)/FilmSite?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
@@ -64,9 +64,9 @@ const (
|
||||
RedisPassword redis访问密码
|
||||
RedisDBNo 使用第几号库
|
||||
*/
|
||||
//RedisAddr = `192.168.20.10:6379`
|
||||
//RedisPassword = `root`
|
||||
//RedisDBNo = 1
|
||||
// RedisAddr = `192.168.20.10:6379`
|
||||
// RedisPassword = `root`
|
||||
// RedisDBNo = 1
|
||||
|
||||
// RedisAddr docker compose 环境下运行使用如下配置信息
|
||||
RedisAddr = `redis:6379`
|
||||
|
||||
@@ -2,11 +2,9 @@ package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"net/http"
|
||||
"server/config"
|
||||
"server/model"
|
||||
"server/plugin/spider"
|
||||
"server/logic"
|
||||
)
|
||||
|
||||
// SpiderRe 数据清零重开
|
||||
@@ -20,8 +18,7 @@ func SpiderRe(c *gin.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
// 如果指令正确,则执行重制
|
||||
spider.StartSpiderRe()
|
||||
logic.SL.ReZero()
|
||||
}
|
||||
|
||||
// FixFilmDetail 修复因网络异常造成的影片详情数据丢失
|
||||
@@ -36,11 +33,22 @@ func FixFilmDetail(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
// 如果指令正确,则执行详情数据获取
|
||||
spider.MainSiteSpider()
|
||||
log.Println("FilmDetail 重制完成!!!")
|
||||
// 先截断表中的数据
|
||||
model.TunCateSearchTable()
|
||||
// 重新扫描完整的信息到mysql中
|
||||
spider.SearchInfoToMdb()
|
||||
log.Println("SearchInfo 重制完成!!!")
|
||||
logic.SL.FixDetail()
|
||||
}
|
||||
|
||||
// RefreshSitePlay 清空附属站点影片数据并重新获取
|
||||
func RefreshSitePlay(c *gin.Context) {
|
||||
// 获取指令参数
|
||||
cip := c.Query("cipher")
|
||||
if cip != config.SpiderCipher {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusFailed,
|
||||
"message": "指令错误无法进行此操作",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 执行多站点播放数据重置
|
||||
logic.SL.SpiderMtPlayRe()
|
||||
|
||||
}
|
||||
|
||||
44
film/server/logic/SpiderLogic.go
Normal file
44
film/server/logic/SpiderLogic.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"server/config"
|
||||
"server/model"
|
||||
"server/plugin/spider"
|
||||
)
|
||||
|
||||
type SpiderLogic struct {
|
||||
}
|
||||
|
||||
var SL *SpiderLogic
|
||||
|
||||
// ReZero 清空所有数据从零开始拉取
|
||||
func (sl *SpiderLogic) ReZero() {
|
||||
// 如果指令正确,则执行重制
|
||||
spider.StartSpiderRe()
|
||||
}
|
||||
|
||||
// FixDetail 重新获取主站点数据信息
|
||||
func (sl *SpiderLogic) FixDetail() {
|
||||
spider.MainSiteSpider()
|
||||
log.Println("FilmDetail 重制完成!!!")
|
||||
// 先截断表中的数据
|
||||
model.TunCateSearchTable()
|
||||
// 重新扫描完整的信息到mysql中
|
||||
spider.SearchInfoToMdb()
|
||||
log.Println("SearchInfo 重制完成!!!")
|
||||
}
|
||||
|
||||
// SpiderMtPlayRe 多站点播放数据清空重新获取
|
||||
func (sl *SpiderLogic) SpiderMtPlayRe() {
|
||||
// 先清空有所附加播放源
|
||||
var keys []string
|
||||
for _, site := range spider.SiteList {
|
||||
keys = append(keys, fmt.Sprintf(config.MultipleSiteDetail, site.Name))
|
||||
}
|
||||
model.DelMtPlay(keys)
|
||||
// 如果指令正确,则执行详情数据获取
|
||||
spider.MtSiteSpider()
|
||||
log.Println("MtSiteSpider 重制完成!!!")
|
||||
}
|
||||
@@ -89,6 +89,11 @@ func RemoveAll() {
|
||||
db.Mdb.Exec(fmt.Sprintf(`drop table if exists %s`, s.TableName()))
|
||||
}
|
||||
|
||||
// DelMtPlay 清空附加播放源信息
|
||||
func DelMtPlay(keys []string) {
|
||||
db.Rdb.Del(db.Cxt, keys...)
|
||||
}
|
||||
|
||||
// ================================= Spider 数据处理(mysql) =================================
|
||||
|
||||
// CreateSearchTable 创建存储检索信息的数据表
|
||||
@@ -211,12 +216,12 @@ func SearchFilmKeyword(keyword string, page *Page) []SearchInfo {
|
||||
var searchList []SearchInfo
|
||||
// 1. 先统计搜索满足条件的数据量
|
||||
var count int64
|
||||
db.Mdb.Model(&SearchInfo{}).Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Count(&count)
|
||||
db.Mdb.Model(&SearchInfo{}).Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Or("sub_title LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Count(&count)
|
||||
page.Total = int(count)
|
||||
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
|
||||
// 2. 获取满足条件的数据
|
||||
db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).
|
||||
Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Order("year DESC, time DESC").Find(&searchList)
|
||||
Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Or("sub_title LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Order("year DESC, time DESC").Find(&searchList)
|
||||
return searchList
|
||||
}
|
||||
|
||||
@@ -259,7 +264,7 @@ func GetRelateMovieBasicInfo(search SearchInfo, page *Page) []MovieBasicInfo {
|
||||
re := regexp.MustCompile("第.{1,3}季")
|
||||
if re.MatchString(search.Name) {
|
||||
search.Name = re.ReplaceAllString(search.Name, "")
|
||||
sql = fmt.Sprintf(`select * from %s where name LIKE "%%%s%%" union`, search.TableName(), search.Name)
|
||||
sql = fmt.Sprintf(`select * from %s where name LIKE "%%%s%%" or sub_title LIKE "%%%[2]s%%" union`, search.TableName(), search.Name)
|
||||
}
|
||||
// 执行后续匹配内容
|
||||
//sql = fmt.Sprintf(`%s select * from %s where cid=%d AND area="%s" AND language="%s" AND`, sql, search.TableName(), search.Cid, search.Area, search.Language)
|
||||
|
||||
@@ -24,7 +24,7 @@ func InitMysql() (err error) {
|
||||
SingularTable: true, //是否使用 结构体名称作为表名 (关闭自动变复数)
|
||||
//NameReplacer: strings.NewReplacer("spider_", ""), // 替表名和字段中的 Me 为 空
|
||||
},
|
||||
//Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
|
||||
//Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
3. api数据格式不变, 获取影片详情时通过subTitle 去redis匹配其他站点的对应播放源并整合到主站详情信息的playUrl中
|
||||
4. 影片搜索时不再使用name进行匹配, 改为使用 subTitle 进行匹配
|
||||
*/
|
||||
|
||||
const (
|
||||
MainSite = "https://www.feisuzyapi.com/api.php/provide/vod/"
|
||||
)
|
||||
@@ -40,10 +41,11 @@ type Site struct {
|
||||
var SiteList = []Site{
|
||||
//{"tk", "https://api.tiankongapi.com/api.php/provide/vod"},
|
||||
//{"yh", "https://m3u8.apiyhzy.com/api.php/provide/vod/"},
|
||||
{"su", "https://subocaiji.com/api.php/provide/vod/at/json"},
|
||||
//{"fs", "https://www.feisuzyapi.com/api.php/provide/vod/"},
|
||||
|
||||
{"lz", "https://cj.lziapi.com/api.php/provide/vod/"},
|
||||
{"ff", "https://cj.ffzyapi.com/api.php/provide/vod/"},
|
||||
//{"fs", "https://www.feisuzyapi.com/api.php/provide/vod/"},
|
||||
{"su", "https://subocaiji.com/api.php/provide/vod/at/json"},
|
||||
}
|
||||
|
||||
// StartSpider 执行多源spider
|
||||
@@ -249,7 +251,7 @@ func UpdateMainDetail() {
|
||||
func UpdatePlayDetail() {
|
||||
for _, s := range SiteList {
|
||||
// 获取单个站点的分页数
|
||||
r := RequestInfo{Uri: MainSite, Params: url.Values{}}
|
||||
r := RequestInfo{Uri: s.Name, Params: url.Values{}}
|
||||
r.Params.Set("h", config.UpdateInterval)
|
||||
pageCount, err := GetPageCount(r)
|
||||
if err != nil {
|
||||
|
||||
@@ -27,6 +27,7 @@ func SetupRouter() *gin.Engine {
|
||||
spiderRoute.GET("/SpiderRe", controller.SpiderRe)
|
||||
// 获取影片详情, 用于网路不稳定导致的影片数据缺失
|
||||
spiderRoute.GET(`/FixFilmDetail`, controller.FixFilmDetail)
|
||||
spiderRoute.GET(`/RefreshSitePlay`, controller.RefreshSitePlay)
|
||||
}
|
||||
|
||||
return r
|
||||
|
||||
@@ -49,14 +49,14 @@ const (
|
||||
const (
|
||||
|
||||
// SearchTableName 存放检索信息的数据表名
|
||||
SearchTableName = "search"
|
||||
SearchTableName = "search_mt"
|
||||
|
||||
//mysql服务配置信息 root:root 设置mysql账户的用户名和密码
|
||||
|
||||
//MysqlDsn = "root:root@(192.168.20.10:3307)/FilmSite?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
MysqlDsn = "root:root@(192.168.20.10:3307)/FilmSite?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
|
||||
// MysqlDsn docker compose 环境下的链接信息 mysql:3306 为 docker compose 中 mysql服务对应的网络名称和端口
|
||||
MysqlDsn = "root:root@(mysql:3306)/FilmSite?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
//MysqlDsn = "root:root@(mysql:3306)/FilmSite?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
|
||||
/*
|
||||
redis 配置信息
|
||||
@@ -64,12 +64,12 @@ const (
|
||||
RedisPassword redis访问密码
|
||||
RedisDBNo 使用第几号库
|
||||
*/
|
||||
//RedisAddr = `192.168.20.10:6379`
|
||||
//RedisPassword = `root`
|
||||
//RedisDBNo = 1
|
||||
RedisAddr = `192.168.20.10:6379`
|
||||
RedisPassword = `root`
|
||||
RedisDBNo = 1
|
||||
|
||||
// RedisAddr docker compose 环境下运行使用如下配置信息
|
||||
RedisAddr = `redis:6379`
|
||||
RedisPassword = `root`
|
||||
RedisDBNo = 0
|
||||
//RedisAddr = `redis:6379`
|
||||
//RedisPassword = `root`
|
||||
//RedisDBNo = 0
|
||||
)
|
||||
|
||||
@@ -2,11 +2,9 @@ package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"net/http"
|
||||
"server/config"
|
||||
"server/model"
|
||||
"server/plugin/spider"
|
||||
"server/logic"
|
||||
)
|
||||
|
||||
// SpiderRe 数据清零重开
|
||||
@@ -20,8 +18,7 @@ func SpiderRe(c *gin.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
// 如果指令正确,则执行重制
|
||||
spider.StartSpiderRe()
|
||||
logic.SL.ReZero()
|
||||
}
|
||||
|
||||
// FixFilmDetail 修复因网络异常造成的影片详情数据丢失
|
||||
@@ -36,11 +33,22 @@ func FixFilmDetail(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
// 如果指令正确,则执行详情数据获取
|
||||
spider.MainSiteSpider()
|
||||
log.Println("FilmDetail 重制完成!!!")
|
||||
// 先截断表中的数据
|
||||
model.TunCateSearchTable()
|
||||
// 重新扫描完整的信息到mysql中
|
||||
spider.SearchInfoToMdb()
|
||||
log.Println("SearchInfo 重制完成!!!")
|
||||
logic.SL.FixDetail()
|
||||
}
|
||||
|
||||
// RefreshSitePlay 清空附属站点影片数据并重新获取
|
||||
func RefreshSitePlay(c *gin.Context) {
|
||||
// 获取指令参数
|
||||
cip := c.Query("cipher")
|
||||
if cip != config.SpiderCipher {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": StatusFailed,
|
||||
"message": "指令错误无法进行此操作",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 执行多站点播放数据重置
|
||||
logic.SL.SpiderMtPlayRe()
|
||||
|
||||
}
|
||||
|
||||
44
server/logic/SpiderLogic.go
Normal file
44
server/logic/SpiderLogic.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"server/config"
|
||||
"server/model"
|
||||
"server/plugin/spider"
|
||||
)
|
||||
|
||||
type SpiderLogic struct {
|
||||
}
|
||||
|
||||
var SL *SpiderLogic
|
||||
|
||||
// ReZero 清空所有数据从零开始拉取
|
||||
func (sl *SpiderLogic) ReZero() {
|
||||
// 如果指令正确,则执行重制
|
||||
spider.StartSpiderRe()
|
||||
}
|
||||
|
||||
// FixDetail 重新获取主站点数据信息
|
||||
func (sl *SpiderLogic) FixDetail() {
|
||||
spider.MainSiteSpider()
|
||||
log.Println("FilmDetail 重制完成!!!")
|
||||
// 先截断表中的数据
|
||||
model.TunCateSearchTable()
|
||||
// 重新扫描完整的信息到mysql中
|
||||
spider.SearchInfoToMdb()
|
||||
log.Println("SearchInfo 重制完成!!!")
|
||||
}
|
||||
|
||||
// SpiderMtPlayRe 多站点播放数据清空重新获取
|
||||
func (sl *SpiderLogic) SpiderMtPlayRe() {
|
||||
// 先清空有所附加播放源
|
||||
var keys []string
|
||||
for _, site := range spider.SiteList {
|
||||
keys = append(keys, fmt.Sprintf(config.MultipleSiteDetail, site.Name))
|
||||
}
|
||||
model.DelMtPlay(keys)
|
||||
// 如果指令正确,则执行详情数据获取
|
||||
spider.MtSiteSpider()
|
||||
log.Println("MtSiteSpider 重制完成!!!")
|
||||
}
|
||||
@@ -89,6 +89,11 @@ func RemoveAll() {
|
||||
db.Mdb.Exec(fmt.Sprintf(`drop table if exists %s`, s.TableName()))
|
||||
}
|
||||
|
||||
// DelMtPlay 清空附加播放源信息
|
||||
func DelMtPlay(keys []string) {
|
||||
db.Rdb.Del(db.Cxt, keys...)
|
||||
}
|
||||
|
||||
// ================================= Spider 数据处理(mysql) =================================
|
||||
|
||||
// CreateSearchTable 创建存储检索信息的数据表
|
||||
@@ -211,12 +216,12 @@ func SearchFilmKeyword(keyword string, page *Page) []SearchInfo {
|
||||
var searchList []SearchInfo
|
||||
// 1. 先统计搜索满足条件的数据量
|
||||
var count int64
|
||||
db.Mdb.Model(&SearchInfo{}).Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Count(&count)
|
||||
db.Mdb.Model(&SearchInfo{}).Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Or("sub_title LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Count(&count)
|
||||
page.Total = int(count)
|
||||
page.PageCount = int((page.Total + page.PageSize - 1) / page.PageSize)
|
||||
// 2. 获取满足条件的数据
|
||||
db.Mdb.Limit(page.PageSize).Offset((page.Current-1)*page.PageSize).
|
||||
Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Order("year DESC, time DESC").Find(&searchList)
|
||||
Where("name LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Or("sub_title LIKE ?", fmt.Sprint(`%`, keyword, `%`)).Order("year DESC, time DESC").Find(&searchList)
|
||||
return searchList
|
||||
}
|
||||
|
||||
@@ -259,7 +264,7 @@ func GetRelateMovieBasicInfo(search SearchInfo, page *Page) []MovieBasicInfo {
|
||||
re := regexp.MustCompile("第.{1,3}季")
|
||||
if re.MatchString(search.Name) {
|
||||
search.Name = re.ReplaceAllString(search.Name, "")
|
||||
sql = fmt.Sprintf(`select * from %s where name LIKE "%%%s%%" union`, search.TableName(), search.Name)
|
||||
sql = fmt.Sprintf(`select * from %s where name LIKE "%%%s%%" or sub_title LIKE "%%%[2]s%%" union`, search.TableName(), search.Name)
|
||||
}
|
||||
// 执行后续匹配内容
|
||||
//sql = fmt.Sprintf(`%s select * from %s where cid=%d AND area="%s" AND language="%s" AND`, sql, search.TableName(), search.Cid, search.Area, search.Language)
|
||||
|
||||
@@ -24,7 +24,7 @@ func InitMysql() (err error) {
|
||||
SingularTable: true, //是否使用 结构体名称作为表名 (关闭自动变复数)
|
||||
//NameReplacer: strings.NewReplacer("spider_", ""), // 替表名和字段中的 Me 为 空
|
||||
},
|
||||
//Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
|
||||
//Logger: logger.Default.LogMode(logger.Info), //设置日志级别为Info
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
3. api数据格式不变, 获取影片详情时通过subTitle 去redis匹配其他站点的对应播放源并整合到主站详情信息的playUrl中
|
||||
4. 影片搜索时不再使用name进行匹配, 改为使用 subTitle 进行匹配
|
||||
*/
|
||||
|
||||
const (
|
||||
MainSite = "https://www.feisuzyapi.com/api.php/provide/vod/"
|
||||
)
|
||||
@@ -40,10 +41,11 @@ type Site struct {
|
||||
var SiteList = []Site{
|
||||
//{"tk", "https://api.tiankongapi.com/api.php/provide/vod"},
|
||||
//{"yh", "https://m3u8.apiyhzy.com/api.php/provide/vod/"},
|
||||
{"su", "https://subocaiji.com/api.php/provide/vod/at/json"},
|
||||
//{"fs", "https://www.feisuzyapi.com/api.php/provide/vod/"},
|
||||
|
||||
{"lz", "https://cj.lziapi.com/api.php/provide/vod/"},
|
||||
{"ff", "https://cj.ffzyapi.com/api.php/provide/vod/"},
|
||||
//{"fs", "https://www.feisuzyapi.com/api.php/provide/vod/"},
|
||||
{"su", "https://subocaiji.com/api.php/provide/vod/at/json"},
|
||||
}
|
||||
|
||||
// StartSpider 执行多源spider
|
||||
@@ -249,7 +251,7 @@ func UpdateMainDetail() {
|
||||
func UpdatePlayDetail() {
|
||||
for _, s := range SiteList {
|
||||
// 获取单个站点的分页数
|
||||
r := RequestInfo{Uri: MainSite, Params: url.Values{}}
|
||||
r := RequestInfo{Uri: s.Name, Params: url.Values{}}
|
||||
r.Params.Set("h", config.UpdateInterval)
|
||||
pageCount, err := GetPageCount(r)
|
||||
if err != nil {
|
||||
|
||||
@@ -27,6 +27,7 @@ func SetupRouter() *gin.Engine {
|
||||
spiderRoute.GET("/SpiderRe", controller.SpiderRe)
|
||||
// 获取影片详情, 用于网路不稳定导致的影片数据缺失
|
||||
spiderRoute.GET(`/FixFilmDetail`, controller.FixFilmDetail)
|
||||
spiderRoute.GET(`/RefreshSitePlay`, controller.RefreshSitePlay)
|
||||
}
|
||||
|
||||
return r
|
||||
|
||||
Reference in New Issue
Block a user