Compare commits

..

69 Commits

Author SHA1 Message Date
maye 6be5c25dfc Update config.json 2025-09-02 11:19:59 +08:00
katelya d9d50891f2 Merge branch 'main' of https://github.com/katelya77/KatelyaTV 2025-09-01 23:34:13 +08:00
katelya cd12ebea76 fixed 2025-09-01 23:34:09 +08:00
Katelya 36c9a6be20
Delete RELEASE_v0.4.0.md 2025-09-01 23:33:53 +08:00
Katelya 8c698ceb7d
Update README.md 2025-09-01 23:33:23 +08:00
katelya 419c686879 Merge branch 'main' of https://github.com/katelya77/KatelyaTV 2025-09-01 23:30:51 +08:00
katelya ec8111243a feat: 添加 RELEASE_v0.4.0 版本说明文件 2025-09-01 23:30:48 +08:00
Katelya 41ea51baae
Fix link to D1初始化.md in README 2025-09-01 23:19:49 +08:00
katelya d639bbe415 feat: 更新 README,重构部署教程,优化 Docker 部署说明和配置示例 2025-09-01 23:14:26 +08:00
katelya dc336af4da feat: 更新 README,移除视频源说明,优化部署和环境变量部分 2025-09-01 22:54:48 +08:00
katelya 3ba6e798f6 feat: 更新 README,优化项目描述和视频源说明,调整布局和功能特性 2025-09-01 22:33:58 +08:00
katelya 8da7d1153f feat: 优化 PageLayout 组件,调整 TopNavbar 的固定定位和注释说明 2025-09-01 22:06:20 +08:00
katelya 63c5e94f25 Merge branch 'main' of https://github.com/katelya77/KatelyaTV 2025-09-01 21:57:24 +08:00
katelya ab4e58dc4c feat: 更新 README 和版本管理脚本,优化 PageLayout 组件布局,添加 .eslintignore 文件 2025-09-01 21:57:20 +08:00
Katelya ea057e7c53
Delete RELEASE_v0.4.0.md 2025-09-01 21:47:56 +08:00
katelya 4d4f2ab665 feat: enhance PageLayout for better responsiveness and scrolling behavior
- Updated PageLayout component to use flexbox for improved layout structure.
- Ensured the main content area is scrollable by adjusting CSS classes.
- Modified the minimum height calculations for better visual consistency across devices.
- Added comments for clarity on layout changes and their purposes.

chore: add Workbox service worker for improved caching and offline support

- Introduced Workbox for managing caching strategies and offline capabilities.
- Implemented various caching strategies including CacheFirst and NetworkFirst.
- Added expiration and cleanup mechanisms for cached entries.
- Enhanced precaching functionality to ensure assets are available offline.
2025-09-01 21:47:05 +08:00
katelya 97f2bdae97 Merge branch 'main' of https://github.com/katelya77/KatelyaTV 2025-09-01 21:39:32 +08:00
katelya 1e0c079957 update 2025-09-01 21:39:27 +08:00
Katelya 40278e1ae1
Delete RELEASE_NOTES.md 2025-09-01 21:38:39 +08:00
Katelya 87c4020f99
Update README.md 2025-09-01 21:31:19 +08:00
Katelya e0c0fb1289
Update README.md 2025-09-01 21:30:40 +08:00
Katelya 3db16acd6c
Rename wechat.JPG to wechat.jpg 2025-09-01 21:30:03 +08:00
Katelya 0d14b089c7
Add files via upload 2025-09-01 21:28:28 +08:00
katelya 4617b0199b feat: Enhance package manager detection script and improve type safety in components
- Updated `check-package-manager.js` to disable specific ESLint rules for better readability.
- Refactored `page.tsx` in the login module to remove unnecessary type assertions and improve state management.
- Modified `page.tsx` in the home module to enhance error handling, improve layout with grid system, and limit displayed items.
- Adjusted `PageLayout.tsx` to implement responsive layout changes for the play page.
- Improved `ThemeToggle.tsx` to ensure proper dependency tracking in useEffect.
- Enhanced `VideoCard.tsx` with better type definitions for favorites.
- Updated `db.client.ts` to rename legacy cache prefix for future migration.
- Added runtime configuration types in `types.ts` and extended global Window interface.
- Introduced a new Workbox service worker file for improved caching strategies.
2025-09-01 21:23:45 +08:00
katelya be5462cbb0 终于可以自由提交了! 2025-09-01 20:40:37 +08:00
katelya af5b2f8e02 移除烦人的版本自动生成,简化提交流程 2025-09-01 20:38:46 +08:00
Katelya 8b2ca1e520
Update README with important video source notice 2025-09-01 13:29:53 +08:00
Katelya ff6a32f371
Update config.json with example API sources 2025-09-01 13:02:22 +08:00
Katelya 702daca788
Update README.md 2025-08-31 22:14:56 +08:00
Katelya d21df45d16
upload screenshot files 2025-08-31 22:12:48 +08:00
Katelya 21ae5b77a8
Delete public/screenshot1.png 2025-08-31 22:08:59 +08:00
Katelya 93af4f97e8
Delete public/screenshot3.png 2025-08-31 22:08:51 +08:00
Katelya b8d09f5220
Delete public/screenshot2.png 2025-08-31 22:08:42 +08:00
Katelya c246350698
Delete public/screenshot.png 2025-08-31 22:08:29 +08:00
Katelya 45d7ff34c7
Update release.yml 2025-08-31 18:47:15 +08:00
Katelya 1134b3a9ad
Delete QUICKSTART.md 2025-08-31 18:46:07 +08:00
Katelya dfc6098913
Delete GITHUB_ACTIONS_FIX.md 2025-08-31 18:45:47 +08:00
Katelya 146ed3d7b5
Delete DOCKER_DEPLOYMENT.md 2025-08-31 18:45:30 +08:00
Katelya a4fd8a78d5
Delete CHANGELOG.md 2025-08-31 18:44:21 +08:00
Katelya 82c1606a37
Delete BUGFIXES.md 2025-08-31 18:44:08 +08:00
Katelya 55a3a13659
Delete RELEASE_NOTES_V0.2.0.md 2025-08-31 18:43:32 +08:00
Katelya 298aa98318
Update README.md 2025-08-31 18:22:48 +08:00
Katelya 11b675486b
Update docker-image.yml 2025-08-31 18:01:03 +08:00
Katelya 78ce9d2371
Update docker-image.yml 2025-08-31 16:02:07 +08:00
Katelya 3007705693
Update docker-image.yml 2025-08-31 15:56:26 +08:00
Katelya c6f1368298
Update docker-image.yml 2025-08-31 15:46:15 +08:00
Katelya a371fcf53d
Update docker-image.yml 2025-08-31 15:40:19 +08:00
Katelya ea12d9ffae
Update UserMenu.tsx 2025-08-31 15:38:54 +08:00
Katelya c7bdf33c77
Update version.ts 2025-08-31 15:38:16 +08:00
Katelya 5e1b92fe88
Update docker-image.yml 2025-08-31 15:32:28 +08:00
Katelya aee8a2a59c
Update docker-image.yml 2025-08-31 15:25:12 +08:00
Katelya ae2a08e79c
Update docker-image.yml 2025-08-31 15:10:10 +08:00
Katelya 3fbab6c512
Update docker-image.yml 2025-08-31 15:06:16 +08:00
Katelya 8be43f46e8
Update docker-image.yml 2025-08-31 15:01:21 +08:00
Katelya d1afde8406
Update docker-build.yml 2025-08-31 14:50:12 +08:00
katelya 438869f1ec update 2025-08-31 14:43:47 +08:00
katelya 0f89112e14 update 2025-08-31 14:39:46 +08:00
Katelya 2c3b7efda4
Update sw.js 2025-08-31 00:43:19 +08:00
Katelya 594fdd60ac
explain v0.2.0 2025-08-31 00:37:16 +08:00
Katelya 61d61f57f4
Merge pull request #9 from katelya77/cursor/update-documentation-and-release-notes-fb3a
fix: update Docker deployment instructions to use correct KatelyaTV i…
2025-08-31 00:36:41 +08:00
Katelya 93106cbf3b
Merge branch 'main' into cursor/update-documentation-and-release-notes-fb3a 2025-08-31 00:36:34 +08:00
Cursor Agent 0782e7f94f feat: update packages and add comprehensive Docker deployment guide
- Update VERSION.txt to trigger fresh Docker build
- Add detailed DOCKER_DEPLOYMENT.md with complete deployment guide
- Include troubleshooting, security recommendations, and performance tips
- Ensure users can successfully pull from ghcr.io/katelya77/katelyatv:latest
- Support both single container and Docker Compose deployments
2025-08-30 16:00:31 +00:00
katelya 42c5f445be Fix Docker method 2025-08-30 23:53:34 +08:00
Cursor Agent edb9857e4a fix: update Docker deployment instructions to use correct KatelyaTV image
- Fix Docker image paths in README.md, QUICKSTART.md, and RELEASE_NOTES.md
- Update from ghcr.io/senshinya/moontv:latest to ghcr.io/katelya77/katelyatv:latest
- Ensure all Docker Compose examples use correct image
- Verify build compatibility and deployment instructions
- Add comprehensive v0.2.0 release notes with deployment guide
2025-08-30 15:44:42 +00:00
Katelya ac3a42d0e3
Update README.md 2025-08-29 21:11:07 +08:00
Katelya b25c738dbf
Merge pull request #6 from katelya77/cursor/update-documentation-and-release-notes-fb3a
Update documentation and release notes
2025-08-29 16:04:40 +08:00
Cursor Agent 7f73c00e0a Update repo URL, Redis client key, and add environment variable support
Co-authored-by: 20250410303 <20250410303@stu.fosu.edu.cn>
2025-08-29 07:59:44 +00:00
Katelya dd2edc48b3
Update README.md 2025-08-29 15:51:26 +08:00
Katelya 9bfbf2d11d
Merge pull request #5 from katelya77/cursor/update-documentation-and-release-notes-fb3a
Rebrand project to KatelyaTV, update docs and release notes
2025-08-29 15:47:06 +08:00
34 changed files with 1046 additions and 972 deletions

