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