diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f9a7a32 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,139 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## 项目概述 + +这是一个基于 Laravel 8 框架的视频评论和弹幕查询系统,主要功能包括: +- 视频评论查询和搜索 +- 节目管理和视频关联 +- 弹幕数据管理(支持B站、西瓜视频、抖音) +- WebAuthn 身份验证 +- 文件上传和管理 + +## 常用开发命令 + +### 后端 PHP/Laravel 命令 +```bash +# 安装 PHP 依赖 +composer install + +# 开发环境安装(包含开发依赖) +composer install + +# 生产环境安装(不含开发依赖) +composer install --optimize-autoloader --no-dev + +# 运行测试 +vendor/bin/phpunit +# 或 +php artisan test + +# 清除缓存 +php artisan cache:clear +php artisan config:clear +php artisan route:clear +php artisan view:clear + +# 生成应用密钥 +php artisan key:generate + +# 数据库迁移 +php artisan migrate + +# 启动开发服务器 +php artisan serve +``` + +### 前端构建命令 +```bash +# 安装前端依赖 +yarn install +# 或 +npm install + +# 开发模式构建 +yarn dev +# 或 +npm run dev + +# 监听文件变化并自动重新构建 +yarn watch +# 或 +npm run watch + +# 生产环境构建 +yarn production +# 或 +npm run production +``` + +### 生产环境部署 +使用 `build.sh` 脚本进行完整的生产环境构建: +```bash +./build.sh +``` +该脚本会依次执行: +1. 安装 PHP 依赖(生产环境) +2. 安装前端依赖 +3. 构建前端资源 +4. 缓存配置、路由和视图 + +## 核心架构 + +### 数据模型关系 +- `Videos`: 视频主表,以 bvid 为主键 +- `VideoComments`: 视频评论,关联到 Videos +- `VideoDanmakus`: 视频弹幕,支持多平台(B站、西瓜、抖音) +- `Programs`: 节目表 +- `ProgramVideos`: 节目与视频的多对多关联表 +- `ProgramAppends`: 节目的点播内容 +- `User`: 用户表,支持传统登录和 WebAuthn + +### 控制器架构 +#### 查询控制器(公开访问) +- `CommentQueryController`: 评论搜索,支持关键词分词搜索 +- `VideoQueryController`: 视频信息查询 +- `ProgramQueryController`: 节目查询,包含关联视频 +- `DanmakuQueryController`: 弹幕查询 + +#### 管理控制器(需要登录) +- `ProgramConstructController`: 节目创建和编辑 +- `ProgramVideoConstructController`: 节目视频关联管理 +- `ProgramAppendConstructController`: 节目点播内容管理 +- `DanmakuConstructController`: 弹幕批量导入 +- `FileController`: 文件上传 + +#### 用户认证 +- `UserController`: 传统用户名密码认证 +- `UserWebAuthnController`: WebAuthn 无密码认证 + +### 前端资源结构 +- 使用 Laravel Mix 构建工具 +- 支持 TailwindCSS 样式框架 +- JavaScript 组件化,主要包含: + - `from_select.js`: 下拉选择组件 + - `webauthn.js`: WebAuthn 认证逻辑 +- 生产环境支持版本哈希和 S3 部署 + +### 视图组件 +- Blade 模板引擎 +- 组件化设计: + - `components/links/`: 用户和视频链接组件 + - `components/appends/`: 点播内容列表组件 +- 支持中文本地化(zh_CN) + +### 特殊功能 +- **多平台弹幕支持**: 通过 platform_id 区分不同平台(1=B站,2=西瓜,3=抖音) +- **关键词分词搜索**: 评论搜索支持空格分隔的多关键词 +- **WebAuthn 集成**: 支持现代无密码认证 +- **文件上传**: 支持 S3 兼容存储 +- **时间戳处理**: 使用 Unix 时间戳格式存储 + +### 路由分组 +- `/`: 公开评论查询页面 +- `/construct/*`: 需要认证的管理功能 +- `/user/*`: 用户认证相关功能 + +### 数据库时间格式 +模型使用 Unix 时间戳格式 (`protected $dateFormat = 'U'`),注意在处理时间相关逻辑时需要考虑这个格式。 \ No newline at end of file diff --git a/app/Console/Commands/CreateProgramsFromComments.php b/app/Console/Commands/CreateProgramsFromComments.php new file mode 100644 index 0000000..fcef310 --- /dev/null +++ b/app/Console/Commands/CreateProgramsFromComments.php @@ -0,0 +1,176 @@ +option('dry-run'); + $limit = (int) $this->option('limit'); + + $this->info('开始查询没有关联 programs 的视频...'); + + // 查询没有关联 programs 的视频,且有置顶的评论 + $videos = Videos::query() + ->whereDoesntHave('program_pivots') + ->whereHas('comments', function ($query) { + $query->where('is_top', 1); + }) + ->with(['comments' => function ($query) { + $query->where('is_top', 1)->orderBy('created_at'); + }]) + ->limit($limit) + ->get(); + + if ($videos->isEmpty()) { + $this->info('没有找到符合条件的视频。'); + return 0; + } + + $this->info("找到 {$videos->count()} 个视频,开始处理..."); + + $successCount = 0; + $errorCount = 0; + + foreach ($videos as $video) { + $this->line("处理视频: {$video->bvid} - {$video->title}"); + + $topComment = $video->comments->first(); + if (!$topComment) { + $this->warn(" 跳过: 没有找到置顶的评论"); + continue; + } + + $this->line(" 评论内容: " . mb_substr($topComment->content, 0, 100) . '...'); + + if ($dryRun) { + $this->info(" [DryRun] 将会基于此评论创建 programs"); + $successCount++; + continue; + } + + try { + $result = $this->createProgramsFromComment($video->bvid, $topComment->content); + if ($result['success']) { + $this->info(" ✅ 成功创建 {$result['count']} 个 programs"); + $successCount++; + } else { + $this->error(" ❌ 创建失败: {$result['error']}"); + $errorCount++; + } + } catch (\Exception $e) { + $this->error(" ❌ 处理异常: " . $e->getMessage()); + $errorCount++; + } + } + + $this->info("\n处理完成:"); + $this->info("成功: {$successCount} 个视频"); + if ($errorCount > 0) { + $this->warn("失败: {$errorCount} 个视频"); + } + + return 0; + } + + /** + * 基于评论内容创建 programs + * 复用 ProgramConstructController::batch_create 的逻辑 + */ + private function createProgramsFromComment(string $bvid, string $content): array + { + // 检查是否已有关联的 programs + $count = ProgramVideos::query()->where("video_bvid", "=", $bvid)->count(); + if ($count > 0) { + return [ + 'success' => false, + 'error' => "该BVID下已有{$count}个节目关联" + ]; + } + + // 使用和 batch_create 相同的正则表达式 + $regex = "/^(p(?P\d{1,2})[-# _:,)]+)?(?P