You've already forked lubo_comment_query
177 lines
5.7 KiB
PHP
177 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Programs;
|
|
use App\Models\ProgramVideos;
|
|
use App\Models\VideoComments;
|
|
use App\Models\Videos;
|
|
use App\Models\VideoParts;
|
|
use App\Util\ProgramVideoUtil;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Database\QueryException;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class CreateProgramsFromComments extends Command
|
|
{
|
|
protected $signature = 'programs:create-from-comments
|
|
{--dry-run : 仅显示结果,不实际创建}
|
|
{--limit=10 : 处理视频数量限制}';
|
|
|
|
protected $description = '查询没有关联 programs 的视频,基于置顶的评论自动创建 programs';
|
|
|
|
public function handle()
|
|
{
|
|
$dryRun = $this->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<part>\d{1,2})[-# _:,)]+)?(?P<time>(\d{1,2}[::])?\d{1,3}[::]\d{1,2})[\s-]*(?P<content>.+)$/ui";
|
|
$video_parts = VideoParts::query()->where("bvid", "=", $bvid)->get();
|
|
|
|
$createdCount = 0;
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
foreach (explode("\n", $content) as $line) {
|
|
$line = trim($line);
|
|
if (empty($line)) {
|
|
continue;
|
|
}
|
|
|
|
$match = [];
|
|
$match_count = preg_match($regex, $line, $match);
|
|
if ($match_count === 0) {
|
|
$this->line(" 跳过行: {$line}");
|
|
continue;
|
|
}
|
|
|
|
$time = $match["time"];
|
|
$time = str_replace(":", ":", $time);
|
|
while (substr_count($time, ":") < 2) {
|
|
$time = "0:" . $time;
|
|
}
|
|
|
|
$program = new Programs();
|
|
$program->name = trim($match["content"]);
|
|
$program->save();
|
|
|
|
$video_pivot = new ProgramVideos();
|
|
$video_pivot->video_bvid = $bvid;
|
|
$video_pivot->start_part = empty($match["part"]) ? 1 : $match["part"];
|
|
$video_pivot->start_time = $time;
|
|
$video_pivot->program_id = $program->id;
|
|
$video_pivot->save();
|
|
|
|
$createdCount++;
|
|
$this->line(" 创建: {$program->name} - P{$video_pivot->start_part} {$time}");
|
|
}
|
|
|
|
if ($createdCount > 0) {
|
|
DB::commit();
|
|
|
|
// 修复创建时间
|
|
ProgramVideoUtil::fix_created_at_by_part_info($bvid, true);
|
|
|
|
return [
|
|
'success' => true,
|
|
'count' => $createdCount
|
|
];
|
|
} else {
|
|
DB::rollBack();
|
|
return [
|
|
'success' => false,
|
|
'error' => '没有解析出有效的节目信息'
|
|
];
|
|
}
|
|
|
|
} catch (QueryException $e) {
|
|
DB::rollBack();
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
}
|