feat: support play

This commit is contained in:
Rogee
2024-12-11 20:07:17 +08:00
parent 59d2beddbf
commit 7b9f6d444f
10 changed files with 184 additions and 21 deletions

View File

@@ -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",

View File

@@ -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",

View File

@@ -1,3 +1,7 @@
<template>
<RouterView />
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</template>

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,3 @@
<template>
<h1>找不到页面</h1>
</template>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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,