53
.eslintignore Normal file
View File

@ -0,0 +1,53 @@
# Dependencies
node_modules/
.pnpm-store/
# Build outputs
.next/
out/
dist/
build/
# Cache directories
.cache/
.parcel-cache/
# Environment files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Log files
*.log
logs/
# Editor directories and files
.vscode/
.idea/
*.swp
*.swo
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# PWA Service Worker files (auto-generated)
public/sw.js
public/workbox-*.js
# Generated files
src/lib/runtime.ts
manifest.json
# Test coverage
coverage/
# Storybook build outputs
storybook-static/

View File

@ -61,8 +61,8 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/${{ github.repository_owner }}/moontv:latest
ghcr.io/${{ github.repository_owner }}/moontv:${{ github.sha }}
ghcr.io/${{ github.repository_owner }}/katelyatv:latest
ghcr.io/${{ github.repository_owner }}/katelyatv:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
@ -81,4 +81,4 @@ jobs:
echo "🚀 Images pushed to GitHub Container Registry"
else
echo "🧪 Build test completed (no push for PR/non-main branch)"
fi
fi

View File

@ -1,5 +1,4 @@
name: Build & Push Docker image
on:
push:
branches:
@ -12,15 +11,11 @@ on:
paths-ignore:
- '**.md'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
@ -29,24 +24,22 @@ jobs:
packages: write
attestations: write
id-token: write
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set image name to lowercase
run: echo "IMAGE_NAME=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
version: latest
driver-opts: image=moby/buildkit:buildx-stable-1
- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
@ -54,7 +47,6 @@ jobs:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
@ -67,14 +59,13 @@ jobs:
type=raw,value=latest,enable={{is_default_branch}}
labels: |
org.opencontainers.image.title=${{ github.repository }}
org.opencontainers.image.description=KatelyaTV - A modern streaming platform
org.opencontainers.image.description=katelyatv - A modern streaming platform
org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.version=${{ steps.meta.outputs.version }}
org.opencontainers.image.created=${{ steps.meta.outputs.created }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.licenses=MIT
- name: Build Docker image
id: build
uses: docker/build-push-action@v5
@ -87,14 +78,14 @@ jobs:
cache-to: type=gha,mode=max,scope=${{ github.ref_name }}-${{ matrix.platform }}
outputs: |
type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
provenance: false
sbom: false
- name: Export digest
if: github.event_name != 'pull_request'
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
@ -103,7 +94,6 @@ jobs:
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge-images:
runs-on: ubuntu-latest
permissions:
@ -114,25 +104,23 @@ jobs:
needs:
- build-and-push
if: github.event_name != 'pull_request'
steps:
- name: Set image name to lowercase
run: echo "IMAGE_NAME=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
@ -142,21 +130,32 @@ jobs:
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
- name: Get multi-arch digest
id: get_digest
run: |
# 直接从 docker pull 获取 digest这是最可靠的方法
digest=$(docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} 2>&1 | grep "Digest:" | cut -d' ' -f2 || echo "")
if [ -z "$digest" ]; then
# 备选方案:使用 crane 风格的检查(如果支持的话)
digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} | grep "Digest:" | head -1 | cut -d' ' -f2 || echo "")
fi
if [ -z "$digest" ]; then
# 最后备选:从 raw manifest 计算
digest=$(docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }} --raw | sha256sum | awk '{print "sha256:"$1}')
fi
echo "digest=$digest" >> $GITHUB_OUTPUT
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
- name: Generate artifact attestation
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
subject-digest: ${{ steps.get_digest.outputs.digest }}
push-to-registry: true

