samlax12 commited on
Commit
dbbbf7e
·
verified ·
1 Parent(s): b8cca13

Upload 33 files

Browse files
Files changed (6) hide show
  1. .dockerignore +2 -0
  2. Dockerfile +16 -18
  3. nginx.conf +2 -2
  4. package.json +9 -5
  5. readme.md +174 -0
  6. server.js +128 -0
.dockerignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .vscode/
2
+ readme.md
Dockerfile CHANGED
@@ -1,25 +1,23 @@
1
- FROM fabiocicerchia/nginx-lua:1.27.5-alpine3.21.3
2
- LABEL maintainer="LibreTV Team"
3
- LABEL description="LibreTV - 免费在线视频搜索与观看平台"
4
 
5
- # 复制应用文件
6
- COPY . /usr/share/nginx/html
7
 
8
- # 复制Nginx配置文件
9
- COPY nginx.conf /etc/nginx/conf.d/default.conf
10
 
11
- # 添加执行权限并设置为入口点脚本
12
- COPY docker-entrypoint.sh /
13
- RUN chmod +x /docker-entrypoint.sh
14
 
15
- # 暴露端口
16
- EXPOSE 7860
17
 
18
- # 设置入口点
19
- ENTRYPOINT ["/docker-entrypoint.sh"]
20
 
21
- # 启动nginx
22
- CMD ["nginx", "-g", "daemon off;"]
 
23
 
24
- # 健康检查
25
- HEALTHCHECK --interval=30s --timeout=3s CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1
 
1
+ FROM node:18-alpine
 
 
2
 
3
+ # 创建工作目录
4
+ WORKDIR /app
5
 
6
+ # 复制 package.json 和 package-lock.json
7
+ COPY package*.json ./
8
 
9
+ # 安装依赖
10
+ RUN npm install --production
 
11
 
12
+ # 复制所有项目文件
13
+ COPY . .
14
 
15
+ # 暴露端口
16
+ EXPOSE 8080
17
 
18
+ # 设置环境变量
19
+ ENV PORT=8080
20
+ ENV PASSWORD=111111
21
 
22
+ # 启动应用
23
+ CMD ["npm", "start"]
nginx.conf CHANGED
@@ -1,5 +1,5 @@
1
  server {
2
- listen 7860;
3
  server_name localhost;
4
 
5
  #access_log /var/log/nginx/host.access.log main;
@@ -61,7 +61,7 @@ server {
61
  root /usr/share/nginx/html;
62
  }
63
 
64
- # proxy the PHP scripts to Apache listening on 127.0.0.1:7860
65
  #
66
  #location ~ \.php$ {
67
  # proxy_pass http://127.0.0.1;
 
1
  server {
2
+ listen 80;
3
  server_name localhost;
4
 
5
  #access_log /var/log/nginx/host.access.log main;
 
61
  root /usr/share/nginx/html;
62
  }
63
 
64
+ # proxy the PHP scripts to Apache listening on 127.0.0.1:80
65
  #
66
  #location ~ \.php$ {
67
  # proxy_pass http://127.0.0.1;
package.json CHANGED
@@ -2,14 +2,18 @@
2
  "name": "libretv",
3
  "version": "1.1.0",
4
  "description": "免费在线视频搜索与观看平台",
5
- "private": true,
6
- "type": "module",
7
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
 
9
  },
10
  "dependencies": {
11
- "node-fetch": "^3.3.2"
 
12
  },
13
- "author": "bestZwei",
 
 
 
14
  "license": "MIT"
15
  }
 
2
  "name": "libretv",
3
  "version": "1.1.0",
4
  "description": "免费在线视频搜索与观看平台",
5
+ "main": "server.js",
 
6
  "scripts": {
7
+ "start": "node server.js",
8
+ "dev": "nodemon server.js"
9
  },
10
  "dependencies": {
11
+ "express": "^4.18.2",
12
+ "http-proxy-middleware": "^2.0.6"
13
  },
14
+ "devDependencies": {
15
+ "nodemon": "^3.0.3"
16
+ },
17
+ "author": "LibreTV Team",
18
  "license": "MIT"
19
  }
