七十二家房客-观看平台v1.5
- 更改播放器 - 优化自动播放
This commit is contained in:
parent
139e1a2135
commit
c7f6d6b2b1
450
README.md
450
README.md
@ -1,265 +1,321 @@
|
||||
# 72QishierPlayer
|
||||
# 72QishierPlayer 技术栈说明
|
||||
|
||||
一个基于 **Vue3 + Vite + Node.js + Playwright + HLS.js** 的《七十二家房客》在线播放项目。
|
||||
一个基于 **Vue3 + Vite + Node.js + Playwright + HLS.js + Artplayer**
|
||||
的《七十二家房客》在线播放项目。
|
||||
|
||||
本项目通过 **浏览器自动采集官网数据 → 本地缓存 JSON → Node API 提供 → Vue 前端播放** 的方式,解决官网接口 **签名、401、分页限制** 等问题,实现稳定播放。
|
||||
本项目通过 **浏览器自动采集官网数据 → 本地缓存 JSON → Node API 提供 →
|
||||
Vue 前端播放** 的方式,解决官网接口 **签名、401、分页限制**
|
||||
等问题,实现稳定播放。
|
||||
|
||||
---
|
||||
------------------------------------------------------------------------
|
||||
# 运行与安装指南
|
||||
|
||||
# 项目特点
|
||||
本文档说明 **72QishierPlayer** 项目的安装与运行步骤。\
|
||||
项目由 **Node.js 后端 + Vue3 前端** 两部分组成,需要分别启动。
|
||||
|
||||
- 自动采集《七十二家房客》节目列表
|
||||
- 自动滚动加载更多节目
|
||||
- 自动去重并缓存到 JSON
|
||||
- Node API 提供数据
|
||||
- Vue3 播放器展示
|
||||
- HLS.js 播放 m3u8 视频
|
||||
- Cookie 记录上次观看进度
|
||||
- 前端分页加载,避免一次加载过多图片
|
||||
------------------------------------------------------------------------
|
||||
|
||||
---
|
||||
# 运行&安装
|
||||
## 一、后端
|
||||
安装后端依赖
|
||||
```shell
|
||||
npm i
|
||||
```
|
||||
# 一、后端服务(Node.js)
|
||||
|
||||
开启后端服务
|
||||
```shell
|
||||
node server.js
|
||||
```
|
||||
后端主要负责:
|
||||
|
||||
如需更新数据:
|
||||
```shell
|
||||
node capture.js
|
||||
```
|
||||
- 提供节目 API
|
||||
- 读取本地 JSON 数据
|
||||
- 提供给前端播放列表
|
||||
|
||||
## 二、前端
|
||||
## 1 安装前端依赖
|
||||
```
|
||||
npm i
|
||||
```
|
||||
|
||||
运行前端服务:
|
||||
```shell
|
||||
npm run dev
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 2 安装后端依赖
|
||||
## 1. 安装依赖
|
||||
|
||||
进入后端目录:
|
||||
|
||||
```
|
||||
``` bash
|
||||
cd backServer
|
||||
```
|
||||
|
||||
安装依赖:
|
||||
|
||||
```
|
||||
``` bash
|
||||
npm install
|
||||
```
|
||||
|
||||
安装 Playwright 浏览器:
|
||||
------------------------------------------------------------------------
|
||||
|
||||
```
|
||||
npx playwright install chromium
|
||||
## 2. 启动后端服务
|
||||
|
||||
``` bash
|
||||
node server.js
|
||||
```
|
||||
|
||||
---
|
||||
默认接口地址:
|
||||
|
||||
# 运行项目
|
||||
http://localhost:3000
|
||||
|
||||
## 1 采集节目数据
|
||||
例如:
|
||||
|
||||
```
|
||||
npm run capture
|
||||
http://localhost:3000/api/qishier/list
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## 3. 更新节目数据(可选)
|
||||
|
||||
如果需要重新采集节目数据:
|
||||
|
||||
``` bash
|
||||
node capture.js
|
||||
```
|
||||
|
||||
程序会自动:
|
||||
该脚本会:
|
||||
|
||||
1. 启动浏览器
|
||||
2. 打开页面
|
||||
1. 启动浏览器自动采集
|
||||
2. 打开节目页面
|
||||
3. 自动加载更多节目
|
||||
4. 捕获接口数据
|
||||
5. 更新本地缓存
|
||||
|
||||
```
|
||||
https://www1.gdtv.cn/tvColumn/768
|
||||
数据保存位置:
|
||||
|
||||
backServer/data/qishier-cache.json
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 二、前端服务(Vue3)
|
||||
|
||||
前端负责:
|
||||
|
||||
- 视频播放器
|
||||
- 节目列表展示
|
||||
- 自动下一集
|
||||
- 播放进度记录
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## 1. 安装前端依赖
|
||||
|
||||
进入前端目录:
|
||||
|
||||
``` bash
|
||||
cd 72QishierPlayer
|
||||
```
|
||||
|
||||
3. 自动滚动页面
|
||||
4. 自动点击 **加载更多**
|
||||
5. 捕获接口数据
|
||||
6. 写入缓存
|
||||
安装依赖:
|
||||
|
||||
缓存文件:
|
||||
|
||||
```
|
||||
backServer/data/qishier-cache.json
|
||||
``` bash
|
||||
npm install
|
||||
```
|
||||
|
||||
---
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## 2 启动 Node API
|
||||
## 2. 启动前端开发服务器
|
||||
|
||||
在 `backServer` 目录运行:
|
||||
|
||||
```
|
||||
npm run server
|
||||
```
|
||||
|
||||
API 地址:
|
||||
|
||||
```
|
||||
http://localhost:3000/api/qishier/all
|
||||
```
|
||||
|
||||
返回示例:
|
||||
|
||||
```
|
||||
{
|
||||
"total": 1141,
|
||||
"list": []
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3 启动 Vue 前端
|
||||
|
||||
回到项目根目录:地址:http://localhost:5173
|
||||
|
||||
```
|
||||
``` bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
默认访问地址:
|
||||
|
||||
---
|
||||
http://localhost:5173
|
||||
|
||||
# 项目架构
|
||||
------------------------------------------------------------------------
|
||||
|
||||
```
|
||||
官网接口
|
||||
gdtv-api.gdtv.cn
|
||||
│
|
||||
▼
|
||||
Playwright 浏览器采集
|
||||
│
|
||||
▼
|
||||
本地 JSON 缓存
|
||||
backServer/data/qishier-cache.json
|
||||
│
|
||||
▼
|
||||
Node API
|
||||
http://localhost:3000/api/qishier/all
|
||||
│
|
||||
▼
|
||||
Vue 播放器
|
||||
# 三、开发模式运行流程
|
||||
|
||||
建议的启动顺序:
|
||||
|
||||
``` text
|
||||
1. 启动 Node 后端
|
||||
node server.js
|
||||
|
||||
2. 启动 Vue 前端
|
||||
npm run dev
|
||||
|
||||
3. 浏览器访问
|
||||
http://localhost:5173
|
||||
```
|
||||
|
||||
---
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 项目目录
|
||||
# 四、生产环境部署
|
||||
|
||||
构建前端:
|
||||
|
||||
``` bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
构建完成后生成:
|
||||
|
||||
dist/
|
||||
|
||||
将 `dist` 部署到 Nginx 或静态服务器即可。
|
||||
|
||||
后端服务建议使用 **PM2** 运行:
|
||||
|
||||
``` bash
|
||||
pm2 start server.js --name qishier-api
|
||||
pm2 save
|
||||
```
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 五、常见问题
|
||||
|
||||
## 1. 播放器无法播放
|
||||
|
||||
确认:
|
||||
|
||||
- 后端服务已启动
|
||||
- API 地址正常
|
||||
- m3u8 视频链接有效
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## 2. 没有节目数据
|
||||
|
||||
执行:
|
||||
|
||||
``` bash
|
||||
node capture.js
|
||||
```
|
||||
|
||||
重新采集节目列表。
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 六、默认端口
|
||||
|
||||
服务 端口
|
||||
---------- ------
|
||||
Vue 前端 5173
|
||||
Node API 3000
|
||||
|
||||
|
||||
|
||||
# 技术栈(Tech Stack)
|
||||
|
||||
## 前端
|
||||
|
||||
技术 说明
|
||||
------------- -----------------------
|
||||
Vue3 前端框架
|
||||
Vite 前端构建工具
|
||||
TypeScript 类型安全开发
|
||||
Axios HTTP 请求库
|
||||
Artplayer 视频播放器 UI
|
||||
hls.js m3u8 / HLS 视频流播放
|
||||
HTML5 Video 浏览器视频播放能力
|
||||
CSS3 页面样式
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## 后端
|
||||
|
||||
技术 说明
|
||||
------------ ------------------
|
||||
Node.js 后端运行环境
|
||||
Express API 服务
|
||||
Playwright 浏览器自动化采集
|
||||
JSON 数据缓存存储
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## 数据采集
|
||||
|
||||
技术 说明
|
||||
---------------- ------------------
|
||||
Playwright 自动打开官网页面
|
||||
浏览器接口拦截 捕获节目 API
|
||||
自动滚动 加载更多节目
|
||||
JSON缓存 本地节目数据存储
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## 视频播放技术
|
||||
|
||||
技术 说明
|
||||
--------------------------- --------------------
|
||||
HLS (HTTP Live Streaming) 视频流协议
|
||||
hls.js 浏览器 HLS 解码
|
||||
Artplayer 视频播放器 UI 控件
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 项目架构
|
||||
|
||||
``` text
|
||||
官网接口
|
||||
gdtv-api.gdtv.cn
|
||||
│
|
||||
▼
|
||||
Playwright 浏览器采集
|
||||
│
|
||||
▼
|
||||
本地 JSON 缓存
|
||||
backServer/data/qishier-cache.json
|
||||
│
|
||||
▼
|
||||
Node API
|
||||
/api/qishier/*
|
||||
│
|
||||
▼
|
||||
Vue3 前端
|
||||
Artplayer + HLS
|
||||
```
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 核心功能
|
||||
|
||||
功能 技术实现
|
||||
----------------- --------------------
|
||||
自动采集节目 Playwright
|
||||
数据缓存 JSON
|
||||
API 服务 Express
|
||||
视频播放 Artplayer + hls.js
|
||||
自动下一集 Vue 状态管理
|
||||
顺序 / 倒序播放 列表排序
|
||||
播放进度记录 Cookie
|
||||
懒加载节目列表 前端分页
|
||||
组件化架构 Vue Components
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 运行环境
|
||||
|
||||
环境 版本
|
||||
---------- -------------------------
|
||||
Node.js ≥ 18
|
||||
npm ≥ 9
|
||||
浏览器 Chrome / Edge / Safari
|
||||
操作系统 macOS / Linux / Windows
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
# 项目目录结构
|
||||
|
||||
``` text
|
||||
72QishierPlayer
|
||||
│
|
||||
├─ src
|
||||
│ ├─ api
|
||||
│ │ └─ qishier.ts
|
||||
│ │
|
||||
│ ├─ components
|
||||
│ │ └─ qishier
|
||||
│ │ ├─ QishierVideoPlayer.vue
|
||||
│ │ └─ QishierEpisodeList.vue
|
||||
│ │
|
||||
│ ├─ views
|
||||
│ │ └─ QishierPlayer.vue
|
||||
│ │
|
||||
│ ├─ App.vue
|
||||
│ ├─ main.ts
|
||||
│ └─ assets
|
||||
│ └─ utils
|
||||
│ └─ playHistory.ts
|
||||
│
|
||||
├─ backServer
|
||||
│ │
|
||||
│ ├─ data
|
||||
│ │ └─ qishier-cache.json
|
||||
│ │
|
||||
│ ├─ capture.js
|
||||
│ ├─ server.js
|
||||
│ └─ package.json
|
||||
│ └─ server.js
|
||||
│
|
||||
├─ vite.config.ts
|
||||
└─ package.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
# 播放器功能
|
||||
|
||||
播放器支持:
|
||||
|
||||
- m3u8 视频播放
|
||||
- HLS.js 播放器
|
||||
- 节目列表分页加载
|
||||
- 懒加载封面图
|
||||
- 自动播放
|
||||
- 自动恢复观看进度
|
||||
|
||||
观看记录存储在 Cookie:
|
||||
|
||||
```
|
||||
qishier_last_episode
|
||||
```
|
||||
|
||||
刷新页面会自动恢复上次观看。
|
||||
|
||||
---
|
||||
|
||||
# 数据缓存机制
|
||||
|
||||
缓存文件:
|
||||
|
||||
```
|
||||
backServer/data/qishier-cache.json
|
||||
```
|
||||
|
||||
缓存策略:
|
||||
|
||||
- 新数据自动追加
|
||||
- 根据 `id` 自动去重
|
||||
- 避免重复节目
|
||||
|
||||
---
|
||||
|
||||
# 技术栈
|
||||
|
||||
前端:
|
||||
|
||||
- Vue 3
|
||||
- Vite
|
||||
- TypeScript
|
||||
- Axios
|
||||
- HLS.js
|
||||
|
||||
后端:
|
||||
|
||||
- Node.js
|
||||
- Express
|
||||
- Playwright
|
||||
|
||||
数据:
|
||||
|
||||
- JSON 本地缓存
|
||||
|
||||
---
|
||||
|
||||
# 免责声明
|
||||
|
||||
本项目仅用于:
|
||||
|
||||
- 技术学习
|
||||
- 数据采集研究
|
||||
- 视频播放技术演示
|
||||
|
||||
请勿用于商业用途。
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="list-panel">
|
||||
<div ref="listPanelRef" class="list-panel">
|
||||
<div
|
||||
v-for="item in episodes"
|
||||
:key="item.id"
|
||||
:data-episode-id="item.id"
|
||||
class="episode-item"
|
||||
:class="{ active: currentEpisodeId === item.id }"
|
||||
@click="$emit('select', item)"
|
||||
@ -23,9 +24,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, ref, watch } from 'vue'
|
||||
import type { EpisodeData } from '@/api/qishier'
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
episodes: EpisodeData[]
|
||||
currentEpisodeId: string
|
||||
hasMore: boolean
|
||||
@ -37,6 +39,8 @@ defineEmits<{
|
||||
loadMore: []
|
||||
}>()
|
||||
|
||||
const listPanelRef = ref<HTMLElement | null>(null)
|
||||
|
||||
function formatDate(timestamp: number): string {
|
||||
if (!timestamp) return '--'
|
||||
const d = new Date(timestamp)
|
||||
@ -45,6 +49,47 @@ function formatDate(timestamp: number): string {
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${y}-${m}-${day}`
|
||||
}
|
||||
|
||||
async function scrollToActiveEpisode() {
|
||||
await nextTick()
|
||||
|
||||
const panel = listPanelRef.value
|
||||
if (!panel || !props.currentEpisodeId) return
|
||||
|
||||
const activeEl = panel.querySelector(
|
||||
`[data-episode-id="${props.currentEpisodeId}"]`
|
||||
) as HTMLElement | null
|
||||
|
||||
if (!activeEl) return
|
||||
|
||||
const panelRect = panel.getBoundingClientRect()
|
||||
const itemRect = activeEl.getBoundingClientRect()
|
||||
|
||||
const isAbove = itemRect.top < panelRect.top
|
||||
const isBelow = itemRect.bottom > panelRect.bottom
|
||||
|
||||
if (isAbove || isBelow) {
|
||||
activeEl.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.currentEpisodeId,
|
||||
async () => {
|
||||
await scrollToActiveEpisode()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.episodes.length,
|
||||
async () => {
|
||||
await scrollToActiveEpisode()
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -54,6 +99,7 @@ function formatDate(timestamp: number): string {
|
||||
padding: 12px;
|
||||
background: #1b1b1b;
|
||||
border-radius: 12px;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
.episode-item {
|
||||
@ -64,6 +110,7 @@ function formatDate(timestamp: number): string {
|
||||
cursor: pointer;
|
||||
margin-bottom: 10px;
|
||||
transition: 0.2s;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.episode-item:hover {
|
||||
@ -72,6 +119,8 @@ function formatDate(timestamp: number): string {
|
||||
|
||||
.episode-item.active {
|
||||
background: rgba(255, 193, 7, 0.16);
|
||||
border-color: rgba(255, 193, 7, 0.45);
|
||||
box-shadow: 0 0 0 1px rgba(255, 193, 7, 0.12) inset;
|
||||
}
|
||||
|
||||
.episode-item img {
|
||||
@ -95,6 +144,10 @@ function formatDate(timestamp: number): string {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.episode-item.active .title {
|
||||
color: #ffd666;
|
||||
}
|
||||
|
||||
.meta {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user