Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93106cbf3b | |||
| 0782e7f94f | |||
| 42c5f445be | |||
| edb9857e4a | |||
| ac3a42d0e3 | |||
| b25c738dbf | |||
| 7f73c00e0a | |||
| 672a386d2c | |||
| dd2edc48b3 | |||
| 9bfbf2d11d | |||
| a9bd8e47e1 | |||
| 60b1042a29 | |||
| 38f5ec35a1 | |||
| 1969ddfe59 | |||
| 7b0fb44c83 |
+2
-2
@@ -1,6 +1,6 @@
|
||||
# 更新日志
|
||||
|
||||
本文档记录了 MoonTV 项目的所有重要更改。
|
||||
本文档记录了 KatelyaTV 项目的所有重要更改。KatelyaTV 为在「MoonTV」基础上的二创与继承版本,延续上游核心能力并持续修复优化。
|
||||
|
||||
## [未发布]
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
- 社交分享功能
|
||||
- 用户评分系统
|
||||
|
||||
## [0.1.0] - 2025-01-XX
|
||||
## [0.1.0-katelya] - 2025-01-XX
|
||||
|
||||
### ✨ 新功能
|
||||
- 🎬 多源聚合搜索系统,集成20+个免费资源站点
|
||||
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
# 贡献指南
|
||||
|
||||
感谢您对 MoonTV 项目的关注!我们欢迎所有形式的贡献,包括但不限于:
|
||||
感谢您对 KatelyaTV 项目的关注!我们欢迎所有形式的贡献,包括但不限于:
|
||||
|
||||
- 🐛 报告 Bug
|
||||
- 💡 提出新功能建议
|
||||
@@ -23,8 +23,8 @@
|
||||
```bash
|
||||
# 在 GitHub 上 Fork 本仓库
|
||||
# 然后克隆到本地
|
||||
git clone https://github.com/YOUR_USERNAME/moontv.git
|
||||
cd moontv
|
||||
git clone https://github.com/YOUR_USERNAME/katelyatv.git
|
||||
cd katelyatv
|
||||
```
|
||||
|
||||
2. **安装依赖**
|
||||
@@ -114,7 +114,7 @@ git commit -m "test: 添加播放记录 API 测试用例"
|
||||
|
||||
在提交 Bug 报告之前,请:
|
||||
|
||||
1. 搜索现有的 [Issues](https://github.com/senshinya/moontv/issues)
|
||||
1. 搜索现有的 Issues(仓库 Issues 页面)
|
||||
2. 检查是否已有相关报告
|
||||
3. 使用 Bug 报告模板
|
||||
|
||||
@@ -153,7 +153,7 @@ git commit -m "test: 添加播放记录 API 测试用例"
|
||||
|
||||
在提出功能建议之前,请:
|
||||
|
||||
1. 搜索现有的 [Discussions](https://github.com/senshinya/moontw/discussions)
|
||||
1. 搜索现有的 Discussions(仓库 Discussions 页面)
|
||||
2. 检查是否已有相关讨论
|
||||
3. 使用功能建议模板
|
||||
|
||||
@@ -349,11 +349,11 @@ pnpm start
|
||||
### Docker 测试
|
||||
|
||||
```bash
|
||||
# 构建 Docker 镜像
|
||||
docker build -t moontv:test .
|
||||
# 构建 Docker 镜像(镜像名示例)
|
||||
docker build -t katelyatv:test .
|
||||
|
||||
# 运行容器
|
||||
docker run -d --name moontv-test -p 3000:3000 --env PASSWORD=test123 moontv:test
|
||||
docker run -d --name katelyatv-test -p 3000:3000 --env PASSWORD=test123 katelyatv:test
|
||||
```
|
||||
|
||||
## 📞 获取帮助
|
||||
@@ -367,7 +367,7 @@ docker run -d --name moontv-test -p 3000:3000 --env PASSWORD=test123 moontv:test
|
||||
|
||||
## 🎉 致谢
|
||||
|
||||
感谢所有为 MoonTV 项目做出贡献的开发者!
|
||||
感谢所有为 KatelyaTV 项目做出贡献的开发者!
|
||||
|
||||
您的贡献让这个项目变得更好。无论是代码、文档、测试还是反馈,我们都非常感激。
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
# KatelyaTV Docker 部署指南
|
||||
|
||||
> 本文档提供 KatelyaTV 的完整 Docker 部署指南,确保用户能够成功拉取和部署镜像。
|
||||
|
||||
## 📦 镜像信息
|
||||
|
||||
- **镜像地址**: `ghcr.io/katelya77/katelyatv:latest`
|
||||
- **支持架构**: linux/amd64, linux/arm64
|
||||
- **基础镜像**: node:20-alpine
|
||||
- **暴露端口**: 3000
|
||||
|
||||
## 🚀 快速部署
|
||||
|
||||
### 1. 单容器部署(推荐新手)
|
||||
|
||||
```bash
|
||||
# 拉取最新镜像
|
||||
docker pull ghcr.io/katelya77/katelyatv:latest
|
||||
|
||||
# 启动容器
|
||||
docker run -d \
|
||||
--name katelyatv \
|
||||
-p 3000:3000 \
|
||||
--env PASSWORD=your_secure_password \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/katelya77/katelyatv:latest
|
||||
|
||||
# 查看运行状态
|
||||
docker ps | grep katelyatv
|
||||
|
||||
# 查看日志
|
||||
docker logs katelyatv
|
||||
```
|
||||
|
||||
### 2. Docker Compose 部署(推荐生产环境)
|
||||
|
||||
创建 `docker-compose.yml` 文件:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
katelyatv:
|
||||
image: ghcr.io/katelya77/katelyatv:latest
|
||||
container_name: katelyatv
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- PASSWORD=your_secure_password
|
||||
- SITE_NAME=KatelyaTV
|
||||
volumes:
|
||||
# 可选:挂载自定义配置
|
||||
# - ./config.json:/app/config.json:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
启动服务:
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
docker-compose up -d
|
||||
|
||||
# 查看状态
|
||||
docker-compose ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
## 🗄️ 数据持久化部署(Redis)
|
||||
|
||||
对于需要多用户支持和数据同步的场景:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
katelyatv:
|
||||
image: ghcr.io/katelya77/katelyatv:latest
|
||||
container_name: katelyatv
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- USERNAME=admin
|
||||
- PASSWORD=admin_password
|
||||
- NEXT_PUBLIC_STORAGE_TYPE=redis
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- NEXT_PUBLIC_ENABLE_REGISTER=true
|
||||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- katelyatv-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: katelyatv-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- katelyatv-network
|
||||
command: redis-server --appendonly yes
|
||||
|
||||
volumes:
|
||||
redis_data:
|
||||
|
||||
networks:
|
||||
katelyatv-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## 🔧 环境变量配置
|
||||
|
||||
| 变量名 | 描述 | 默认值 | 示例 |
|
||||
|--------|------|--------|------|
|
||||
| `PASSWORD` | 访问密码 | - | `my_secure_password` |
|
||||
| `USERNAME` | 管理员用户名(Redis模式) | - | `admin` |
|
||||
| `SITE_NAME` | 站点名称 | `KatelyaTV` | `我的影视站` |
|
||||
| `NEXT_PUBLIC_STORAGE_TYPE` | 存储类型 | `localstorage` | `redis`, `d1`, `upstash` |
|
||||
| `REDIS_URL` | Redis连接地址 | - | `redis://redis:6379` |
|
||||
| `NEXT_PUBLIC_ENABLE_REGISTER` | 开放注册 | `false` | `true` |
|
||||
| `NEXT_PUBLIC_SEARCH_MAX_PAGE` | 搜索最大页数 | `5` | `10` |
|
||||
|
||||
## 🔍 故障排查
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **容器启动失败**
|
||||
```bash
|
||||
# 查看详细错误信息
|
||||
docker logs katelyatv
|
||||
|
||||
# 检查端口占用
|
||||
netstat -tulpn | grep :3000
|
||||
```
|
||||
|
||||
2. **镜像拉取失败**
|
||||
```bash
|
||||
# 确认镜像地址正确
|
||||
docker pull ghcr.io/katelya77/katelyatv:latest
|
||||
|
||||
# 如果是私有仓库,需要先登录
|
||||
docker login ghcr.io
|
||||
```
|
||||
|
||||
3. **数据丢失问题**
|
||||
- localStorage 模式:数据存储在浏览器,清除缓存会丢失
|
||||
- 建议使用 Redis 模式进行数据持久化
|
||||
|
||||
### 健康检查
|
||||
|
||||
```bash
|
||||
# 检查容器状态
|
||||
docker ps
|
||||
|
||||
# 检查容器健康状态
|
||||
docker inspect katelyatv | grep -A 5 "Health"
|
||||
|
||||
# 测试应用响应
|
||||
curl -I http://localhost:3000
|
||||
```
|
||||
|
||||
## 🔄 更新升级
|
||||
|
||||
### 更新到最新版本
|
||||
|
||||
```bash
|
||||
# 停止旧容器
|
||||
docker stop katelyatv
|
||||
docker rm katelyatv
|
||||
|
||||
# 拉取最新镜像
|
||||
docker pull ghcr.io/katelya77/katelyatv:latest
|
||||
|
||||
# 启动新容器(使用相同配置)
|
||||
docker run -d \
|
||||
--name katelyatv \
|
||||
-p 3000:3000 \
|
||||
--env PASSWORD=your_secure_password \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/katelya77/katelyatv:latest
|
||||
```
|
||||
|
||||
### Docker Compose 更新
|
||||
|
||||
```bash
|
||||
# 拉取最新镜像
|
||||
docker-compose pull
|
||||
|
||||
# 重新创建容器
|
||||
docker-compose up -d --force-recreate
|
||||
```
|
||||
|
||||
## 🔐 安全建议
|
||||
|
||||
1. **设置强密码**: 使用复杂密码保护访问
|
||||
2. **限制访问**: 配置防火墙或反向代理限制访问来源
|
||||
3. **定期更新**: 保持镜像版本最新
|
||||
4. **数据备份**: 定期备份 Redis 数据(如果使用)
|
||||
5. **监控日志**: 关注异常访问和错误日志
|
||||
|
||||
## 📊 性能优化
|
||||
|
||||
### 资源限制
|
||||
|
||||
```yaml
|
||||
services:
|
||||
katelyatv:
|
||||
image: ghcr.io/katelya77/katelyatv:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.25'
|
||||
```
|
||||
|
||||
### 反向代理(Nginx)
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🆘 获取帮助
|
||||
|
||||
- 📖 [项目文档](README.md)
|
||||
- 🐛 [问题反馈](https://github.com/katelya77/KatelyaTV/issues)
|
||||
- 💬 [讨论区](https://github.com/katelya77/KatelyaTV/discussions)
|
||||
|
||||
---
|
||||
|
||||
**注意**: 本项目仅供学习和个人使用,请遵守当地法律法规。
|
||||
+6
-4
@@ -1,10 +1,10 @@
|
||||
# 📊 MoonTV 项目状态报告
|
||||
# 📊 KatelyaTV 项目状态报告
|
||||
|
||||
## 🎯 项目概述
|
||||
|
||||
**MoonTV** 是一个功能完整的影视聚合播放器,基于现代 Web 技术栈构建,支持多平台部署和多种存储后端。
|
||||
**KatelyaTV** 是一个功能完整的影视聚合播放器,基于现代 Web 技术栈构建,支持多平台部署和多种存储后端。该项目为在原始项目「MoonTV」基础上的二创与继承版本,延续其优秀架构并在此之上进行持续优化与维护。
|
||||
|
||||
**当前版本**: v0.1.0
|
||||
**当前版本**: v0.1.0-katelya
|
||||
**最后更新**: 2025-01-XX
|
||||
**项目状态**: 🟢 生产就绪
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
MoonTV 项目目前处于**生产就绪**状态,核心功能完整,技术架构成熟,用户体验优秀。项目具备以下特点:
|
||||
KatelyaTV 项目目前处于**生产就绪**状态,核心功能完整,技术架构成熟,用户体验优秀。项目具备以下特点:
|
||||
|
||||
- ✅ **功能完整**: 所有核心功能均已实现
|
||||
- ✅ **技术先进**: 使用最新的 Web 技术
|
||||
@@ -203,6 +203,8 @@ MoonTV 项目目前处于**生产就绪**状态,核心功能完整,技术架
|
||||
|
||||
项目可以安全地用于生产环境,适合个人用户和中小型团队使用。
|
||||
|
||||
> 注:KatelyaTV 基于 MoonTV 二创与继承开发,保留并致谢原作者与社区贡献;如有授权或版权问题,请联系以尽快处理。
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-01-XX
|
||||
|
||||
+18
-11
@@ -1,6 +1,6 @@
|
||||
# 🚀 MoonTV 快速开始指南
|
||||
# 🚀 KatelyaTV 快速开始指南
|
||||
|
||||
欢迎使用 MoonTV!本指南将帮助您在几分钟内完成部署和配置。
|
||||
欢迎使用 KatelyaTV!本指南将帮助您在几分钟内完成部署和配置。
|
||||
|
||||
## 📋 前置要求
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
|
||||
```bash
|
||||
# 拉取最新镜像
|
||||
docker pull ghcr.io/senshinya/moontv:latest
|
||||
docker pull ghcr.io/katelya77/katelyatv:latest
|
||||
|
||||
# 启动容器
|
||||
docker run -d \
|
||||
--name moontv \
|
||||
--name katelyatv \
|
||||
-p 3000:3000 \
|
||||
--env PASSWORD=your_password \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/senshinya/moontv:latest
|
||||
ghcr.io/katelya77/katelyatv:latest
|
||||
```
|
||||
|
||||
### 2. 访问应用
|
||||
@@ -33,10 +33,10 @@ docker run -d \
|
||||
|
||||
```bash
|
||||
# 停止容器
|
||||
docker stop moontv
|
||||
docker stop katelyatv
|
||||
|
||||
# 删除容器
|
||||
docker rm moontv
|
||||
docker rm katelyatv
|
||||
```
|
||||
|
||||
## 🌐 云平台部署
|
||||
@@ -91,11 +91,13 @@ nano .env.local
|
||||
```
|
||||
|
||||
**必需配置:**
|
||||
|
||||
```bash
|
||||
PASSWORD=your_secure_password
|
||||
```
|
||||
|
||||
**推荐配置:**
|
||||
|
||||
```bash
|
||||
SITE_NAME=我的影视站
|
||||
NEXT_PUBLIC_STORAGE_TYPE=localstorage
|
||||
@@ -197,15 +199,19 @@ NEXT_PUBLIC_STORAGE_TYPE=d1
|
||||
## 🚨 常见问题
|
||||
|
||||
### Q: 无法访问应用
|
||||
|
||||
**A:** 检查端口是否被占用,防火墙设置,或尝试其他端口。
|
||||
|
||||
### Q: 搜索无结果
|
||||
|
||||
**A:** 检查网络连接,资源站点是否可用,或尝试其他关键词。
|
||||
|
||||
### Q: 视频无法播放
|
||||
|
||||
**A:** 检查视频源是否有效,浏览器是否支持相关格式。
|
||||
|
||||
### Q: 数据丢失
|
||||
|
||||
**A:** 如果使用 localStorage,数据存储在浏览器中,清除缓存会丢失数据。
|
||||
|
||||
## 📱 移动端使用
|
||||
@@ -224,19 +230,20 @@ NEXT_PUBLIC_STORAGE_TYPE=d1
|
||||
## 📞 获取帮助
|
||||
|
||||
- 📖 [完整文档](README.md)
|
||||
- 🐛 [问题反馈](https://github.com/senshinya/moontv/issues)
|
||||
- 💬 [功能讨论](https://github.com/senshinya/moontv/discussions)
|
||||
- 🐛 问题反馈:在仓库 Issues 页面提交
|
||||
- 💬 功能讨论:在 Discussions 页面参与
|
||||
- 📝 [更新日志](CHANGELOG.md)
|
||||
|
||||
## 🎉 开始使用
|
||||
|
||||
现在您已经完成了基础配置,可以开始享受 MoonTV 带来的影视体验了!
|
||||
现在您已经完成了基础配置,可以开始享受 KatelyaTV 带来的影视体验了!
|
||||
|
||||
**重要提醒:**
|
||||
|
||||
- 本项目仅供学习和个人使用
|
||||
- 请遵守当地法律法规
|
||||
- 不要用于商业用途或公开服务
|
||||
|
||||
---
|
||||
|
||||
如有任何问题,欢迎在 GitHub 上提出 Issue 或参与讨论!
|
||||
如有任何问题,欢迎在 GitHub 上提出 Issue 或参与讨论!
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# MoonTV
|
||||
# KatelyaTV
|
||||
|
||||
<div align="center">
|
||||
<img src="public/logo.png" alt="MoonTV Logo" width="120">
|
||||
<img src="public/logo.png" alt="KatelyaTV Logo" width="120">
|
||||
</div>
|
||||
|
||||
> 🎬 **MoonTV** 是一个开箱即用的、跨平台的影视聚合播放器。它基于 **Next.js 14** + **Tailwind CSS** + **TypeScript** 构建,支持多资源搜索、在线播放、收藏同步、播放记录、本地/云端存储,让你可以随时随地畅享海量免费影视内容。
|
||||
> 🎬 **KatelyaTV** 是一个开箱即用的、跨平台的影视聚合播放器。它基于 **Next.js 14** + **Tailwind CSS** + **TypeScript** 构建,支持多资源搜索、在线播放、收藏同步、播放记录、本地/云端存储,让你可以随时随地畅享海量免费影视内容。
|
||||
>
|
||||
> 本项目是在原始项目「MoonTV」基础上的二创与继承版本,由 Katelya 持续开发与维护。在致敬原作的前提下,继续修复问题、优化体验并扩展功能。
|
||||
|
||||
<div align="center">
|
||||
|
||||
@@ -43,6 +45,7 @@
|
||||
|
||||
- [技术栈](#技术栈)
|
||||
- [核心功能](#核心功能)
|
||||
- [项目来源与声明](#项目来源与声明)
|
||||
- [部署](#部署)
|
||||
- [Docker Compose 最佳实践](#Docker-Compose-最佳实践)
|
||||
- [环境变量](#环境变量)
|
||||
@@ -69,6 +72,7 @@
|
||||
## 🎯 核心功能
|
||||
|
||||
### 观看历史记录
|
||||
|
||||
- **智能进度记录**:自动记录每个视频的播放进度、观看时长、当前集数
|
||||
- **断点续播**:支持从上次观看位置继续播放,无需手动寻找
|
||||
- **多设备同步**:通过 Redis/D1/Upstash 存储,实现跨设备观看记录同步
|
||||
@@ -76,23 +80,32 @@
|
||||
- **进度条显示**:在视频卡片上显示观看进度百分比
|
||||
|
||||
### 多源聚合搜索
|
||||
|
||||
- **20+ 资源站点**:集成电影天堂、黑木耳、如意资源等热门站点
|
||||
- **统一搜索接口**:一次搜索返回多个源的结果,提高资源获取成功率
|
||||
- **智能去重**:自动识别重复内容,优化搜索结果展示
|
||||
- **分类筛选**:支持按电影、电视剧、综艺等类型筛选
|
||||
|
||||
### 收藏与同步
|
||||
|
||||
- **个性化收藏**:支持收藏喜欢的影视作品,创建个人片单
|
||||
- **多端同步**:收藏数据云端存储,多设备访问保持一致
|
||||
- **观看状态**:收藏夹中显示观看进度和当前集数
|
||||
- **批量管理**:支持批量删除和清空收藏
|
||||
|
||||
### PWA 特性
|
||||
|
||||
- **离线缓存**:支持离线访问已缓存的内容
|
||||
- **桌面安装**:可安装到桌面,提供原生应用体验
|
||||
- **推送通知**:支持新内容推送和更新提醒
|
||||
- **响应式设计**:完美适配各种屏幕尺寸
|
||||
|
||||
## 📢 项目来源与声明
|
||||
|
||||
- 本项目自「MoonTV」演进而来,为其二创/继承版本,持续维护与改进功能与体验。
|
||||
- 代码中保留并致谢原有作者与社区贡献者;如有授权或版权问题,请与我们联系以尽快处理。
|
||||
- KatelyaTV 致力于在原作优秀基础上,提供更易部署、更友好、更稳定的使用体验。
|
||||
|
||||
## 🚀 部署
|
||||
|
||||
本项目**支持 Vercel、Docker 和 Cloudflare** 部署。
|
||||
@@ -163,11 +176,11 @@
|
||||
|
||||
```bash
|
||||
# 拉取预构建镜像
|
||||
docker pull ghcr.io/senshinya/moontv:latest
|
||||
docker pull ghcr.io/katelya77/katelyatv:latest
|
||||
|
||||
# 运行容器
|
||||
# -d: 后台运行 -p: 映射端口 3000 -> 3000
|
||||
docker run -d --name moontv -p 3000:3000 --env PASSWORD=your_password ghcr.io/senshinya/moontv:latest
|
||||
docker run -d --name katelyatv -p 3000:3000 --env PASSWORD=your_password ghcr.io/katelya77/katelyatv:latest
|
||||
```
|
||||
|
||||
访问 `http://服务器 IP:3000` 即可。(需自行到服务器控制台放通 `3000` 端口)
|
||||
@@ -180,9 +193,9 @@ docker run -d --name moontv -p 3000:3000 --env PASSWORD=your_password ghcr.io/se
|
||||
|
||||
```yaml
|
||||
services:
|
||||
moontv:
|
||||
image: ghcr.io/senshinya/moontv:latest
|
||||
container_name: moontv
|
||||
katelyatv:
|
||||
image: ghcr.io/katelya77/katelyatv:latest
|
||||
container_name: katelyatv
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3000:3000'
|
||||
@@ -197,9 +210,9 @@ services:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
moontv-core:
|
||||
image: ghcr.io/senshinya/moontv:latest
|
||||
container_name: moontv
|
||||
katelyatv-core:
|
||||
image: ghcr.io/katelya77/katelyatv:latest
|
||||
container_name: katelyatv
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3000:3000'
|
||||
@@ -207,26 +220,26 @@ services:
|
||||
- USERNAME=admin
|
||||
- PASSWORD=admin_password
|
||||
- NEXT_PUBLIC_STORAGE_TYPE=redis
|
||||
- REDIS_URL=redis://moontv-redis:6379
|
||||
- REDIS_URL=redis://katelyatv-redis:6379
|
||||
- NEXT_PUBLIC_ENABLE_REGISTER=true
|
||||
networks:
|
||||
- moontv-network
|
||||
- katelyatv-network
|
||||
depends_on:
|
||||
- moontv-redis
|
||||
- katelyatv-redis
|
||||
# 如需自定义配置,可挂载文件
|
||||
# volumes:
|
||||
# - ./config.json:/app/config.json:ro
|
||||
moontv-redis:
|
||||
katelyatv-redis:
|
||||
image: redis
|
||||
container_name: moontv-redis
|
||||
container_name: katelyatv-redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- moontv-network
|
||||
- katelyatv-network
|
||||
# 如需持久化
|
||||
# volumes:
|
||||
# - ./data:/data
|
||||
networks:
|
||||
moontv-network:
|
||||
katelyatv-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
@@ -242,7 +255,7 @@ networks:
|
||||
| --------------------------- | ----------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
||||
| USERNAME | redis 部署时的管理员账号 | 任意字符串 | (空) |
|
||||
| PASSWORD | 默认部署时为唯一访问密码,redis 部署时为管理员密码 | 任意字符串 | (空) |
|
||||
| SITE_NAME | 站点名称 | 任意字符串 | MoonTV |
|
||||
| SITE_NAME | 站点名称 | 任意字符串 | KatelyaTV |
|
||||
| ANNOUNCEMENT | 站点公告 | 任意字符串 | 本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。 |
|
||||
| NEXT_PUBLIC_STORAGE_TYPE | 播放记录/收藏的存储方式 | localstorage、redis、d1、upstash | localstorage |
|
||||
| REDIS_URL | redis 连接 url,若 NEXT_PUBLIC_STORAGE_TYPE 为 redis 则必填 | 连接 url | 空 |
|
||||
@@ -278,7 +291,7 @@ networks:
|
||||
- `name`:在人机界面中展示的名称。
|
||||
- `detail`:(可选)部分无法通过 API 获取剧集详情的站点,需要提供网页详情根 URL,用于爬取。
|
||||
|
||||
MoonTV 支持标准的苹果 CMS V10 API 格式。
|
||||
KatelyaTV 支持标准的苹果 CMS V10 API 格式。
|
||||
|
||||
修改后 **无需重新构建**,服务会在启动时读取一次。
|
||||
|
||||
@@ -336,12 +349,13 @@ MoonTV 支持标准的苹果 CMS V10 API 格式。
|
||||
|
||||
## 📄 License
|
||||
|
||||
[MIT](LICENSE) © 2025 MoonTV & Contributors
|
||||
[MIT](LICENSE) © 2025 KatelyaTV & Contributors
|
||||
|
||||
## 🙏 致谢
|
||||
|
||||
- [ts-nextjs-tailwind-starter](https://github.com/theodorusclarence/ts-nextjs-tailwind-starter) — 项目最初基于该脚手架。
|
||||
- [LibreTV](https://github.com/LibreSpark/LibreTV) — 由此启发,站在巨人的肩膀上。
|
||||
- [LunaTV-原MoonTV](https://github.com/MoonTechLab/LunaTV) — 原始项目与作者社区,感谢原作奠定坚实基础。
|
||||
- [ArtPlayer](https://github.com/zhw2590582/ArtPlayer) — 提供强大的网页视频播放器。
|
||||
- [HLS.js](https://github.com/video-dev/hls.js) — 实现 HLS 流媒体在浏览器中的播放支持。
|
||||
- 感谢所有提供免费影视接口的站点。
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# KatelyaTV v0.1.0-katelya 发布说明
|
||||
|
||||
> 本项目在「MoonTV」基础上进行二创与继承,由 Katelya 持续维护。保留并致谢原作与社区贡献,在不改变核心理念的前提下,专注于更易部署、更友好体验与更稳定维护。
|
||||
|
||||
## 亮点
|
||||
|
||||
- 全面延续上游核心:多源聚合搜索、在线播放、收藏与观看历史、PWA 支持、响应式布局、多用户系统等
|
||||
- 文档重写与梳理:README、QUICKSTART、PROJECT_STATUS、CONTRIBUTING、CHANGELOG 全面适配 KatelyaTV 品牌
|
||||
- 部署指引优化:Vercel / Docker / Cloudflare Pages 一站式说明,提供 Compose 最佳实践
|
||||
- 安全与隐私提醒:新增部署安全提示与法律风险说明
|
||||
|
||||
## 变更摘要
|
||||
|
||||
- 品牌与文档
|
||||
- 将项目品牌统一为 KatelyaTV,并明确二创与继承来源
|
||||
- 更新部署与使用说明,优化快速上手体验
|
||||
- 调整仓库路径、示例命令与 Docker 镜像示例名称(镜像仍沿用上游命名空间)
|
||||
- 代码与配置
|
||||
- 保持与上游 MoonTV 的接口与行为兼容
|
||||
- 默认站点名改为 `KatelyaTV`(可通过 `SITE_NAME` 环境变量覆盖)
|
||||
|
||||
## 安装与升级
|
||||
|
||||
- 首次安装(Docker 推荐)
|
||||
|
||||
```bash
|
||||
# 拉取镜像
|
||||
docker pull ghcr.io/katelya77/katelyatv:latest
|
||||
|
||||
# 启动示例
|
||||
docker run -d --name katelyatv \
|
||||
-p 3000:3000 \
|
||||
--env PASSWORD=your_password \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/katelya77/katelyatv:latest
|
||||
```
|
||||
|
||||
- 或使用 README 中的 Docker Compose 示例
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 保持与上游 MoonTV v0.1.0 行为一致
|
||||
- 支持存储后端:localStorage / Redis / Cloudflare D1 / Upstash Redis
|
||||
- 运行环境:Node.js 18+;容器镜像支持多架构
|
||||
|
||||
## 已知问题
|
||||
|
||||
- 部分第三方资源站可用性受其自身状态影响
|
||||
- Android TV 端收藏与网页端暂未完全互通(后续版本优化)
|
||||
|
||||
## 后续路线
|
||||
|
||||
- 弹幕系统、字幕支持、下载功能、社交分享
|
||||
- 数据同步与多端互通完善
|
||||
- 性能与稳定性持续优化
|
||||
|
||||
## 鸣谢
|
||||
|
||||
- 原始项目 MoonTV 及其作者与社区
|
||||
- 所有为本项目提供反馈、贡献代码与文档的开发者
|
||||
|
||||
— Katelya
|
||||
+1
-1
@@ -1 +1 @@
|
||||
20250928125318
|
||||
20250830155949
|
||||
@@ -1 +0,0 @@
|
||||
if(!self.define){let e,s={};const n=(n,a)=>(n=new URL(n+".js",a).href,s[n]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()}).then(()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(a,i)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(s[c])return;let t={};const r=e=>n(e,c),o={module:{uri:c},exports:t,require:r};s[c]=Promise.all(a.map(e=>o[e]||r(e))).then(e=>(i(...e),t))}}define(["./workbox-e9849328"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"165f11a0a3d5db6c1c8dc7aa005033e2"},{url:"/_next/static/0Xa7Nn4iRGMNLwKw4hJZP/_buildManifest.js",revision:"85aecd8a55db42fc901f52386fd2a680"},{url:"/_next/static/0Xa7Nn4iRGMNLwKw4hJZP/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/151-467740e7dc8a9501.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/180-9f7b03cf3105da2f.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/242-3804d87f50553b94.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/348-637558541eb689b6.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/402-abec0144ce81ad6a.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/62-9dcc8624f6dcf545.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/78-2aa39dfce34bcd40.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/866-d2269a3038f10b5a.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/_not-found/page-d6cb5fee19b812f4.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/admin/page-cf6fa07173bfdcbf.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/douban/page-984df666dd74a3f5.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/layout-f2be6b03f6eb1026.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/login/page-21403bbd4848f696.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/page-e8549ab6c668cffc.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/play/page-c55fbb62b2dc4ace.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/search/page-5dc770f3abeac649.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/app/warning/page-e6b20b93b37dc516.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/b145b63a-b7e49c063d2fa255.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/c72274ce-909438a8a5dd87a5.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/da9543df-c2ce5269243dd748.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/framework-6e06c675866dc992.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/main-app-0cf6afdd74694b9f.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/main-e84422daeb8eaf88.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/pages/_app-3fcac1a2c632f1ef.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/pages/_error-d3fe151bf402c134.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-4a57793b45c0f940.js",revision:"0Xa7Nn4iRGMNLwKw4hJZP"},{url:"/_next/static/css/23100062f5d4aac0.css",revision:"23100062f5d4aac0"},{url:"/_next/static/css/a7b7a98490e311ff.css",revision:"a7b7a98490e311ff"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/8e9860b6e62d6359-s.woff2",revision:"01ba6c2a184b8cba08b0d57167664d75"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/e4af272ccee01ff0-s.p.woff2",revision:"65850a373e258f1c897a2b3d75eb74de"},{url:"/favicon.ico",revision:"c5de6e56c5664adda146825f75ea6ecf"},{url:"/icons/icon-192x192.png",revision:"4a56c090828a1ad254c903c7aec0389d"},{url:"/icons/icon-256x256.png",revision:"f6409eb1a001f754121e3a8281c0319c"},{url:"/icons/icon-384x384.png",revision:"f6efc3e357b9ffdf4e0d8c14b2ed0ac1"},{url:"/icons/icon-512x512.png",revision:"9c008cbbeb6a576fe07bb1284a83f4d2"},{url:"/logo.png",revision:"40de611b143c47c6291c7bdad2c959ca"},{url:"/manifest.json",revision:"f8a4f2b082d6396d3b1a84ce0e267dfe"},{url:"/robots.txt",revision:"0483b37fb6cf7455cefe516197e39241"},{url:"/screenshot.png",revision:"05a86e8d4faae6b384d19f02173ea87f"},{url:"/screenshot1.png",revision:"d7de3a25686c5b9c9d8c8675bc6109fc"},{url:"/screenshot2.png",revision:"b0b715a3018d2f02aba5d94762473bb6"},{url:"/screenshot3.png",revision:"7e454c28e110e291ee12f494fb3cf40c"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:n,state:a})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;const s=e.pathname;return!s.startsWith("/api/auth/")&&!!s.startsWith("/api/")},new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>{if(!(self.origin===e.origin))return!1;return!e.pathname.startsWith("/api/")},new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(({url:e})=>!(self.origin===e.origin),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")});
|
||||
|
||||
@@ -11,7 +11,7 @@ const publicDir = path.join(projectRoot, 'public');
|
||||
const manifestPath = path.join(publicDir, 'manifest.json');
|
||||
|
||||
// 从环境变量获取站点名称
|
||||
const siteName = process.env.SITE_NAME || 'MoonTV';
|
||||
const siteName = process.env.SITE_NAME || 'KatelyaTV';
|
||||
|
||||
// manifest.json 模板
|
||||
const manifestTemplate = {
|
||||
|
||||
Executable → Regular
@@ -35,7 +35,10 @@ function VersionDisplay() {
|
||||
return (
|
||||
<button
|
||||
onClick={() =>
|
||||
window.open('https://github.com/senshinya/MoonTV', '_blank')
|
||||
window.open(
|
||||
process.env.NEXT_PUBLIC_REPO_URL || 'https://github.com/katelya77/KatelyaTV',
|
||||
'_blank'
|
||||
)
|
||||
}
|
||||
className='absolute bottom-4 left-1/2 transform -translate-x-1/2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400 transition-colors cursor-pointer'
|
||||
>
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ const BottomKatelyaLogo = () => {
|
||||
<div className='text-center'>
|
||||
<div className='bottom-logo'>KatelyaTV</div>
|
||||
<div className='mt-2 text-sm text-gray-500 dark:text-gray-400 opacity-75'>
|
||||
Powered by MoonTV Core
|
||||
Powered by KatelyaTV Core
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: '安全警告 - MoonTV',
|
||||
title: '安全警告 - KatelyaTV',
|
||||
description: '站点安全配置警告',
|
||||
};
|
||||
|
||||
|
||||
+4
-4
@@ -151,7 +151,7 @@ async function initConfig() {
|
||||
}
|
||||
adminConfig = {
|
||||
SiteConfig: {
|
||||
SiteName: process.env.SITE_NAME || 'MoonTV',
|
||||
SiteName: process.env.SITE_NAME || 'KatelyaTV',
|
||||
Announcement:
|
||||
process.env.ANNOUNCEMENT ||
|
||||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
|
||||
@@ -190,7 +190,7 @@ async function initConfig() {
|
||||
// 本地存储直接使用文件配置
|
||||
cachedConfig = {
|
||||
SiteConfig: {
|
||||
SiteName: process.env.SITE_NAME || 'MoonTV',
|
||||
SiteName: process.env.SITE_NAME || 'KatelyaTV',
|
||||
Announcement:
|
||||
process.env.ANNOUNCEMENT ||
|
||||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
|
||||
@@ -230,7 +230,7 @@ export async function getConfig(): Promise<AdminConfig> {
|
||||
}
|
||||
if (adminConfig) {
|
||||
// 合并一些环境变量配置
|
||||
adminConfig.SiteConfig.SiteName = process.env.SITE_NAME || 'MoonTV';
|
||||
adminConfig.SiteConfig.SiteName = process.env.SITE_NAME || 'KatelyaTV';
|
||||
adminConfig.SiteConfig.Announcement =
|
||||
process.env.ANNOUNCEMENT ||
|
||||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。';
|
||||
@@ -337,7 +337,7 @@ export async function resetConfig() {
|
||||
}
|
||||
const adminConfig = {
|
||||
SiteConfig: {
|
||||
SiteName: process.env.SITE_NAME || 'MoonTV',
|
||||
SiteName: process.env.SITE_NAME || 'KatelyaTV',
|
||||
Announcement:
|
||||
process.env.ANNOUNCEMENT ||
|
||||
'本网站仅提供影视信息搜索服务,所有内容均来自第三方网站。本站不存储任何视频资源,不对任何内容的准确性、合法性、完整性负责。',
|
||||
|
||||
+20
-7
@@ -55,12 +55,17 @@ interface UserCacheStore {
|
||||
}
|
||||
|
||||
// ---- 常量 ----
|
||||
const PLAY_RECORDS_KEY = 'moontv_play_records';
|
||||
const FAVORITES_KEY = 'moontv_favorites';
|
||||
const SEARCH_HISTORY_KEY = 'moontv_search_history';
|
||||
// 新的键名(KatelyaTV)与旧键名(MoonTV)保持向后兼容
|
||||
const PLAY_RECORDS_KEY = 'katelyatv_play_records';
|
||||
const FAVORITES_KEY = 'katelyatv_favorites';
|
||||
const SEARCH_HISTORY_KEY = 'katelyatv_search_history';
|
||||
const LEGACY_PLAY_RECORDS_KEY = 'moontv_play_records';
|
||||
const LEGACY_FAVORITES_KEY = 'moontv_favorites';
|
||||
const LEGACY_SEARCH_HISTORY_KEY = 'moontv_search_history';
|
||||
|
||||
// 缓存相关常量
|
||||
const CACHE_PREFIX = 'moontv_cache_';
|
||||
const CACHE_PREFIX = 'katelyatv_cache_';
|
||||
const LEGACY_CACHE_PREFIX = 'moontv_cache_';
|
||||
const CACHE_VERSION = '1.0.0';
|
||||
const CACHE_EXPIRE_TIME = 60 * 60 * 1000; // 一小时缓存过期
|
||||
|
||||
@@ -426,7 +431,9 @@ export async function getAllPlayRecords(): Promise<Record<string, PlayRecord>> {
|
||||
|
||||
// localstorage 模式
|
||||
try {
|
||||
const raw = localStorage.getItem(PLAY_RECORDS_KEY);
|
||||
const primary = localStorage.getItem(PLAY_RECORDS_KEY);
|
||||
const fallback = localStorage.getItem(LEGACY_PLAY_RECORDS_KEY);
|
||||
const raw = primary ?? fallback;
|
||||
if (!raw) return {};
|
||||
return JSON.parse(raw) as Record<string, PlayRecord>;
|
||||
} catch (err) {
|
||||
@@ -614,7 +621,9 @@ export async function getSearchHistory(): Promise<string[]> {
|
||||
|
||||
// localStorage 模式
|
||||
try {
|
||||
const raw = localStorage.getItem(SEARCH_HISTORY_KEY);
|
||||
const primary = localStorage.getItem(SEARCH_HISTORY_KEY);
|
||||
const fallback = localStorage.getItem(LEGACY_SEARCH_HISTORY_KEY);
|
||||
const raw = primary ?? fallback;
|
||||
if (!raw) return [];
|
||||
const arr = JSON.parse(raw) as string[];
|
||||
// 仅返回字符串数组
|
||||
@@ -835,7 +844,9 @@ export async function getAllFavorites(): Promise<Record<string, Favorite>> {
|
||||
|
||||
// localStorage 模式
|
||||
try {
|
||||
const raw = localStorage.getItem(FAVORITES_KEY);
|
||||
const primary = localStorage.getItem(FAVORITES_KEY);
|
||||
const fallback = localStorage.getItem(LEGACY_FAVORITES_KEY);
|
||||
const raw = primary ?? fallback;
|
||||
if (!raw) return {};
|
||||
return JSON.parse(raw) as Record<string, Favorite>;
|
||||
} catch (err) {
|
||||
@@ -1053,6 +1064,7 @@ export async function clearAllPlayRecords(): Promise<void> {
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.removeItem(PLAY_RECORDS_KEY);
|
||||
localStorage.removeItem(LEGACY_PLAY_RECORDS_KEY);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('playRecordsUpdated', {
|
||||
detail: {},
|
||||
@@ -1094,6 +1106,7 @@ export async function clearAllFavorites(): Promise<void> {
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.removeItem(FAVORITES_KEY);
|
||||
localStorage.removeItem(LEGACY_FAVORITES_KEY);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('favoritesUpdated', {
|
||||
detail: {},
|
||||
|
||||
+5
-2
@@ -287,8 +287,9 @@ export class RedisStorage implements IStorage {
|
||||
|
||||
// 单例 Redis 客户端
|
||||
function getRedisClient(): RedisClientType {
|
||||
const globalKey = Symbol.for('__MOONTV_REDIS_CLIENT__');
|
||||
let client: RedisClientType | undefined = (global as any)[globalKey];
|
||||
const legacyKey = Symbol.for('__MOONTV_REDIS_CLIENT__');
|
||||
const globalKey = Symbol.for('__KATELYATV_REDIS_CLIENT__');
|
||||
let client: RedisClientType | undefined = (global as any)[globalKey] || (global as any)[legacyKey];
|
||||
|
||||
if (!client) {
|
||||
const url = process.env.REDIS_URL;
|
||||
@@ -349,6 +350,8 @@ function getRedisClient(): RedisClientType {
|
||||
connectWithRetry();
|
||||
|
||||
(global as any)[globalKey] = client;
|
||||
// 同步旧键,保持兼容
|
||||
(global as any)[legacyKey] = client;
|
||||
}
|
||||
|
||||
return client;
|
||||
|
||||
@@ -271,8 +271,9 @@ export class UpstashRedisStorage implements IStorage {
|
||||
|
||||
// 单例 Upstash Redis 客户端
|
||||
function getUpstashRedisClient(): Redis {
|
||||
const globalKey = Symbol.for('__MOONTV_UPSTASH_REDIS_CLIENT__');
|
||||
let client: Redis | undefined = (global as any)[globalKey];
|
||||
const legacyKey = Symbol.for('__MOONTV_UPSTASH_REDIS_CLIENT__');
|
||||
const globalKey = Symbol.for('__KATELYATV_UPSTASH_REDIS_CLIENT__');
|
||||
let client: Redis | undefined = (global as any)[globalKey] || (global as any)[legacyKey];
|
||||
|
||||
if (!client) {
|
||||
const upstashUrl = process.env.UPSTASH_URL;
|
||||
@@ -299,6 +300,8 @@ function getUpstashRedisClient(): Redis {
|
||||
console.log('Upstash Redis client created successfully');
|
||||
|
||||
(global as any)[globalKey] = client;
|
||||
// 同步设置旧的全局键,保持向后兼容
|
||||
(global as any)[legacyKey] = client;
|
||||
}
|
||||
|
||||
return client;
|
||||
|
||||
+6
-2
@@ -11,11 +11,15 @@ export enum UpdateStatus {
|
||||
FETCH_FAILED = 'fetch_failed', // 获取失败
|
||||
}
|
||||
|
||||
// 远程版本检查URL配置
|
||||
// 远程版本检查URL配置(支持环境变量覆盖,并保留 MoonTV 上游作为后备)
|
||||
const ENV_PRIMARY = process.env.NEXT_PUBLIC_VERSION_URL_PRIMARY;
|
||||
const ENV_BACKUP = process.env.NEXT_PUBLIC_VERSION_URL_BACKUP;
|
||||
const VERSION_CHECK_URLS = [
|
||||
ENV_PRIMARY,
|
||||
ENV_BACKUP,
|
||||
'https://ghfast.top/raw.githubusercontent.com/senshinya/MoonTV/main/VERSION.txt',
|
||||
'https://raw.githubusercontent.com/senshinya/MoonTV/main/VERSION.txt',
|
||||
];
|
||||
].filter(Boolean) as string[];
|
||||
|
||||
/**
|
||||
* 检查是否有新版本可用
|
||||
|
||||
Reference in New Issue
Block a user