View File

@ -25,12 +25,28 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
# 修改这里:改为 pnpm 或者移除 cache 配置
# cache: 'npm' # 删除这行,因为使用的是 pnpm
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
# 添加 pnpm 缓存配置
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
@ -273,4 +289,4 @@ jobs:
echo "🎉 Release ${{ github.ref_name }} 发布成功!"
echo "📦 Docker 镜像: ghcr.io/senshinya/moontv:${{ github.ref_name }}"
echo "🔗 Release 页面: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}"
echo "📝 更新日志: https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md"
echo "📝 更新日志: https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md"

View File

@ -1,4 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit "$1"
# 禁用commitlint检查让提交更自由
echo "✅ 提交消息检查已跳过"

View File

@ -1,11 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# 生成版本号
pnpm gen:version
# 自动添加修改的版本文件
git add src/lib/version.ts
git add VERSION.txt
npx lint-staged
# 简化版 - 只做最基本的检查,不阻塞提交
echo "✅ 提交检查通过,代码已暂存"

View File

@ -1,143 +0,0 @@
# Bug修复说明
## 修复的问题
### 1. GitHub Actions构建失败问题
**问题描述:**
- ARM64平台构建失败`linux/arm64, ubuntu-24.04-arm` 构建失败
- 权限错误:`permission_denied: write_package`
- 只有AMD64平台构建成功
**根本原因:**
1. GitHub Actions权限配置过高导致权限冲突
2. ARM64平台使用特定的Ubuntu版本可能存在兼容性问题
3. Docker构建缓存未启用影响构建效率
**解决方案:**
1. 调整GitHub Actions权限
- `contents: write``contents: read`
- `actions: write``actions: read`
- 保留 `packages: write` 用于推送镜像
2. 统一使用 `ubuntu-latest` 平台:
- 移除 `ubuntu-24.04-arm` 特殊配置
- 确保ARM64和AMD64使用相同的操作系统版本
3. 启用Docker构建缓存
- 添加 `cache-from: type=gha`
- 添加 `cache-to: type=gha,mode=max`
4. 优化Dockerfile
- 添加 `--platform=$BUILDPLATFORM` 确保跨平台构建兼容性
### 2. iOS Safari渲染问题
**问题描述:**
- 登录界面在iOS Safari上无法正常显示
- 只显示特效背景,缺少登录表单
- 复杂的CSS动画可能导致性能问题
**根本原因:**
1. 复杂的CSS动画和特效在iOS Safari上支持有限
2. 使用了过多的3D变换和复杂动画
3. backdrop-filter等CSS属性在iOS Safari上可能有问题
4. 缺少针对移动端的优化
**解决方案:**
1. 简化CSS特效
- 移除复杂的3D变换动画
- 简化粒子效果动画
- 保留基本的渐变和悬停效果
2. 创建iOS Safari兼容性组件
- 自动检测iOS Safari环境
- 动态应用兼容性样式
- 禁用可能导致问题的CSS属性
3. 优化移动端体验:
- 简化背景装饰元素
- 使用更兼容的CSS属性
- 添加响应式设计优化
4. 添加CSS兼容性检测
- 使用 `@supports` 检测特性支持
- 为iOS Safari提供降级方案
- 保持美观的同时确保功能正常
## 修复后的改进
### 1. 构建稳定性
- ✅ ARM64和AMD64平台都能成功构建
- ✅ 启用构建缓存,提高构建效率
- ✅ 权限配置更加合理和安全
### 2. 移动端兼容性
- ✅ iOS Safari登录界面正常显示
- ✅ 保持美观的UI设计
- ✅ 优化移动端性能
- ✅ 自动检测和适配不同设备
### 3. 代码质量
- ✅ 修复所有ESLint错误
- ✅ 代码格式化和导入排序
- ✅ 类型检查通过
- ✅ 构建过程无错误
## 技术细节
### GitHub Actions配置
```yaml
permissions:
contents: read # 降低权限,避免冲突
packages: write # 保留推送镜像权限
actions: read # 降低权限,避免冲突
```
### Dockerfile优化
```dockerfile
FROM --platform=$BUILDPLATFORM node:20-alpine AS deps
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
```
### iOS兼容性检测
```typescript
const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
const safari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
```
### CSS兼容性优化
```css
@supports (-webkit-touch-callout: none) {
/* iOS Safari特定样式 */
.animate-pulse { animation: none; }
.particle { animation: none; opacity: 0.4; }
}
```
## 测试建议
1. **GitHub Actions测试**
- 推送代码到main分支
- 检查ARM64和AMD64构建是否都成功
- 验证镜像推送是否正常
2. **移动端测试:**
- 在iOS Safari上测试登录界面
- 验证所有UI元素正常显示
- 检查动画效果是否流畅
3. **本地构建测试:**
- 运行 `pnpm run build` 确保无错误
- 运行 `pnpm run lint:fix` 检查代码质量
- 运行 `pnpm run dev` 测试开发环境
## 注意事项
1. **权限配置:** 如果仍有权限问题可能需要检查GitHub仓库的Settings > Actions > General中的权限设置
2. **iOS兼容性** 如果发现新的兼容性问题,可以在`IOSCompatibility.tsx`组件中添加相应的样式规则
3. **性能监控:** 建议在生产环境中监控移动端的性能表现,确保用户体验良好
4. **浏览器支持:** 考虑添加更多浏览器的兼容性检测和优化

View File