readme.md ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # LibreTV - 免费在线视频搜索与观看平台
2
+
3
+ <div align="center">
4
+ <img src="https://images.icon-icons.com/38/PNG/512/retrotv_5520.png" alt="LibreTV Logo" width="120">
5
+ <br>
6
+ <p><strong>自由观影,畅享精彩</strong></p>
7
+ </div>
8
+
9
+ ## 📺 项目简介
10
+
11
+ LibreTV 是一个轻量级、免费的在线视频搜索与观看平台,提供来自多个视频源的内容搜索与播放服务。无需注册,即开即用,支持多种设备访问。项目结合了前端技术和后端代理功能,可部署在支持服务端功能的各类网站托管服务上。
12
+
13
+ 本项目基于 [bestK/tv](https://github.com/bestK/tv) 进行重构与增强。
14
+
15
+ <details>
16
+ <summary>点击查看项目截图</summary>
17
+ <img src="https://testingcf.jsdelivr.net/gh/bestZwei/imgs@master/picgo/image-20250406231222216.png" alt="项目截图" style="max-width:600px">
18
+ </details>
19
+
20
+ ## 🥇 感谢赞助
21
+
22
+ - **[YXVM](https://yxvm.com)**
23
+ - **[VTEXS](https://vtexs.com)**
24
+
25
+ ## 🚀 快速部署
26
+
27
+ 选择以下任一平台,点击一键部署按钮,即可快速创建自己的 LibreTV 实例:
28
+
29
+ [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FLibreSpark%2FLibreTV) [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/LibreSpark/LibreTV)
30
+
31
+ ## 📋 详细部署指南
32
+
33
+ ### Cloudflare Pages
34
+
35
+ 1. Fork 或克隆本仓库到您的 GitHub 账户
36
+ 2. 登录 [Cloudflare Dashboard](https://dash.cloudflare.com/),进入 Pages 服务
37
+ 3. 点击"创建项目",连接您的 GitHub 仓库
38
+ 4. 使用以下设置:
39
+ - 构建命令:留空(无需构建)
40
+ - 输出目录:留空(默认为根目录)
41
+ 5. 点击"保存并部署"
42
+ 6. 可选:在"设置" > "环境变量"中配置密码保护
43
+
44
+ ### Vercel
45
+
46
+ 1. Fork 或克隆本仓库到您的 GitHub/GitLab 账户
47
+ 2. 登录 [Vercel](https://vercel.com/),点击"New Project"
48
+ 3. 导入您的仓库,使用默认设置
49
+ 4. 点击"Deploy"
50
+ 5. 可选:在"Settings" > "Environment Variables"中配置密码保护
51
+
52
+ ### Netlify
53
+
54
+ 1. Fork 或克隆本仓库到您的 GitHub 账户
55
+ 2. 登录 [Netlify](https://app.netlify.com/)
56
+ 3. 点击"New site from Git",选择您的仓库
57
+ 4. 构建设置保持默认
58
+ 5. 点击"Deploy site"
59
+ 6. 可选:在"Site settings" > "Build & deploy" > "Environment"中配置密码保护
60
+
61
+ ### Docker
62
+
63
+ 使用 Docker 运行 LibreTV:
64
+
65
+ ```bash
66
+ docker run -d \
67
+ --name libretv \
68
+ -p 8899:80 \
69
+ -e PASSWORD=your_password_here \
70
+ bestzwei/libretv:latest
71
+ ```
72
+
73
+ 访问 `http://localhost:8899` 即可使用。
74
+
75
+ ### Docker Compose
76
+
77
+ `docker-compose.yml` 文件:
78
+
79
+ ```yaml
80
+ version: '3'
81
+ services:
82
+ libretv:
83
+ image: bestzwei/libretv:latest
84
+ container_name: libretv
85
+ ports:
86
+ - "8899:80"
87
+ environment:
88
+ - PASSWORD=111111
89
+ restart: unless-stopped
90
+ ```
91
+
92
+ ### 本地开发环境
93
+
94
+ 项目包含后端代理功能,需要支持服务器端功能的环境:
95
+
96
+ ```bash
97
+ # 安装依赖
98
+ npm install
99
+
100
+ # 启动开发服务器
101
+ npm run dev
102
+ ```
103
+
104
+ > ⚠️ 注意:使用简单静态服务器(如 `python -m http.server` 或 `npx http-server`)时,视频代理功能将不可用,视频无法正常播放。完整功能测试请使用 Node.js 开发服务器。
105
+
106
+ ## 🔧 自定义配置
107
+
108
+ ### 密码保护
109
+
110
+ 要为您的 LibreTV 实例添加密码保护,可以在部署平台上设置环境变量:
111
+
112
+ **环境变量名**: `PASSWORD`
113
+ **值**: 您想设置的密码
114
+
115
+ 各平台设置方法:
116
+
117
+ - **Cloudflare Pages**: Dashboard > 您的项目 > 设置 > 环境变量
118
+ - **Vercel**: Dashboard > 您的项目 > Settings > Environment Variables
119
+ - **Netlify**: Dashboard > 您的项目 > Site settings > Build & deploy > Environment
120
+ - **Docker**: 使用 `-e PASSWORD=your_password` 参数
121
+
122
+ ### API兼容性
123
+
124
+ LibreTV 支持标准的苹果 CMS V10 API 格式。添加自定义 API 时需遵循以下格式:
125
+ - 搜索接口: `https://example.com/api.php/provide/vod/?ac=videolist&wd=关键词`
126
+ - 详情接口: `https://example.com/api.php/provide/vod/?ac=detail&ids=视频ID`
127
+
128
+ **添加 CMS 源**:
129
+ 1. 在设置面板中选择"自定义接口"
130
+ 2. 接口地址只需填写到域名部分: `https://example.com`(不要包含`/api.php/provide/vod`部分)
131
+
132
+ ## ⌨️ 键盘快捷键
133
+
134
+ 播放器支持以下键盘快捷键:
135
+
136
+ - **空格键**: 播放/暂停
137
+ - **左右箭头**: 快退/快进
138
+ - **上下箭头**: 音量增加/减小
139
+ - **M 键**: 静音/取消静音
140
+ - **F 键**: 全屏/退出全屏
141
+ - **Esc 键**: 退出全屏
142
+
143
+ ## 🛠️ 技术栈
144
+
145
+ - HTML5 + CSS3 + JavaScript (ES6+)
146
+ - Tailwind CSS (通过 CDN 引入)
147
+ - HLS.js 用于 HLS 流处理
148
+ - DPlayer 视频播放器核心
149
+ - Cloudflare/Vercel/Netlify Serverless Functions
150
+ - 服务端 HLS 代理和处理技术
151
+ - localStorage 本地存储
152
+
153
+ ## 🔄 更新日志
154
+
155
+ <details>
156
+ <summary>点击查看更新日志</summary>
157
+
158
+ - **1.1.2** (2025-04-22): 新增豆瓣热门内容显示,设置中可开关
159
+ - **1.1.1** (2025-04-19):
160
+ - 修复 docker 部署时无法搜索的问题
161
+ - 修复播放页面进度保存与恢复的兼容性问题
162
+ - **1.1.0** (2025-04-17): 添加服务端代理功能,支持 HLS 流处理和解析,支持环境变量设置访问密码
163
+ - **1.0.3** (2025-04-13): 性能优化、UI优化、更新设置功能
164
+ - **1.0.2** (2025-04-08): 分离播放页面,优化视频源 API 兼容性
165
+ - **1.0.1** (2025-04-07): 添加广告过滤功能,优化播放器性能
166
+ - **1.0.0** (2025-04-06): 初始版本发布
167
+
168
+ </details>
169
+
170
+ ## ⚠️ 免责声明
171
+
172
+ LibreTV 仅作为视频搜索工具,不存储、上传或分发任何视频内容。所有视频均来自第三方 API 接口提供的搜索结果。如有侵权内容,请联系相应的内容提供方。
173
+
174
+ 本项目开发者不对使用本项目产生的任何后果负责。使用本项目时,您必须遵守当地的法律法规。
server.js ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const { createProxyMiddleware } = require('http-proxy-middleware');
3
+ const path = require('path');
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+
7
+ const app = express();
8
+ const PORT = process.env.PORT || 8080;
9
+
10
+ // 中间件:解析请求体
11
+ app.use(express.json());
12
+ app.use(express.urlencoded({ extended: true }));
13
+
14
+ // 中间件:处理HTML文件中的环境变量注入
15
+ app.use((req, res, next) => {
16
+ if (req.path.endsWith('.html') || req.path === '/' || req.path.endsWith('/')) {
17
+ const filePath = req.path === '/' || req.path.endsWith('/')
18
+ ? path.join(__dirname, 'index.html')
19
+ : path.join(__dirname, req.path);
20
+
21
+ if (fs.existsSync(filePath)) {
22
+ let content = fs.readFileSync(filePath, 'utf8');
23
+
24
+ // 替换密码占位符
25
+ const password = process.env.PASSWORD || '';
26
+ let passwordHash = '';
27
+
28
+ if (password) {
29
+ const hash = crypto.createHash('sha256');
30
+ hash.update(password);
31
+ passwordHash = hash.digest('hex');
32
+ }
33
+
34
+ content = content.replace(
35
+ 'window.__ENV__.PASSWORD = "{{PASSWORD}}";',
36
+ `window.__ENV__.PASSWORD = "${passwordHash}"; // SHA-256 hash`
37
+ );
38
+
39
+ res.setHeader('Content-Type', 'text/html');
40
+ return res.send(content);
41
+ }
42
+ }
43
+ next();
44
+ });
45
+
46
+ // 创建代理中间件函数
47
+ function createDynamicProxy(req, res, next) {
48
+ // 从URL参数获取目标URL
49
+ const targetUrl = decodeURIComponent(req.params.url);
50
+
51
+ if (!targetUrl || !targetUrl.match(/^https?:\/\/.+/i)) {
52
+ return res.status(400).json({
53
+ success: false,
54
+ error: '无效的目标URL'
55
+ });
56
+ }
57
+
58
+ // 提取主机和协议
59
+ try {
60
+ const urlObj = new URL(targetUrl);
61
+ const target = `${urlObj.protocol}//${urlObj.host}`;
62
+ const pathToProxy = urlObj.pathname + urlObj.search;
63
+
64
+ // 创建代理
65
+ const proxy = createProxyMiddleware({
66
+ target,
67
+ changeOrigin: true,
68
+ pathRewrite: () => pathToProxy,
69
+ onProxyReq: (proxyReq, req, res) => {
70
+ // 设置请求头
71
+ proxyReq.setHeader('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36');
72
+ proxyReq.setHeader('Accept', req.headers.accept || '*/*');
73
+ proxyReq.setHeader('Accept-Language', req.headers['accept-language'] || 'zh-CN,zh;q=0.9');
74
+ proxyReq.setHeader('Referer', req.headers.referer || target);
75
+ },
76
+ onProxyRes: (proxyRes, req, res) => {
77
+ // 设置CORS头
78
+ proxyRes.headers['Access-Control-Allow-Origin'] = '*';
79
+ proxyRes.headers['Access-Control-Allow-Methods'] = 'GET, HEAD, OPTIONS';
80
+ proxyRes.headers['Access-Control-Allow-Headers'] = '*';
81
+
82
+ // 设置缓存策略
83
+ proxyRes.headers['Cache-Control'] = 'public, max-age=86400';
84
+
85
+ // 移除可能导致问题的头部
86
+ delete proxyRes.headers['content-length'];
87
+ delete proxyRes.headers['content-encoding'];
88
+ }
89
+ });
90
+
91
+ proxy(req, res, next);
92
+ } catch (error) {
93
+ console.error(`代理错误: ${error.message}`);
94
+ return res.status(500).json({
95
+ success: false,
96
+ error: `代理请求失败: ${error.message}`
97
+ });
98
+ }
99
+ }
100
+
101
+ // 设置代理路由
102
+ app.use('/proxy/:url(*)', createDynamicProxy);
103
+
104
+ // OPTIONS请求处理
105
+ app.options('/proxy/:url(*)', (req, res) => {
106
+ res.setHeader('Access-Control-Allow-Origin', '*');
107
+ res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS');
108
+ res.setHeader('Access-Control-Allow-Headers', '*');
109
+ res.setHeader('Access-Control-Max-Age', '86400');
110
+ res.status(204).end();
111
+ });
112
+
113
+ // 静态文件服务 - 所有其他请求
114
+ app.use(express.static(path.join(__dirname), {
115
+ maxAge: '1d'
116
+ }));
117
+
118
+ // 错误处理中间件
119
+ app.use((err, req, res, next) => {
120
+ console.error(`服务器错误: ${err.stack}`);
121
+ res.status(500).send('服务器内部错误');
122
+ });
123
+
124
+ // 启动服务器
125
+ app.listen(PORT, () => {
126
+ console.log(`LibreTV 服务器已启动,运行在 http://localhost:${PORT}`);
127
+ console.log(`代理服务可通过 http://localhost:${PORT}/proxy/{URL} 访问`);
128
+ });