feat: support play
This commit is contained in:
Binary file not shown.
16
frontend/package-lock.json
generated
16
frontend/package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"hls.js": "^0.8.5",
|
||||
"pinia": "^2.2.6",
|
||||
"vant": "^4.9.9",
|
||||
"vue": "^3.5.12",
|
||||
@@ -1371,6 +1372,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/hls.js": {
|
||||
"version": "0.8.5",
|
||||
"resolved": "https://npm.hub.ipao.vip/repository/npm/hls.js/-/hls.js-0.8.5.tgz",
|
||||
"integrity": "sha512-hJBxUAsJInjXNqDPPA6646h/IulN2OUAK9OT6/0gO1oygQ4ZF3pB3j/Uyk2UWO0cDKyAs/SDTclVWMGurt4glw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"url-toolkit": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hookable": {
|
||||
"version": "5.5.3",
|
||||
"dev": true,
|
||||
@@ -2485,6 +2495,12 @@
|
||||
"browserslist": ">= 4.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url-toolkit": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://npm.hub.ipao.vip/repository/npm/url-toolkit/-/url-toolkit-2.2.5.tgz",
|
||||
"integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/vant": {
|
||||
"version": "4.9.9",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"hls.js": "^0.8.5",
|
||||
"pinia": "^2.2.6",
|
||||
"vant": "^4.9.9",
|
||||
"vue": "^3.5.12",
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<template>
|
||||
<RouterView />
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive>
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</template>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import NotFound from '@/views/NotFound.vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '../views/tabs/HomeView.vue'
|
||||
import TabView from '../views/TabView.vue'
|
||||
@@ -5,13 +6,14 @@ import TabView from '../views/TabView.vue'
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
|
||||
{
|
||||
path: '/tab',
|
||||
path: '/t/:tenant',
|
||||
name: 'tab',
|
||||
component: TabView,
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
path: '',
|
||||
name: 'tab.home',
|
||||
component: HomeView,
|
||||
},
|
||||
@@ -21,8 +23,8 @@ const router = createRouter({
|
||||
component: () => import('../views/tabs/BoughtView.vue'),
|
||||
},
|
||||
{
|
||||
path: 'me',
|
||||
name: 'tab.me',
|
||||
path: 'user',
|
||||
name: 'tab.user',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
@@ -31,7 +33,7 @@ const router = createRouter({
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/play/{:id}',
|
||||
path: '/t/:tenant/play/:hash',
|
||||
name: 'play',
|
||||
component: () => import('../views/PlayView.vue'),
|
||||
},
|
||||
@@ -40,12 +42,6 @@ const router = createRouter({
|
||||
|
||||
router.beforeEach((to, from) => {
|
||||
console.log("from", from, "goto: ", to)
|
||||
|
||||
if (to.path === "/" && from.path === "/") {
|
||||
console.log("redirecting to tab.home")
|
||||
return { name: "tab.home" }
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import axios from 'axios'; // 引入axios
|
||||
|
||||
console.log("__GA: ", __GA)
|
||||
const service = axios.create({
|
||||
baseURL: "/v1",
|
||||
timeout: 30,
|
||||
timeout: 30 * 1000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + __GA,
|
||||
@@ -16,15 +15,18 @@ service.interceptors.request.use(
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
)
|
||||
|
||||
// http response 拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
console.log(response)
|
||||
return response
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
)
|
||||
export default service
|
||||
3
frontend/src/views/NotFound.vue
Normal file
3
frontend/src/views/NotFound.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<h1>找不到页面</h1>
|
||||
</template>
|
||||
@@ -1,3 +1,143 @@
|
||||
<template>
|
||||
<h1>Player</h1>
|
||||
<van-nav-bar :title="item.title" left-text="返回" left-arrow @click-left="onClickLeft" />
|
||||
<div style="background-color: black;">
|
||||
<video id="video" :poster="item.poster"></video>
|
||||
</div>
|
||||
|
||||
<van-notice-bar v-if="false === item.bought" left-icon="volume-o" text="未购买的视频、音频默认播放时长为1分钟左右。" />
|
||||
|
||||
|
||||
<div id="container">
|
||||
<van-space direction="vertical" fill size="2rem">
|
||||
|
||||
<van-row gutter="20" v-show="playing">
|
||||
<van-col span="24">
|
||||
<van-progress :percent="(currentTime / duration) * 100" />
|
||||
</van-col>
|
||||
</van-row>
|
||||
|
||||
<van-row gutter="20">
|
||||
<van-col span="12">
|
||||
<van-button type="primary" plain round @click="play(item.hash, 'video')" size="large" block>看视频</van-button>
|
||||
</van-col>
|
||||
<van-col span="12">
|
||||
<van-button type="warning" plain round="" @click="play(item.hash, 'audio')" size="large"
|
||||
block>听音频</van-button>
|
||||
</van-col>
|
||||
</van-row>
|
||||
|
||||
<van-row gutter="20" v-show="playing">
|
||||
<van-col span="24">
|
||||
<van-button round type="danger" @click="stop()" size="large" block>结束播放</van-button>
|
||||
</van-col>
|
||||
</van-row>
|
||||
</van-space>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import request from "@/utils/request";
|
||||
import Hls from "hls.js";
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const item = ref({
|
||||
title: "加载中...",
|
||||
})
|
||||
|
||||
const currentTime = ref(0);
|
||||
const duration = ref(0);
|
||||
const playing = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
loadMedia(route.params.hash);
|
||||
const player = document.getElementById('video');
|
||||
player.addEventListener('timeupdate', updateTime);
|
||||
player.addEventListener('loadedmetadata', () => {
|
||||
duration.value = player.duration;
|
||||
});
|
||||
player.addEventListener('ended', function () {
|
||||
console.log("Video ended");
|
||||
playing.value = false;
|
||||
});
|
||||
player.addEventListener('pause', () => {
|
||||
playing.value = false;
|
||||
});
|
||||
})
|
||||
|
||||
const onClickLeft = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
|
||||
const loadMedia = (hash) => {
|
||||
console.log("loadMedia: ", hash);
|
||||
setTimeout(() => {
|
||||
request
|
||||
.get(`/medias/${hash}`)
|
||||
.then((res) => {
|
||||
console.log(res)
|
||||
item.value = res.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("ERROR", err);
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const play = (hash, type) => {
|
||||
playing.value = true;
|
||||
|
||||
const player = document.getElementById('video');
|
||||
const source = `/v1/medias/${hash}/${type}`
|
||||
if (Hls.isSupported()) {
|
||||
var hls = new Hls({
|
||||
xhrSetup: function (xhr, url) {
|
||||
xhr.setRequestHeader('Authorization', 'Bearer ' + __GA);
|
||||
}
|
||||
});
|
||||
hls.loadSource(source);
|
||||
hls.attachMedia(player);
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||
player.play();
|
||||
});
|
||||
} else if (player.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
player.src = source;
|
||||
player.addEventListener('loadedmetadata', function () {
|
||||
player.play();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const updateTime = () => {
|
||||
const player = document.getElementById('video');
|
||||
currentTime.value = player.currentTime;
|
||||
};
|
||||
|
||||
const stop = () => {
|
||||
const player = document.getElementById('video');
|
||||
player.pause();
|
||||
player.currentTime = 0;
|
||||
currentTime.value = 0;
|
||||
}
|
||||
|
||||
const formatTime = (time) => {
|
||||
const minutes = Math.floor(time / 60);
|
||||
const seconds = Math.floor(time % 60);
|
||||
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#container {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#video {
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
}
|
||||
</style>
|
||||
@@ -2,16 +2,14 @@
|
||||
<RouterView />
|
||||
|
||||
<van-tabbar route v-model="active">
|
||||
<van-tabbar-item replace name="home" icon="home-o" to="/tab/home"
|
||||
>主页
|
||||
<van-tabbar-item replace name="home" icon="home-o" to="/tab/home">主页
|
||||
</van-tabbar-item>
|
||||
<van-tabbar-item replace name="bought" icon="like-o" to="/tab/bought"
|
||||
>已购</van-tabbar-item
|
||||
>
|
||||
<van-tabbar-item replace name="bought" icon="like-o" to="/tab/bought">已购</van-tabbar-item>
|
||||
<van-tabbar-item replace name="me" icon="contact-o" to="/tab/me">我</van-tabbar-item>
|
||||
</van-tabbar>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { RouterView } from "vue-router";
|
||||
const active = ref("home");
|
||||
</script>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
<van-back-top bottom="80" />
|
||||
|
||||
<van-button :to="{ name: 'play', params: { tenant: 'ypl', hash: '123' } }" type="primary">主要按钮</van-button>
|
||||
|
||||
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" offset="100" @load="loadData">
|
||||
<van-card v-for="item in items" :key="item" :desc="item.title" :thumb="item.poster" @click="play(item)">
|
||||
<template #title>
|
||||
@@ -51,10 +53,11 @@ const offset = ref("");
|
||||
const play = (item) => {
|
||||
// vue router goto play view
|
||||
console.log("play -", item);
|
||||
router.push({ name: "play", params: { id: item } });
|
||||
router.push({ name: "play", params: { hash: item.hash } });
|
||||
};
|
||||
|
||||
const loadData = () => {
|
||||
return
|
||||
// request /v1/medias
|
||||
const data = {
|
||||
offset: offset.value,
|
||||
|
||||
Reference in New Issue
Block a user