@ -1,94 +0,0 @@
# 更新日志
本文档记录了 KatelyaTV 项目的所有重要更改。KatelyaTV 为在「MoonTV」基础上的二创与继承版本延续上游核心能力并持续修复优化。
## [未发布]
### 计划中
- 弹幕系统支持
- 字幕文件支持
- 下载功能
- 社交分享功能
- 用户评分系统
## [0.1.0-katelya] - 2025-01-XX
### ✨ 新功能
- 🎬 多源聚合搜索系统集成20+个免费资源站点
- 📺 观看历史记录功能,支持断点续播和多设备同步
- ❤️ 收藏系统,支持个性化片单管理
- 👥 多用户系统,支持用户注册、登录和权限管理
- 🌗 深色模式支持,自动跟随系统主题切换
- 📱 PWA 支持,可安装到桌面,支持离线缓存
- 🎯 豆瓣集成,提供热门电影、电视剧、综艺推荐
- 🔍 智能搜索,支持分类筛选和结果去重
### 🎨 用户界面
- 响应式设计,完美适配桌面和移动端
- 现代化 UI 设计,基于 Tailwind CSS 构建
- 流畅的动画效果,使用 Framer Motion
- 移动端底部导航栏,优化触摸操作体验
- 视频卡片进度条显示,直观展示观看进度
### 🚀 技术特性
- 基于 Next.js 14 App Router 构建
- TypeScript 4.x 类型安全
- 多种存储后端支持localStorage、Redis、Cloudflare D1、Upstash
- 视频播放器集成ArtPlayer + HLS.js
- 自动广告跳过功能
- 智能缓存策略
### 🔧 性能优化
- 接口缓存机制,减少重复请求
- 图片懒加载和占位符
- 代码分割和动态导入
- 数据库查询优化
### 📱 移动端优化
- 触摸友好的操作界面
- 移动端专用底部导航
- 响应式图片和布局
- 触摸手势支持
### 🐛 问题修复
- 修复播放进度记录丢失问题
- 优化视频播放器兼容性
- 修复移动端响应式布局问题
- 改进错误处理和用户提示
### 📚 文档
- 完整的 README.md 文档
- 详细的部署指南
- 环境变量配置说明
- Docker 部署最佳实践
## 部署说明
### 支持的平台
- ✅ Docker推荐
- ✅ Vercel
- ✅ Cloudflare Pages
- ✅ 自托管服务器
### 存储后端
- ✅ localStorage默认单用户
- ✅ Redis多用户数据同步
- ✅ Cloudflare D1多用户数据同步
- ✅ Upstash Redis多用户数据同步
### 环境要求
- Node.js 18+
- pnpm 8+
- 现代浏览器支持
## 贡献指南
我们欢迎所有形式的贡献!请查看 [CONTRIBUTING.md](CONTRIBUTING.md) 了解如何参与项目开发。
## 许可证
本项目采用 [MIT 许可证](LICENSE)。
---
**注意**: 本项目仅供学习和个人使用,请遵守当地法律法规,不要用于商业用途或公开服务。

View File

@ -1,110 +0,0 @@
# GitHub Actions 权限问题修复方案
## 🚨 问题分析
根据您的GitHub Actions失败日志主要问题包括
1. **权限拒绝错误**: `permission_denied: write_package`
2. **资源访问错误**: `Resource not accessible by integration`
3. **策略配置取消**: `The strategy configuration was canceled`
## 🔧 修复方案
### 1. 仓库权限设置检查
请确认以下设置:
#### GitHub仓库设置 → Actions → General
1. 进入您的仓库: https://github.com/katelya77/KatelyaTV/settings/actions
2. 在 "Workflow permissions" 部分,选择 **"Read and write permissions"**
3. 勾选 **"Allow GitHub Actions to create and approve pull requests"**
#### GitHub仓库设置 → Packages
1. 进入: https://github.com/katelya77/KatelyaTV/settings/packages
2. 确保 "Package creation" 设置允许创建包
### 2. 工作流程修复
我已经创建了三个修复版本:
#### 版本1: 完整修复版 (`docker-image.yml`)
- 修复了权限设置
- 移除了有问题的cleanup job
- 优化了多平台构建流程
#### 版本2: 简化版 (`docker-build.yml`)
- 简化的构建流程
- 更好的错误处理
- 测试优先的方法
### 3. 具体修复内容
1. **权限优化**:
```yaml
permissions:
contents: read
packages: write
attestations: write
id-token: write
```
2. **移除问题组件**:
- 删除了导致权限错误的cleanup job
- 简化了digest处理流程
3. **构建流程优化**:
- 改进了多平台构建策略
- 添加了更好的缓存机制
- 优化了错误处理
## 🎯 推荐操作步骤
### 立即操作
1. **检查仓库权限设置** (最重要!)
- 访问: https://github.com/katelya77/KatelyaTV/settings/actions
- 设置为 "Read and write permissions"
2. **测试新的工作流程**
- 新的 `docker-image.yml` 已经推送
- 等待下次推送触发自动构建
### 如果仍有问题
1. **使用简化版本**:
```bash
git add .github/workflows/docker-build.yml
git commit -m "Add simplified Docker build workflow"
git push origin main
```
2. **手动创建Personal Access Token** (备用方案):
- 访问: https://github.com/settings/tokens
- 创建token权限包括: `write:packages`, `read:packages`
- 添加到仓库Secrets: `PAT_TOKEN`
- 修改workflow使用PAT而不是GITHUB_TOKEN
## 🔍 预期结果
修复后,您应该看到:
- ✅ ARM64和AMD64平台都成功构建
- ✅ 没有权限错误
- ✅ Docker镜像成功推送到ghcr.io
- ✅ 绿色的GitHub Actions状态
## 🆘 如果问题持续
如果上述方案都不能解决问题,可能需要:
1. **联系GitHub支持**: 可能是账户级别的权限限制
2. **使用替代方案**: 切换到Docker Hub或其他容器注册中心
3. **简化构建**: 暂时只构建单平台镜像
## 📞 技术支持
如果您需要进一步的帮助,请提供:
- 新的GitHub Actions运行URL
- 仓库权限设置的截图
- 详细的错误日志
祝您早日解决这个强迫症问题!🎉

View File

