mirror of
https://github.com/ProudMuBai/GoFilm.git
synced 2026-02-04 06:54:41 +08:00
v2 Multiple play source
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "anime_client",
|
||||
"name": "client",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
@@ -13,7 +13,8 @@
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"axios": "^1.3.4",
|
||||
"element-plus": "^2.3.2",
|
||||
"vue": "^3.2.47"
|
||||
"vue": "^3.2.47",
|
||||
"vue3-video-play": "^1.3.1-beta.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<!-- <img class="logo" src="/src/assets/logo.png">-->
|
||||
<a href="/" style="font-weight: 600;font-style: italic;font-size: 24px;margin-right: 5px">Boat</a>
|
||||
<div class="search_group">
|
||||
<input v-model="keyword" placeholder="搜索 动漫,剧集,电影 " class="search"/>
|
||||
<input v-model="keyword" @keydown="(e)=>{e.keyCode == 13 && searchFilm()}" placeholder="搜索 动漫,剧集,电影 " class="search"/>
|
||||
<el-button @click="searchFilm" :icon="Search"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -41,11 +41,11 @@ defineProps({
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-flow: wrap;
|
||||
justify-content: space-between;
|
||||
justify-content: start;
|
||||
}
|
||||
.container .item {
|
||||
width: calc(14% - 18px);
|
||||
margin-bottom: 18px;
|
||||
width: calc(14% - 20px);
|
||||
margin: 2px 10px 16px 10px;
|
||||
}
|
||||
.cus_content_link {
|
||||
border-radius: 5px;
|
||||
@@ -102,11 +102,11 @@ defineProps({
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-flow: wrap;
|
||||
justify-content: space-between;
|
||||
justify-content: start;
|
||||
}
|
||||
.container .item {
|
||||
width: calc(33% - 5px);
|
||||
margin-bottom: 18px;
|
||||
width: calc(33% - 8px);
|
||||
margin: 2px 4px 16px 4px;
|
||||
}
|
||||
.cus_content_link {
|
||||
border-radius: 5px;
|
||||
|
||||
@@ -7,6 +7,7 @@ import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
|
||||
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
||||
@@ -15,6 +16,8 @@ app.use(ElementPlus)
|
||||
app.use(router)
|
||||
|
||||
|
||||
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import axios from "axios";
|
||||
import {ElMessage, ElLoading } from "element-plus";
|
||||
|
||||
// 定义加载动画对象
|
||||
let loading:any
|
||||
// 创建loading加载动画对象
|
||||
const startLoading = ()=>{
|
||||
loading = ElLoading.service({
|
||||
return ElLoading.service({
|
||||
lock: true,
|
||||
text: `请求发送中...`,
|
||||
background: `rgba(255,255,255,0.5)`,
|
||||
text: `加载中...`,
|
||||
background: `rgba(0,0,0,0.5)`,
|
||||
// target: document.querySelector(`.content`)
|
||||
})
|
||||
}
|
||||
const closeLoading = ()=>{
|
||||
loading.close()
|
||||
}
|
||||
|
||||
const http = (options: any) => {
|
||||
// 开启loading动画
|
||||
let loading:any = startLoading()
|
||||
return new Promise((resolve, reject) => {
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
@@ -28,8 +26,7 @@ const http = (options: any) => {
|
||||
// request interceptor
|
||||
service.interceptors.request.use(
|
||||
(config: any) => {
|
||||
// 开启loading动画
|
||||
startLoading()
|
||||
|
||||
// let token: string = ""; //此处换成自己获取回来的token,通常存在在cookie或者store里面
|
||||
// if (token) {
|
||||
// // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
|
||||
@@ -48,12 +45,10 @@ const http = (options: any) => {
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
closeLoading()
|
||||
|
||||
loading.close()
|
||||
return response.data;
|
||||
},
|
||||
(error) => {
|
||||
closeLoading()
|
||||
if (error.response.status == 403) {
|
||||
ElMessage.error("请求异常: ", error)
|
||||
} else {
|
||||
@@ -61,6 +56,7 @@ const http = (options: any) => {
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
);
|
||||
// 请求处理
|
||||
service(options)
|
||||
@@ -70,6 +66,7 @@ const http = (options: any) => {
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<div class="c_header">
|
||||
<a :class="`nav ${d.list.length >0 && d.list[0].cid == c.id?'active':''}`" href="javascript:;" @click="changeCategory(c.id)"
|
||||
v-for="c in d.category.children">{{ c.name }}</a>
|
||||
<!-- <a :class="`nav `" href="javascript:;" @click="changeCategory">{{ d.category.name }}</a>-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,10 +70,10 @@ const changeCurrent = (currentVal: number) => {
|
||||
}
|
||||
|
||||
// 点击分类事件
|
||||
const changeCategory = (cid: any) => {
|
||||
const changeCategory = (cid?: any) => {
|
||||
let params = new URLSearchParams(location.search)
|
||||
// location.href = `/categoryFilm?pid=${params.get('pid')}&cid=${cid}¤t=${params.get('current')?params.get('current'):1}`
|
||||
location.href = `/categoryFilm?pid=${params.get('pid')}&cid=${cid}¤t=1`
|
||||
location.href = cid?`/categoryFilm?pid=${params.get('pid')}&cid=${cid}¤t=1`:`/categoryFilm?pid=${params.get('pid')}`
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +106,7 @@ onMounted(() => {
|
||||
/*顶部内容区域*/
|
||||
.header {
|
||||
width: 100%;
|
||||
margin-bottom: 150px;
|
||||
margin-bottom: 100px;
|
||||
background: none!important;
|
||||
}
|
||||
.header p {
|
||||
@@ -177,14 +178,13 @@ onMounted(() => {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
justify-content: space-between;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.c_content .item {
|
||||
flex-basis: calc(33% - 5px);
|
||||
flex-basis: calc(33% - 6px);
|
||||
max-width: 33%;
|
||||
margin-bottom: 20px;
|
||||
/*width: 100px;*/
|
||||
margin: 0 3px 20px 3px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -305,13 +305,12 @@ onMounted(() => {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
justify-content: space-between;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.c_content .item {
|
||||
flex-basis: calc(14% - 16px);
|
||||
max-width: 14%;
|
||||
margin-bottom: 20px;
|
||||
margin: 0 8px 20px 8px;
|
||||
/*width: 100px;*/
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="film">
|
||||
<div class="film" v-show="data.loading">
|
||||
<!-- hidden-sm-and-up 移动端title -->
|
||||
<div class="hidden-sm-and-up">
|
||||
<div class="title_mt ">
|
||||
@@ -11,7 +11,7 @@
|
||||
</ul>
|
||||
<p><span>导演:</span> {{ data.detail.descriptor.director }}</p>
|
||||
<p><span>主演:</span>
|
||||
{{ `${data.detail.descriptor.actor}`.split(",")[0] + " " + `${data.detail.descriptor.actor}`.split(",")[1] + " " + `${data.detail.descriptor.actor}`.split(",")[2] }}
|
||||
{{ (data.detail.descriptor.actor && data.detail.descriptor.actor.length > 0) ? `${data.detail.descriptor.actor}`.split(",")[0] + " " + `${data.detail.descriptor.actor}`.split(",")[1] : ''}}
|
||||
</p>
|
||||
<p><span>上映:</span> {{ data.detail.descriptor.releaseDate }}</p>
|
||||
<p><span>地区:</span> {{ data.detail.descriptor.area }}</p>
|
||||
@@ -81,12 +81,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {useRouter} from "vue-router";
|
||||
import {onMounted, reactive, ref,} from "vue";
|
||||
import {onBeforeMount, reactive, ref,} from "vue";
|
||||
import {ApiGet} from "../../utils/request";
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {ElMessage, ElLoading} from 'element-plus'
|
||||
import {Promotion, CaretRight} from "@element-plus/icons-vue";
|
||||
import RelateList from "../../components/RelateList.vue";
|
||||
const show = ref(false)
|
||||
|
||||
// 获取路由对象
|
||||
const router = useRouter()
|
||||
@@ -94,15 +93,17 @@ const router = useRouter()
|
||||
const data = reactive({
|
||||
detail: {descriptor: {}},
|
||||
relate: [],
|
||||
loading: false,
|
||||
})
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
onBeforeMount(() => {
|
||||
let link = router.currentRoute.value.query.link
|
||||
ApiGet('/filmDetail', {id: link}).then((resp: any) => {
|
||||
if (resp.status === "ok") {
|
||||
data.detail = resp.data.detail
|
||||
data.relate = resp.data.relate
|
||||
data.loading = true
|
||||
} else {
|
||||
ElMessage({
|
||||
type: "error",
|
||||
@@ -180,7 +181,15 @@ const showContent = (flag: boolean) => {
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.play_content a {
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
margin: 6px 8px;
|
||||
background: #888888;
|
||||
flex-basis: calc(25% - 16px);
|
||||
font-size: 12px;
|
||||
padding: 6px 12px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -217,14 +226,16 @@ const showContent = (flag: boolean) => {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.play_content a {
|
||||
font-size: 12px;
|
||||
min-width: 65px;
|
||||
padding: 6px 15px;
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
margin: 8px 8px;
|
||||
background: #888888;
|
||||
@media (min-width: 650px) {
|
||||
.play_content a {
|
||||
font-size: 12px;
|
||||
flex-basis: calc(10% - 24px);
|
||||
padding: 6px 15px;
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
margin: 8px 12px;
|
||||
background: #888888;
|
||||
}
|
||||
}
|
||||
|
||||
.plya_tabs {
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
<template>
|
||||
|
||||
<div class="player_area">
|
||||
<!-- 视频播放区域-->
|
||||
<div class="player_p">
|
||||
<iframe ref="iframe" class="player" :src="data.current.link"
|
||||
:name="data.detail.name"
|
||||
marginheight="0"
|
||||
marginwidth="0"
|
||||
framespacing="0"
|
||||
vspale="0"
|
||||
frameborder="0" allowfullscreen="true" scolling="no"
|
||||
sandbox="allow-scripts allow-same-origin allow-downloads">
|
||||
</iframe>
|
||||
</div>
|
||||
<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="current_play_info">
|
||||
<div class="play_info_left">
|
||||
<h3 class="current_play_title">{{ `${data.detail.name} ${data.current.episode}` }}</h3>
|
||||
@@ -32,13 +23,14 @@
|
||||
<!-- 播放选集 -->
|
||||
<div class="play_list">
|
||||
<h2 class="hidden-md-and-down">播放列表:(右侧切换播放源)</h2>
|
||||
<el-tabs type="card" v-model="data.currentTabName" class="plya_tabs" @tab-change="changeSource">
|
||||
<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}`">
|
||||
:label="`播放列表${i+1}`">
|
||||
<div class="play_content">
|
||||
<a v-for="(item,index) in p" href="javascript:void(false)" @click="playChange(item)"
|
||||
:class="data.current.link.search(item.link) !== -1?'play_active':''">{{ item.episode }}</a>
|
||||
<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>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -52,120 +44,97 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {onMounted, reactive, ref, withDirectives} from "vue";
|
||||
import {onBeforeMount, onMounted, reactive, ref, withDirectives} from "vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {ApiGet} from "../../utils/request";
|
||||
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";
|
||||
|
||||
|
||||
// 播放页所需数据
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
detail: {descriptor: {}, playList: [[{episode: '', link: ''}]]},
|
||||
current: {episode: '', link: ''},
|
||||
current: {index: 0, episode: '', link: ''},
|
||||
currentTabName: '',
|
||||
currentPlayFrom: 0,
|
||||
currentEpisode: 0,
|
||||
relate: [],
|
||||
relate: [{}],
|
||||
// vue3-video-play 播放属性设置
|
||||
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, //是否显示控制器
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
// 获取路由信息
|
||||
const router = useRouter()
|
||||
onMounted(() => {
|
||||
onBeforeMount(() => {
|
||||
let query = router.currentRoute.value.query
|
||||
ApiGet(`/filmPlayInfo`, {id: query.id, playFrom: query.source, episode: query.episode}).then((resp: any) => {
|
||||
if (resp.status === 'ok') {
|
||||
data.detail = resp.data.detail
|
||||
resp.data.current.link = converLink(resp.data.current.link)
|
||||
data.current = resp.data.current
|
||||
data.current = {index: resp.data.currentEpisode, ...resp.data.current}
|
||||
data.currentPlayFrom = resp.data.currentPlayFrom
|
||||
data.currentEpisode = resp.data.currentEpisode
|
||||
data.relate = resp.data.relate
|
||||
// 设置当前选中的播放源
|
||||
data.currentTabName = `tab-${query.source}`
|
||||
// 设置当前的视频播放url
|
||||
data.options.src = data.current.link
|
||||
data.loading = true
|
||||
} else {
|
||||
ElMessage.error("影片信息加载失败,请尝试刷新页面!!!")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// ===============================视频播放处理=======================================
|
||||
// 视频解析接口地址, 默认使用第一个
|
||||
const resolver = [
|
||||
// m3u8使用此解析
|
||||
'https://jx.jsonplayer.com/player/?url=',
|
||||
// 'https://jx.m3u8.tv/jiexi/?url=',
|
||||
|
||||
|
||||
// 'https://jx.jsonplayer.com/player/?url=',
|
||||
// 'https://vip.bljiex.com/?url=',
|
||||
// 'https://jx.bozrc.com:4433/player/?url=',
|
||||
// html视频使用此解析
|
||||
'http://www.82190555.com/index/qqvod.php?url=',
|
||||
// 'https://jx.bozrc.com:4433/player/?url=',
|
||||
// 'https://vip.bljiex.com/?url=',
|
||||
|
||||
// Google上随便找的
|
||||
'https://vip.bljiex.com/?url=',
|
||||
'https://jx.kingtail.xyz/?url=',
|
||||
'http://www.82190555.com/index/qqvod.php?url=',
|
||||
'https://www.nxflv.com/?url=',
|
||||
'http://www.wmxz.wang/video.php?url=',
|
||||
'https://www.feisuplayer.com/m3u8/?url=',
|
||||
// tampermonkey 脚本使用的解析
|
||||
'https://jx.bozrc.com:4433/player/?url=',
|
||||
'https://z1.m1907.top/?jx=',
|
||||
'https://jx.aidouer.net/?url=',
|
||||
'https://www.gai4.com/?url=',
|
||||
'https://okjx.cc/?url=',
|
||||
'https://jx.rdhk.net/?v=',
|
||||
'https://jx.blbo.cc:4433/?url=',
|
||||
'https://jsap.attakids.com/?url=',
|
||||
'https://jx.dj6u.com/?url=',
|
||||
]
|
||||
|
||||
// 添加视频解析前缀
|
||||
const converLink = (link: string): string => {
|
||||
// 视频统一使用第三方解析
|
||||
if (link.search("m3u8") != -1) {
|
||||
return `${resolver[0] + link}`
|
||||
}
|
||||
// return `${resolver[1]+link}`
|
||||
return `${link}`
|
||||
// 点击播集数播放对应影片
|
||||
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} `
|
||||
}
|
||||
|
||||
// 点击播放对应影片
|
||||
const playChange = (info: { link: string, episode: string }) => {
|
||||
// 判断是否是m3u8播放器, 如果是则添加前缀
|
||||
data.current.link = converLink(info.link)
|
||||
data.current.episode = info.episode
|
||||
}
|
||||
// 点击播放源标签事件
|
||||
const changeSource = (tabName: any) => {
|
||||
data.currentTabName = tabName
|
||||
data.detail.playList.find((item, index) => {
|
||||
if (tabName.split("-")[1] - index == 0) {
|
||||
item.find(i => {
|
||||
if (i.episode == data.current.episode) {
|
||||
data.current.link = converLink(i.link)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 测试滑动音量调节
|
||||
const iframe = ref()
|
||||
// document.querySelector('#brightnessSlider').addEventListener('change', function() {
|
||||
// // 获取滑块的值
|
||||
// var brightness = this.value;
|
||||
//
|
||||
// // 设置亮度为滑块的值
|
||||
// iframe.style.filter = 'brightness(' + brightness + '%)';
|
||||
// })
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/*vue3-video-play 相关设置*/
|
||||
/*//播放器控件区域大小*/
|
||||
:deep(#refPlayerWrap) {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border-radius: 6px;
|
||||
position: absolute;
|
||||
}
|
||||
/*将鼠标右键触发元素的层级降低,回避触发右键视频菜单信息*/
|
||||
:deep(.d-player-contextmenu){
|
||||
z-index: -100!important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*当前播放的影片信息展示*/
|
||||
.current_play_info {
|
||||
width: 100%;
|
||||
@@ -184,9 +153,6 @@ const iframe = ref()
|
||||
.player_area {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
/*height: 1400px;*/
|
||||
/*background: red;*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -211,33 +177,30 @@ const iframe = ref()
|
||||
margin: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.play_content a {
|
||||
font-size: 12px;
|
||||
flex-basis: calc(10% - 24px);
|
||||
padding: 6px 10px;
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
margin: 8px 12px;
|
||||
background: #888888;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.player_p {
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
/*height: 700px;*/
|
||||
margin: 0;
|
||||
padding-bottom: 56.25% !important;
|
||||
/*padding-bottom: 42.25% !important;*/
|
||||
position: relative;
|
||||
background-image: url("/src/assets/image/play.png");
|
||||
background-size: cover;
|
||||
background: red;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border-radius: 6px;
|
||||
left: 0;
|
||||
width: 100%; /* 设置iframe元素的宽度为父容器的100% */
|
||||
height: 100%; /* 设置iframe元素的高度为0,以便自适应高度 */
|
||||
/*padding-bottom: 56.25%; !* 使用padding-bottom属性计算iframe元素的高度,这里假设视频的宽高比为16:9 *!*/
|
||||
/*border: none; !* 去除iframe元素的边框 *!*/
|
||||
/*transform: scale(1);*/
|
||||
position: absolute;
|
||||
|
||||
}
|
||||
|
||||
/*右侧播放源选择区域*/
|
||||
/*影片播放列表信息展示*/
|
||||
@@ -253,7 +216,7 @@ iframe {
|
||||
.play_content {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
padding: 10px 10px 10px 18px;
|
||||
padding: 10px 10px 10px 10px;
|
||||
|
||||
}
|
||||
|
||||
@@ -264,15 +227,7 @@ iframe {
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.play_content a {
|
||||
font-size: 12px;
|
||||
min-width: 65px;
|
||||
padding: 6px 15px;
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
margin: 8px 8px;
|
||||
background: #888888;
|
||||
}
|
||||
|
||||
|
||||
/*集数选中效果*/
|
||||
.play_active {
|
||||
@@ -342,6 +297,17 @@ iframe {
|
||||
border-radius: 6px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
|
||||
.play_content a {
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
margin: 6px 8px;
|
||||
background: #888888;
|
||||
flex-basis: calc(25% - 16px);
|
||||
font-size: 12px;
|
||||
padding: 6px 12px !important;
|
||||
}
|
||||
.tags span {
|
||||
padding: 6px 10px;
|
||||
background-color: #404042;
|
||||
@@ -350,6 +316,12 @@ iframe {
|
||||
margin: 0 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
:deep(.el-tabs__item){
|
||||
width: 70px;
|
||||
height: 35px;
|
||||
margin: 17px 5px 0 0!important;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
357
client/src/views/index/PlayV1.vue
Normal file
357
client/src/views/index/PlayV1.vue
Normal file
@@ -0,0 +1,357 @@
|
||||
<template>
|
||||
|
||||
<div class="player_area">
|
||||
<!-- 视频播放区域-->
|
||||
<div class="player_p">
|
||||
<iframe ref="iframe" class="player" :src="data.current.link"
|
||||
:name="data.detail.name"
|
||||
marginheight="0"
|
||||
marginwidth="0"
|
||||
framespacing="0"
|
||||
vspale="0"
|
||||
allow="fullscreen"
|
||||
frameborder="0" scolling="no"
|
||||
sandbox="allow-scripts allow-same-origin allow-downloads">
|
||||
</iframe>
|
||||
|
||||
</div>
|
||||
<div class="current_play_info">
|
||||
<div class="play_info_left">
|
||||
<h3 class="current_play_title">{{ `${data.detail.name} ${data.current.episode}` }}</h3>
|
||||
<div class="tags">
|
||||
<b>
|
||||
<el-icon>
|
||||
<Promotion/>
|
||||
</el-icon>
|
||||
{{ data.detail.descriptor.cName }}</b>
|
||||
<span>{{ data.detail.descriptor.classTag }}</span>
|
||||
<span>{{ data.detail.descriptor.year }}</span>
|
||||
<span>{{ data.detail.descriptor.area }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- 播放选集 -->
|
||||
<div class="play_list">
|
||||
<h2 class="hidden-md-and-down">播放列表:(右侧切换播放源)</h2>
|
||||
<el-tabs type="card" v-model="data.currentTabName" class="plya_tabs" @tab-change="changeSource">
|
||||
<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(item)"
|
||||
:class="data.current.link.search(item.link) !== -1?'play_active':''">{{ item.episode }}</a>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
<div class="correlation">
|
||||
<RelateList :relate-list="data.relate"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {onMounted, reactive, ref, withDirectives} from "vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {ApiGet} from "../../utils/request";
|
||||
import RelateList from "../../components/RelateList.vue";
|
||||
import {Promotion} from "@element-plus/icons-vue";
|
||||
|
||||
// 播放页所需数据
|
||||
const data = reactive({
|
||||
detail: {descriptor: {}, playList: [[{episode: '', link: ''}]]},
|
||||
current: {episode: '', link: ''},
|
||||
currentTabName: '',
|
||||
currentPlayFrom: 0,
|
||||
currentEpisode: 0,
|
||||
relate: [],
|
||||
|
||||
})
|
||||
|
||||
// 获取路由信息
|
||||
const router = useRouter()
|
||||
onMounted(() => {
|
||||
let query = router.currentRoute.value.query
|
||||
ApiGet(`/filmPlayInfo`, {id: query.id, playFrom: query.source, episode: query.episode}).then((resp: any) => {
|
||||
if (resp.status === 'ok') {
|
||||
data.detail = resp.data.detail
|
||||
resp.data.current.link = converLink(resp.data.current.link)
|
||||
data.current = resp.data.current
|
||||
data.currentPlayFrom = resp.data.currentPlayFrom
|
||||
data.currentEpisode = resp.data.currentEpisode
|
||||
data.relate = resp.data.relate
|
||||
// 设置当前选中的播放源
|
||||
data.currentTabName = `tab-${query.source}`
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// ===============================视频播放处理=======================================
|
||||
// 视频解析接口地址, 默认使用第一个
|
||||
const resolver = [
|
||||
// m3u8使用此解析
|
||||
'https://jx.jsonplayer.com/player/?url=',
|
||||
// 'https://jx.m3u8.tv/jiexi/?url=',
|
||||
|
||||
|
||||
// 'https://jx.jsonplayer.com/player/?url=',
|
||||
// 'https://vip.bljiex.com/?url=',
|
||||
// 'https://jx.bozrc.com:4433/player/?url=',
|
||||
// html视频使用此解析
|
||||
'http://www.82190555.com/index/qqvod.php?url=',
|
||||
// 'https://jx.bozrc.com:4433/player/?url=',
|
||||
// 'https://vip.bljiex.com/?url=',
|
||||
|
||||
// Google上随便找的
|
||||
'https://vip.bljiex.com/?url=',
|
||||
'https://jx.kingtail.xyz/?url=',
|
||||
'http://www.82190555.com/index/qqvod.php?url=',
|
||||
'https://www.nxflv.com/?url=',
|
||||
'http://www.wmxz.wang/video.php?url=',
|
||||
'https://www.feisuplayer.com/m3u8/?url=',
|
||||
// tampermonkey 脚本使用的解析
|
||||
'https://jx.bozrc.com:4433/player/?url=',
|
||||
'https://z1.m1907.top/?jx=',
|
||||
'https://jx.aidouer.net/?url=',
|
||||
'https://www.gai4.com/?url=',
|
||||
'https://okjx.cc/?url=',
|
||||
'https://jx.rdhk.net/?v=',
|
||||
'https://jx.blbo.cc:4433/?url=',
|
||||
'https://jsap.attakids.com/?url=',
|
||||
'https://jx.dj6u.com/?url=',
|
||||
]
|
||||
|
||||
// 添加视频解析前缀
|
||||
const converLink = (link: string): string => {
|
||||
// 视频统一使用第三方解析
|
||||
if (link.search("m3u8") != -1) {
|
||||
return `${resolver[0] + link}`
|
||||
}
|
||||
// return `${resolver[1]+link}`
|
||||
return `${link}`
|
||||
}
|
||||
|
||||
// 点击播放对应影片
|
||||
const playChange = (info: { link: string, episode: string }) => {
|
||||
// 判断是否是m3u8播放器, 如果是则添加前缀
|
||||
data.current.link = converLink(info.link)
|
||||
data.current.episode = info.episode
|
||||
}
|
||||
// 点击播放源标签事件
|
||||
const changeSource = (tabName: any) => {
|
||||
data.currentTabName = tabName
|
||||
data.detail.playList.find((item, index) => {
|
||||
if (tabName.split("-")[1] - index == 0) {
|
||||
item.find(i => {
|
||||
if (i.episode == data.current.episode) {
|
||||
data.current.link = converLink(i.link)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 测试滑动音量调节
|
||||
const iframe = ref()
|
||||
// document.querySelector('#brightnessSlider').addEventListener('change', function() {
|
||||
// // 获取滑块的值
|
||||
// var brightness = this.value;
|
||||
//
|
||||
// // 设置亮度为滑块的值
|
||||
// iframe.style.filter = 'brightness(' + brightness + '%)';
|
||||
// })
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/*当前播放的影片信息展示*/
|
||||
.current_play_info {
|
||||
width: 100%;
|
||||
padding: 15px 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.current_play_title {
|
||||
font-weight: 500;
|
||||
color: rgb(201, 196, 196);
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
|
||||
/* 播放区域*/
|
||||
.player_area {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
/*height: 1400px;*/
|
||||
/*background: red;*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 650px) {
|
||||
.player_area {
|
||||
padding: 10px 6%;
|
||||
}
|
||||
|
||||
.tags b {
|
||||
padding: 5px 10px;
|
||||
background-color: rgba(155, 73, 231, 0.72);
|
||||
font-size: 13px;
|
||||
border-radius: 6px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.tags span {
|
||||
padding: 6px 12px;
|
||||
background-color: #404042;
|
||||
color: #b5b2b2;
|
||||
border-radius: 5px;
|
||||
margin: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
.player_p {
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
margin: 0;
|
||||
padding-bottom: 56.25% !important;
|
||||
/*padding-bottom: 42.25% !important;*/
|
||||
position: relative;
|
||||
background-image: url("/src/assets/image/play.png");
|
||||
background-size: cover;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border-radius: 6px;
|
||||
left: 0;
|
||||
width: 100%; /* 设置iframe元素的宽度为父容器的100% */
|
||||
height: 100%; /* 设置iframe元素的高度为0,以便自适应高度 */
|
||||
/*padding-bottom: 56.25%; !* 使用padding-bottom属性计算iframe元素的高度,这里假设视频的宽高比为16:9 *!*/
|
||||
/*border: none; !* 去除iframe元素的边框 *!*/
|
||||
/*transform: scale(1);*/
|
||||
position: absolute;
|
||||
|
||||
}
|
||||
|
||||
/*右侧播放源选择区域*/
|
||||
/*影片播放列表信息展示*/
|
||||
/*影片播放列表信息展示*/
|
||||
.play_list {
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
background: #2e2e2e;
|
||||
margin-top: 50px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.play_content {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
padding: 10px 10px 10px 18px;
|
||||
|
||||
}
|
||||
|
||||
.play_list > h2 {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: -10px;
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.play_content a {
|
||||
font-size: 12px;
|
||||
min-width: 65px;
|
||||
padding: 6px 15px;
|
||||
color: #ffffff;
|
||||
border-radius: 6px;
|
||||
margin: 8px 8px;
|
||||
background: #888888;
|
||||
}
|
||||
|
||||
/*集数选中效果*/
|
||||
.play_active {
|
||||
color: orange !important;
|
||||
background: #424242 !important;
|
||||
}
|
||||
|
||||
.play_content .play_tabs {
|
||||
background: #2e2e2e;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-scroll) {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__header) {
|
||||
/*border-bottom: 1px solid #888888!important;*/
|
||||
margin-bottom: 0;
|
||||
border-bottom: none !important;
|
||||
background: rgb(34, 34, 34);
|
||||
height: 50px !important;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav) {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item.is-active) {
|
||||
color: #ee9600;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item:hover) {
|
||||
color: orange;
|
||||
background: #484646;
|
||||
}
|
||||
|
||||
:deep(.el-tabs__item) {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
margin-left: 2px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
border: none !important;
|
||||
color: #ffffff;
|
||||
background: #2e2e2e;
|
||||
}
|
||||
|
||||
/*推荐列表区域*/
|
||||
.correlation {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<!--移动端-->
|
||||
<style scoped>
|
||||
|
||||
/*适应小尺寸*/
|
||||
@media (max-width: 650px) {
|
||||
.player_area {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.tags b {
|
||||
padding: 5px 10px;
|
||||
background-color: rgba(155, 73, 231, 0.72);
|
||||
font-size: 13px;
|
||||
border-radius: 6px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
.tags span {
|
||||
padding: 6px 10px;
|
||||
background-color: #404042;
|
||||
color: #b5b2b2;
|
||||
border-radius: 5px;
|
||||
margin: 0 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="search_group">
|
||||
<input v-model="data.search" placeholder="搜索 动漫,剧集,电影 " class="search"/>
|
||||
<input v-model="data.search" @keydown="e=>{e.keyCode==13 && searchMovie()}" placeholder="搜索 动漫,剧集,电影 " class="search"/>
|
||||
<el-button @click="searchMovie" :icon="Search" style="" />
|
||||
</div>
|
||||
<div v-if="data.list.length > 0 " class="search_res">
|
||||
@@ -116,14 +116,13 @@ const changeCurrent = (currentVal: number) => {
|
||||
}
|
||||
.film_item {
|
||||
flex-basis: calc(100% - 20px);
|
||||
margin: 0 10px;
|
||||
margin: 0 10px 25px 10px;
|
||||
display: flex;
|
||||
background: #2e2e2e;
|
||||
padding: 10px;
|
||||
min-height: 180px;
|
||||
max-height: 200px;
|
||||
border-radius: 16px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.film_item a {
|
||||
flex: 2;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user