@ -1,242 +0,0 @@
# 🚀 KatelyaTV 快速开始指南
欢迎使用 KatelyaTV本指南将帮助您在几分钟内完成部署和配置。
## 📋 前置要求
- **Docker** (推荐) 或 **Node.js 18+**
- 现代浏览器 (Chrome 90+, Firefox 88+, Safari 14+)
- 稳定的网络连接
## 🐳 Docker 部署 (推荐)
### 1. 快速启动
```bash
# 拉取最新镜像(当前镜像沿用上游命名空间)
docker pull ghcr.io/senshinya/moontv:latest
# 启动容器
docker run -d \
--name katelyatv \
-p 3000:3000 \
--env PASSWORD=your_password \
--restart unless-stopped \
ghcr.io/senshinya/moontv:latest
```
### 2. 访问应用
打开浏览器访问 `http://localhost:3000`,输入密码 `your_password` 即可使用。
### 3. 停止服务
```bash
# 停止容器
docker stop katelyatv
# 删除容器
docker rm katelyatv
```
## 🌐 云平台部署
### Vercel 部署
1. **Fork 项目**
- 点击 GitHub 仓库右上角的 "Fork" 按钮
- 等待 Fork 完成
2. **部署到 Vercel**
- 访问 [Vercel](https://vercel.com/)
- 点击 "New Project"
- 选择 Fork 后的仓库
- 设置环境变量 `PASSWORD=your_password`
- 点击 "Deploy"
3. **访问应用**
- 部署完成后Vercel 会提供一个域名
- 访问该域名,输入密码即可使用
### Cloudflare Pages 部署
1. **Fork 项目**
- 同上
2. **部署到 Cloudflare Pages**
- 访问 [Cloudflare Dashboard](https://dash.cloudflare.com/)
- 进入 "Workers & Pages"
- 点击 "Create application" → "Pages"
- 选择 "Connect to Git"
- 选择 Fork 后的仓库
- 构建命令:`pnpm run pages:build`
- 构建输出目录:`.vercel/output/static`
- 环境变量:`PASSWORD=your_password`
3. **访问应用**
- 部署完成后访问提供的域名
## ⚙️ 基础配置
### 环境变量
创建 `.env.local` 文件:
```bash
# 复制示例文件
cp .env.example .env.local
# 编辑配置
nano .env.local
```
**必需配置:**
```bash
PASSWORD=your_secure_password
```
**推荐配置:**
```bash
SITE_NAME=我的影视站
NEXT_PUBLIC_STORAGE_TYPE=localstorage
NEXT_PUBLIC_SEARCH_MAX_PAGE=10
```
### 自定义资源站点
编辑 `config.json` 文件:
```json
{
"cache_time": 7200,
"api_site": {
"dyttzy": {
"api": "http://caiji.dyttzyapi.com/api.php/provide/vod",
"name": "电影天堂资源",
"detail": "http://caiji.dyttzyapi.com"
}
}
}
```
## 🎯 核心功能使用
### 1. 搜索影视
- 在首页搜索框输入影视名称
- 支持中文、英文、拼音搜索
- 结果来自多个资源站点
### 2. 观看视频
- 点击搜索结果进入详情页
- 选择播放源和剧集
- 支持进度记录和断点续播
### 3. 收藏管理
- 点击心形图标收藏影视
- 在"我的收藏"中查看
- 支持多设备同步
### 4. 观看历史
- 自动记录观看进度
- 在"继续观看"中查看
- 支持从上次位置继续
## 🔧 高级配置
### 多用户支持
如需支持多用户,请配置 Redis 或 D1 存储:
```bash
# Redis 配置
NEXT_PUBLIC_STORAGE_TYPE=redis
REDIS_URL=redis://localhost:6379/0
# 或 D1 配置 (Cloudflare Pages)
NEXT_PUBLIC_STORAGE_TYPE=d1
# 在 Cloudflare Pages 中绑定 D1 数据库
```
### 自定义主题
修改 `src/styles/globals.css` 文件:
```css
:root {
--primary-color: #3b82f6;
--secondary-color: #1e40af;
--background-color: #ffffff;
--text-color: #1f2937;
}
.dark {
--background-color: #111827;
--text-color: #f9fafb;
}
```
### 添加新资源站点
`config.json` 中添加:
```json
{
"api_site": {
"newsite": {
"api": "https://newsite.com/api.php/provide/vod",
"name": "新站点名称"
}
}
}
```
## 🚨 常见问题
### Q: 无法访问应用
**A:** 检查端口是否被占用,防火墙设置,或尝试其他端口。
### Q: 搜索无结果
**A:** 检查网络连接,资源站点是否可用,或尝试其他关键词。
### Q: 视频无法播放
**A:** 检查视频源是否有效,浏览器是否支持相关格式。
### Q: 数据丢失
**A:** 如果使用 localStorage数据存储在浏览器中清除缓存会丢失数据。
## 📱 移动端使用
- 支持响应式设计
- 可安装为 PWA 应用
- 触摸友好的操作界面
## 🔒 安全建议
1. **设置强密码**:使用复杂密码保护访问
2. **限制访问**:不要公开分享访问链接
3. **定期更新**:保持应用版本最新
4. **监控日志**:关注异常访问记录
## 📞 获取帮助
- 📖 [完整文档](README.md)
- 🐛 问题反馈:在仓库 Issues 页面提交
- 💬 功能讨论:在 Discussions 页面参与
- 📝 [更新日志](CHANGELOG.md)
## 🎉 开始使用
现在您已经完成了基础配置,可以开始享受 KatelyaTV 带来的影视体验了!
**重要提醒:**
- 本项目仅供学习和个人使用
- 请遵守当地法律法规
- 不要用于商业用途或公开服务
---
如有任何问题,欢迎在 GitHub 上提出 Issue 或参与讨论!

921
README.md

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +0,0 @@
# 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/senshinya/moontv:latest
# 启动示例
docker run -d --name katelyatv \
-p 3000:3000 \
--env PASSWORD=your_password \
--restart unless-stopped \
ghcr.io/senshinya/moontv:latest
```
- 或使用 README 中的 Docker Compose 示例
## 兼容性
- 保持与上游 MoonTV v0.1.0 行为一致
- 支持存储后端localStorage / Redis / Cloudflare D1 / Upstash Redis
- 运行环境Node.js 18+;容器镜像支持多架构
## 已知问题
- 部分第三方资源站可用性受其自身状态影响
- Android TV 端收藏与网页端暂未完全互通(后续版本优化)
## 后续路线
- 弹幕系统、字幕支持、下载功能、社交分享
- 数据同步与多端互通完善
- 性能与稳定性持续优化
## 鸣谢
- 原始项目 MoonTV 及其作者与社区
- 所有为本项目提供反馈、贡献代码与文档的开发者
— Katelya

View File

@ -1 +1 @@
20250928125318
20250901193125

View File

@ -86,4 +86,4 @@
"name": "小猫咪资源"
}
}
}
}

View File

@ -1,13 +1,13 @@
{
"name": "moontv",
"version": "0.1.0",
"name": "katelyatv",
"version": "0.4.0-katelya",
"private": true,
"scripts": {
"dev": "pnpm gen:runtime && pnpm gen:manifest && next dev -H 0.0.0.0",
"build": "pnpm gen:runtime && pnpm gen:manifest && next build",
"dev": "npm run gen:runtime && npm run gen:manifest && next dev -H 0.0.0.0",
"build": "npm run gen:runtime && npm run gen:manifest && next build",
"start": "next start",
"lint": "next lint",
"lint:fix": "eslint src --fix && pnpm format",
"lint:fix": "eslint src --fix && npm run format",
"lint:strict": "eslint --max-warnings=0 src",
"typecheck": "tsc --noEmit --incremental false",
"test:watch": "jest --watch",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 MiB

After

Width:  |  Height:  |  Size: 737 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
public/screenshot4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 KiB

File diff suppressed because one or more lines are too long

BIN
public/wechat.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@ -0,0 +1,84 @@
#!/usr/bin/env node
/* eslint-disable @typescript-eslint/no-var-requires, no-console */
/**
* 智能包管理器检测和推荐脚本
* 帮助用户选择最适合的包管理器
*/
const { execSync } = require('child_process');
const fs = require('fs');
console.log('🔍 检测包管理器环境...\n');
// 检测函数
function checkCommand(command) {
try {
execSync(`${command} --version`, { stdio: 'pipe' });
return true;
} catch {
return false;
}
}
function getVersion(command) {
try {
const version = execSync(`${command} --version`, { encoding: 'utf8' }).trim();
return version;
} catch {
return 'unknown';
}
}
// 检测包管理器
const hasNpm = checkCommand('npm');
const hasPnpm = checkCommand('pnpm');
const hasYarn = checkCommand('yarn');
const npmVersion = hasNpm ? getVersion('npm') : null;
const pnpmVersion = hasPnpm ? getVersion('pnpm') : null;
const yarnVersion = hasYarn ? getVersion('yarn') : null;
// 检测锁文件
const hasPnpmLock = fs.existsSync('pnpm-lock.yaml');
const hasNpmLock = fs.existsSync('package-lock.json');
const hasYarnLock = fs.existsSync('yarn.lock');
console.log('📦 包管理器检测结果:');
console.log(` npm: ${hasNpm ? '✅ ' + npmVersion : '❌ 未安装'}`);
console.log(` pnpm: ${hasPnpm ? '✅ ' + pnpmVersion : '❌ 未安装'}`);
console.log(` yarn: ${hasYarn ? '✅ ' + yarnVersion : '❌ 未安装'}`);
console.log('\n🔒 锁文件检测结果:');
console.log(` pnpm-lock.yaml: ${hasPnpmLock ? '✅ 存在' : '❌ 不存在'}`);
console.log(` package-lock.json: ${hasNpmLock ? '✅ 存在' : '❌ 不存在'}`);
console.log(` yarn.lock: ${hasYarnLock ? '✅ 存在' : '❌ 不存在'}`);
// 智能推荐
console.log('\n💡 智能推荐:');
if (hasPnpm && hasPnpmLock) {
console.log(' 🎯 推荐使用 pnpm (已安装且有锁文件)');
console.log(' 📝 运行命令: pnpm install && pnpm dev');
} else if (hasNpm && hasNpmLock) {
console.log(' 🎯 推荐使用 npm (已安装且有锁文件)');
console.log(' 📝 运行命令: npm install && npm run dev');
} else if (hasPnpm) {
console.log(' 🎯 推荐使用 pnpm (性能更好)');
console.log(' 📝 运行命令: pnpm install && pnpm dev');
} else if (hasNpm) {
console.log(' 🎯 使用 npm (已安装)');
console.log(' 📝 运行命令: npm install && npm run dev');
} else {
console.log(' ❌ 未检测到任何包管理器,请先安装 Node.js');
}
// 安装建议
if (!hasPnpm && hasNpm) {
console.log('\n🚀 pnpm 安装建议 (可选):');
console.log(' npm install -g pnpm # 通过npm安装');
console.log(' corepack enable && corepack prepare pnpm@latest --activate # 通过corepack');
}
console.log('\n✨ KatelyaTV 支持智能包管理器检测,任何包管理器都可以正常工作!');

View File

@ -1,5 +1,7 @@
#!/usr/bin/env node
/* eslint-disable @typescript-eslint/no-var-requires, no-console, unused-imports/no-unused-vars */
/**
* MoonTV 版本管理脚本
* 用于自动化版本号更新CHANGELOG 生成和发布管理
@ -13,7 +15,7 @@ const { execSync } = require('child_process');
const PACKAGE_JSON = path.join(__dirname, '../package.json');
const VERSION_TXT = path.join(__dirname, '../VERSION.txt');
const CHANGELOG_MD = path.join(__dirname, '../CHANGELOG.md');
const README_MD = path.join(__dirname, '../README.md');
const _README_MD = path.join(__dirname, '../README.md');
// 版本类型
const VERSION_TYPES = {

View File

@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client';
import { AlertCircle, CheckCircle } from 'lucide-react';
@ -35,7 +33,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'
>
@ -82,10 +83,10 @@ function LoginPageClient() {
// 在客户端挂载后设置配置
useEffect(() => {
if (typeof window !== 'undefined') {
const storageType = (window as any).RUNTIME_CONFIG?.STORAGE_TYPE;
setShouldAskUsername(storageType && storageType !== 'localstorage');
const storageType = window.RUNTIME_CONFIG?.STORAGE_TYPE;
setShouldAskUsername(Boolean(storageType && storageType !== 'localstorage'));
setEnableRegister(
Boolean((window as any).RUNTIME_CONFIG?.ENABLE_REGISTER)
Boolean(window.RUNTIME_CONFIG?.ENABLE_REGISTER)
);
}
}, []);

View File

@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any, react-hooks/exhaustive-deps, no-console */
/* eslint-disable react-hooks/exhaustive-deps */
'use client';
@ -8,6 +8,7 @@ import { Suspense, useEffect, useState } from 'react';
// 客户端收藏 API
import {
type Favorite,
clearAllFavorites,
getAllFavorites,
getAllPlayRecords,
@ -19,7 +20,6 @@ import { DoubanItem } from '@/lib/types';
import CapsuleSwitch from '@/components/CapsuleSwitch';
import ContinueWatching from '@/components/ContinueWatching';
import PageLayout from '@/components/PageLayout';
import ScrollableRow from '@/components/ScrollableRow';
import { useSite } from '@/components/SiteProvider';
import VideoCard from '@/components/VideoCard';
@ -137,7 +137,8 @@ function HomeClient() {
setHotVarietyShows(varietyShowsData.list);
}
} catch (error) {
console.error('获取豆瓣数据失败:', error);
// 静默处理错误,避免控制台警告
// console.error('获取豆瓣数据失败:', error);
} finally {
setLoading(false);
}
@ -147,7 +148,7 @@ function HomeClient() {
}, []);
// 处理收藏数据更新的函数
const updateFavoriteItems = async (allFavorites: Record<string, any>) => {
const updateFavoriteItems = async (allFavorites: Record<string, Favorite>) => {
const allPlayRecords = await getAllPlayRecords();
// 根据保存时间排序(从近到远)
@ -191,7 +192,7 @@ function HomeClient() {
// 监听收藏更新事件
const unsubscribe = subscribeToDataUpdates(
'favoritesUpdated',
(newFavorites: Record<string, any>) => {
(newFavorites: Record<string, Favorite>) => {
updateFavoriteItems(newFavorites);
}
);
@ -290,13 +291,13 @@ function HomeClient() {
<ChevronRight className='w-4 h-4 ml-1' />
</Link>
</div>
<ScrollableRow>
<div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4'>
{loading
? // 加载状态显示灰色占位数据
Array.from({ length: 8 }).map((_, index) => (
? // 加载状态显示灰色占位数据 (显示10个2行x5列)
Array.from({ length: 10 }).map((_, index) => (
<div
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
className='w-full'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-purple-200 animate-pulse dark:bg-purple-800'>
<div className='absolute inset-0 bg-purple-300 dark:bg-purple-700'></div>
@ -304,11 +305,11 @@ function HomeClient() {
<div className='mt-2 h-4 bg-purple-200 rounded animate-pulse dark:bg-purple-800'></div>
</div>
))
: // 显示真实数据
hotMovies.map((movie, index) => (
: // 显示真实数据只显示前10个实现2行布局
hotMovies.slice(0, 10).map((movie, index) => (
<div
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
className='w-full'
>
<VideoCard
from='douban'
@ -321,7 +322,7 @@ function HomeClient() {
/>
</div>
))}
</ScrollableRow>
</div>
</section>
{/* 热门剧集 */}
@ -338,13 +339,13 @@ function HomeClient() {
<ChevronRight className='w-4 h-4 ml-1' />
</Link>
</div>
<ScrollableRow>
<div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4'>
{loading
? // 加载状态显示灰色占位数据
Array.from({ length: 8 }).map((_, index) => (
? // 加载状态显示灰色占位数据 (显示10个2行x5列)
Array.from({ length: 10 }).map((_, index) => (
<div
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
className='w-full'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-purple-200 animate-pulse dark:bg-purple-800'>
<div className='absolute inset-0 bg-purple-300 dark:bg-purple-700'></div>
@ -352,11 +353,11 @@ function HomeClient() {
<div className='mt-2 h-4 bg-purple-200 rounded animate-pulse dark:bg-purple-800'></div>
</div>
))
: // 显示真实数据
hotTvShows.map((show, index) => (
: // 显示真实数据只显示前10个实现2行布局
hotTvShows.slice(0, 10).map((show, index) => (
<div
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
className='w-full'
>
<VideoCard
from='douban'
@ -368,7 +369,7 @@ function HomeClient() {
/>
</div>
))}
</ScrollableRow>
</div>
</section>
{/* 热门综艺 */}
@ -385,13 +386,13 @@ function HomeClient() {
<ChevronRight className='w-4 h-4 ml-1' />
</Link>
</div>
<ScrollableRow>
<div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4'>
{loading
? // 加载状态显示灰色占位数据
Array.from({ length: 8 }).map((_, index) => (
? // 加载状态显示灰色占位数据 (显示10个2行x5列)
Array.from({ length: 10 }).map((_, index) => (
<div
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
className='w-full'
>
<div className='relative aspect-[2/3] w-full overflow-hidden rounded-lg bg-purple-200 animate-pulse dark:bg-purple-800'>
<div className='absolute inset-0 bg-purple-300 dark:bg-purple-700'></div>
@ -399,11 +400,11 @@ function HomeClient() {
<div className='mt-2 h-4 bg-purple-200 rounded animate-pulse dark:bg-purple-800'></div>
</div>
))
: // 显示真实数据
hotVarietyShows.map((show, index) => (
: // 显示真实数据只显示前10个实现2行布局
hotVarietyShows.slice(0, 10).map((show, index) => (
<div
key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
className='w-full'
>
<VideoCard
from='douban'
@ -415,7 +416,7 @@ function HomeClient() {
/>
</div>
))}
</ScrollableRow>
</div>
</section>
{/* 首页底部 Logo */}

View File

@ -71,8 +71,10 @@ const TopNavbar = ({ activePath = '/' }: { activePath?: string }) => {
},
];
// 桌面端顶部固定导航fixed
// 移动端:不显示此组件,改由底部导航 + 轻量顶部条(非固定)
return (
<nav className='w-full bg-white/40 backdrop-blur-xl border-b border-purple-200/50 shadow-lg dark:bg-gray-900/70 dark:border-purple-700/50 sticky top-0 z-50'>
<nav className='w-full bg-white/40 backdrop-blur-xl border-b border-purple-200/50 shadow-lg dark:bg-gray-900/70 dark:border-purple-700/50 fixed top-0 left-0 right-0 z-40 hidden md:block'>
<div className='w-full px-8 lg:px-12 xl:px-16'>
<div className='flex items-center justify-between h-16'>
{/* Logo区域 - 调整为更靠左 */}
@ -164,58 +166,59 @@ const TopNavbar = ({ activePath = '/' }: { activePath?: string }) => {
const PageLayout = ({ children, activePath = '/' }: PageLayoutProps) => {
return (
<div className='w-full min-h-screen'>
{/* 移动端头部 */}
{/* 移动端头部 (fixed) */}
<MobileHeader showBackButton={['/play'].includes(activePath)} />
{/* 桌面端顶部导航栏 */}
<div className='hidden md:block'>
<TopNavbar activePath={activePath} />
</div>
{/* 桌面端顶部导航栏 (fixed) */}
<TopNavbar activePath={activePath} />
{/* 主要布局容器 */}
<div className='w-full min-h-screen md:min-h-auto'>
{/* 主内容区域 */}
<div className='relative min-w-0 flex-1 transition-all duration-300'>
{/* 桌面端左上角返回按钮 */}
{['/play'].includes(activePath) && (
<div className='absolute top-3 left-1 z-20 hidden md:flex'>
<BackButton />
</div>
)}
{/* 主内容区域 - 预留桌面端顶部导航高度 64px */}
<div className='relative min-w-0 transition-all duration-300 md:pt-16'>
{/* 桌面端左上角返回按钮 */}
{['/play'].includes(activePath) && (
<div className='absolute top-3 left-1 z-20 hidden md:flex'>
<BackButton />
</div>
)}
{/* 主内容容器 - 修改布局实现完全居中左右各留白1/6主内容区占2/3 */}
<main className='flex-1 md:min-h-0 mb-14 md:mb-0 md:p-6 lg:p-8'>
{/* 使用flex布局实现三等分 */}
<div className='flex w-full min-h-screen md:min-h-[calc(100vh-10rem)]'>
{/* 左侧留白区域 - 占1/6 */}
{/* 主内容容器 - 为播放页面使用特殊布局83.33%宽度其他页面使用默认布局66.67%宽度) */}
<main className='mb-14 md:mb-0 md:p-6 lg:p-8'>
{/* 使用flex布局实现宽度控制 */}
<div className='flex w-full min-h-[calc(100vh-4rem)]'>
{/* 左侧留白区域 - 播放页面占8.33%其他页面占16.67% */}
<div
className='hidden md:block flex-shrink-0'
style={{
width: ['/play'].includes(activePath) ? '8.33%' : '16.67%'
}}
></div>
{/* 主内容区 - 播放页面占83.33%其他页面占66.67% */}
<div
className='flex-1 md:flex-none rounded-container w-full'
style={{
width: ['/play'].includes(activePath) ? '83.33%' : '66.67%'
}}
>
<div
className='hidden md:block flex-shrink-0'
style={{ width: '16.67%' }}
></div>
{/* 主内容区 - 占2/3 */}
<div
className='flex-1 md:flex-none rounded-container w-full'
style={{ width: '66.67%' }}
className='p-4 md:p-8 lg:p-10'
style={{
paddingBottom: 'calc(3.5rem + env(safe-area-inset-bottom))',
}}
>
<div
className='p-4 md:p-8 lg:p-10'
style={{
paddingBottom: 'calc(3.5rem + env(safe-area-inset-bottom))',
}}
>
{children}
</div>
{children}
</div>
{/* 右侧留白区域 - 占1/6 */}
<div
className='hidden md:block flex-shrink-0'
style={{ width: '16.67%' }}
></div>
</div>
</main>
</div>
{/* 右侧留白区域 - 播放页面占8.33%其他页面占16.67% */}
<div
className='hidden md:block flex-shrink-0'
style={{
width: ['/play'].includes(activePath) ? '8.33%' : '16.67%'
}}
></div>
</div>
</main>
</div>
{/* 移动端底部导航 */}

View File

@ -1,5 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any,react-hooks/exhaustive-deps */
'use client';
import { Moon, Sun } from 'lucide-react';
@ -25,7 +23,7 @@ export function ThemeToggle() {
useEffect(() => {
setMounted(true);
setThemeColor(resolvedTheme);
}, []);
}, [resolvedTheme]);
if (!mounted) {
// 渲染一个占位符以避免布局偏移
@ -36,12 +34,18 @@ export function ThemeToggle() {
// 检查浏览器是否支持 View Transitions API
const targetTheme = resolvedTheme === 'dark' ? 'light' : 'dark';
setThemeColor(targetTheme);
if (!(document as any).startViewTransition) {
// 使用更好的类型定义
const documentWithTransition = document as Document & {
startViewTransition?: (callback: () => void) => void;
};
if (!documentWithTransition.startViewTransition) {
setTheme(targetTheme);
return;
}
(document as any).startViewTransition(() => {
documentWithTransition.startViewTransition(() => {
setTheme(targetTheme);
});
};

View File

@ -403,7 +403,7 @@ export const UserMenu: React.FC = () => {
{/* 版本信息 */}
<button
onClick={() =>
window.open('https://github.com/senshinya/MoonTV', '_blank')
window.open('https://github.com/katelya77/KatelyaTV', '_blank')
}
className='w-full px-3 py-2 text-center flex items-center justify-center text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors text-xs'
>

View File

@ -1,11 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CheckCircle, Heart, Link, PlayCircleIcon } from 'lucide-react';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
type Favorite,
deleteFavorite,
deletePlayRecord,
generateStorageKey,
@ -131,7 +130,7 @@ export default function VideoCard({
const storageKey = generateStorageKey(actualSource, actualId);
const unsubscribe = subscribeToDataUpdates(
'favoritesUpdated',
(newFavorites: Record<string, any>) => {
(newFavorites: Record<string, Favorite>) => {
// 检查当前项目是否在新的收藏列表中
const isNowFavorited = !!newFavorites[storageKey];
setFavorited(isNowFavorited);

View File

@ -65,7 +65,7 @@ const LEGACY_SEARCH_HISTORY_KEY = 'moontv_search_history';
// 缓存相关常量
const CACHE_PREFIX = 'katelyatv_cache_';
const LEGACY_CACHE_PREFIX = 'moontv_cache_';
const _LEGACY_CACHE_PREFIX = 'moontv_cache_'; // 保留用于将来的迁移功能
const CACHE_VERSION = '1.0.0';
const CACHE_EXPIRE_TIME = 60 * 60 * 1000; // 一小时缓存过期

View File

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

View File

@ -95,3 +95,18 @@ export interface DoubanResult {
message: string;
list: DoubanItem[];
}
// Runtime配置类型
export interface RuntimeConfig {
STORAGE_TYPE?: string;
ENABLE_REGISTER?: boolean;
IMAGE_PROXY?: string;
DOUBAN_PROXY?: string;
}
// 全局Window类型扩展
declare global {
interface Window {
RUNTIME_CONFIG?: RuntimeConfig;
}
}

View File

@ -2,7 +2,7 @@
'use client';
const CURRENT_VERSION = '20250928125318';
const CURRENT_VERSION = '20250831153112';
// 版本检查结果枚举
export enum UpdateStatus {