123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- <?php
- namespace App\Console\Sync;
- use App\Libs\BatchUpdateTrait;
- use App\Models\Book\Book;
- use App\Models\Book\Chapter;
- use App\Models\Book\ChapterContent;
- use Illuminate\Console\Command;
- use Illuminate\Support\Facades\DB;
- class SyncChapters extends Command
- {
- use BatchUpdateTrait;
- /**
- * The name and signature of the console command.
- *
- * @var string
- */
- protected $signature = 'sync:chapters {--bids=}';
- /**
- * The console command description.
- *
- * @var string
- */
- protected $description = '从内容平台同步章节';
- public function handle()
- {
- // 传参
- $bids = $this->option('bids');
- $bids = filterValidIds(explode(',', $bids));
- dLog('sync')->info('sync chapters start...');
- // 获取书籍列表
- $books = $this->getBooks($bids);
- // 执行更新
- $this->runSync($books);
- dLog('sync')->info('sync chapters end...');
- }
- /**
- * @param $bids
- * @return mixed
- */
- private function getBooks($bids)
- {
- // 组装查询条件
- $query = Book::select('id', 'zw_id')->where('zw_id', '>', 0);
- if ($bids) {
- $query->whereIn('id', $bids);
- } else {
- // 连载
- $query->where('status', 0);
- }
- // 查询
- return $query->orderBy('id')->get();
- }
- /**
- * @param $books
- * @return void
- */
- private function runSync($books): void
- {
- // 判空
- if ($books->isEmpty()) {
- return;
- }
- // 循环执行
- foreach ($books as $book) {
- // 这本书有点问题
- if (in_array($book->zw_id, [141873, 125717])) {
- continue;
- }
- dLog('sync')->info('sync book chapters start: ', [$book->id, $book->zw_id]);
- // 同步章节
- $this->syncChapters($book->id, $book->zw_id);
- dLog('sync')->info('sync book chapters end: ', [$book->id, $book->zw_id]);
- // 执行更新书籍数据脚本
- $this->call('book:after:spider', ['--bid' => $book->id]);
- }
- }
- /**
- * 制作新增章节的同步
- *
- * @param $bid
- * @param $zwBid
- * @return void
- */
- private function syncChapters($bid, $zwBid)
- {
- // 判空
- if (empty($bid) || empty($zwBid)) {
- return;
- }
- // 获取内容平台书籍所有章节列表
- $zwChapters = $this->getZwChapters($zwBid);
- if (empty($zwChapters)) {
- return;
- }
- // 获取抖音平台书籍所有章节(及内容)列表
- $chapters = Chapter::where('bid', $bid)->get();
- $chapterContents = ChapterContent::select('id', 'bid', 'zw_bid', 'zw_chapter_id')
- ->where('bid', $bid)
- ->where('zw_chapter_id', '>', 0)
- ->get();
- // 校验章节数据
- $diffData = $this->getDiffChapters($bid, $zwBid, $zwChapters, $chapters, $chapterContents);
- // 写入新章节
- $chaptersInData = getProp($diffData, 'chaptersInData', []);
- if ($chaptersInData) {
- Chapter::insert($chaptersInData);
- }
- // 更新章节
- $chaptersUpData = getProp($diffData, 'chaptersUpData', []);
- if ($chaptersInData) {
- $this->batchUpdateDb('chapters', $chaptersUpData);
- }
- // 写入新章节内容(内容数据较大,分批获取)
- $newZwChaptersContentIds = getProp($diffData, 'newZwChaptersContentIds', []);
- $zwChaptersContentData = getProp($diffData, 'zwChaptersContentData', []);
- $this->saveNewChaptersContent($newZwChaptersContentIds, $bid, $zwBid, $zwChaptersContentData);
- //更新章节的content_chapter_id
- $this->updateChaptersContentId($bid);
- }
- /**
- * 书籍章节比较
- *
- * @param $bid
- * @param $zwBid
- * @param $zwChapters
- * @param $chapters
- * @param $chapterContents
- * @return array
- */
- private function getDiffChapters($bid, $zwBid, $zwChapters, $chapters, $chapterContents): array
- {
- if (empty($zwChapters)) {
- return [];
- }
- // 循环章节数据
- $chaptersData = [];
- if ($chapters) {
- foreach ($chapters as $chapter) {
- $id = (int)getProp($chapter, 'id');
- $zwChapterId = (int)getProp($chapter, 'zw_chapter_id');
- // 当前已存在的章节
- $chaptersData[$zwChapterId] = ['id' => $id];
- }
- }
- // 循环章节内容表
- $chapterContentsData = [];
- if ($chapterContents) {
- foreach ($chapterContents as $chapterContent) {
- $bid = (int)getProp($chapterContent, 'bid');
- $zwChapterId = (int)getProp($chapterContent, 'zw_chapter_id');
- $zwBid = (int)getProp($chapterContent, 'zw_bid');
- // 当前已存在的章节内容
- $chapterContentsData[$zwChapterId] = ['bid' => $bid, 'zw_bid' => $zwBid];
- }
- }
- // 循环内容平台章节列表数据
- $now = date('Y-m-d H:i:s');
- $chaptersUpData = $chaptersInData = $newZwChaptersContentIds = $zwChaptersContentData = [];
- foreach ($zwChapters as $zwChapter) {
- // 内容平台章节id
- $zwChapterId = (int)getProp($zwChapter, 'id');
- $zwChapterContentId = (int)getProp($zwChapter, 'chapter_content_id');
- $name = getProp($zwChapter, 'name');
- // 章节基本数据,为了同步章节内容时用
- $zwChaptersContentData[$zwChapterContentId] = [
- 'bid' => $bid,
- 'chapter_name' => $name,
- 'zw_bid' => $zwBid,
- 'zw_chapter_id' => $zwChapterId,
- ];
- // 基本数据
- $item = [
- 'bid' => $bid,
- 'name' => $name,
- 'sequence' => (int)getProp($zwChapter, 'sequence'),
- 'size' => (int)getProp($zwChapter, 'size'),
- 'is_vip' => (int)getProp($zwChapter, 'is_vip'),
- 'is_check' => 1,
- 'is_deleted' => (int)getProp($zwChapter, 'is_deleted'),
- 'zw_bid' => $zwBid,
- 'zw_chapter_id' => $zwChapterId,
- 'recent_update_at' => $now,
- 'post_time' => $now,
- 'check_time' => $now,
- 'created_at' => $now,
- 'updated_at' => $now,
- ];
- // 区分章节写入还是更新
- if (!isset($chaptersData[$zwChapterId])) {
- $chaptersInData[] = $item;
- } else {
- // 去掉无需更新的字段
- unset($item['bid'], $item['zw_bid'], $item['zw_chapter_id'], $item['recent_update_at'],
- $item['post_time'], $item['check_time'], $item['created_at']);
- // 加上当前章节id
- $item['id'] = (int)getProp($chaptersData[$zwChapterId], 'id');
- $chaptersUpData[] = $item;
- }
- // 区分章节内容写入还是更新
- if (!isset($chapterContentsData[$zwChapterId])) {
- $newZwChaptersContentIds[] = $zwChapterContentId;
- }
- }
- return compact('chaptersUpData', 'chaptersInData', 'newZwChaptersContentIds', 'zwChaptersContentData');
- }
- /**
- * 写入章节内容
- *
- * @param $zwChaptersContentIds
- * @param $bid
- * @param $zwBid
- * @param $zwChaptersContentData
- * @return void
- */
- private function saveNewChaptersContent($zwChaptersContentIds, $bid, $zwBid, $zwChaptersContentData)
- {
- if (empty($zwChaptersContentIds)) {
- return;
- }
- // 当前时间
- $now = date('Y-m-d H:i:s');
- // 切分id
- $zwChapterContentIdsArr = array_chunk($zwChaptersContentIds, 100);
- // 循环切分数据
- foreach ($zwChapterContentIdsArr as $contentIds) {
- // 获取内容平台章节内容
- $zwChapterContents = $this->getZwChaptersContent($contentIds);
- if (empty($zwChapterContents)) {
- continue;
- }
- // 组装写入数据
- $chaptersContentInsertData = [];
- foreach ($zwChapterContents as $zwChapterContent) {
- $zwChapterContentId = (int)getProp($zwChapterContent, 'id');
- $zwChapterContentData = getProp($zwChaptersContentData, $zwChapterContentId, []);
- // 组装写入数据
- $chaptersContentInsertData[] = [
- 'bid' => $bid,
- 'zw_bid' => $zwBid,
- 'zw_chapter_id' => (int)getProp($zwChapterContentData, 'zw_chapter_id'),
- 'chapter_name' => getProp($zwChapterContentData, 'chapter_name'),
- 'content' => formatContent(getProp($zwChapterContent, 'content')),
- 'created_at' => $now,
- 'updated_at' => $now,
- ];
- }
- // 执行写入
- ChapterContent::insert($chaptersContentInsertData);
- }
- }
- /**
- * 更新章节chapter_content_id
- *
- * @param $bid
- * @return void
- */
- private function updateChaptersContentId($bid)
- {
- if (empty($bid)) {
- return;
- }
- // 获取新章节
- $chapters = $this->getChaptersByBid($bid);
- $chapterContents = $this->getChapterContentsByBid($bid);
- if (empty($chapters) || empty($chapterContents)) {
- return;
- }
- $chaptersData = $this->buildChaptersData($chapters);
- $chapterContentsData = $this->buildChaptersData($chapterContents);
- // 组装更新数据-更新章节表chapter_content_id
- $chaptersUpdateData = [];
- foreach ($chaptersData as $key => $value) {
- $chapterContent = getProp($chapterContentsData, $key, []);
- $chaptersUpdateData[] = [
- 'id' => getProp($value, 'id'),
- 'chapter_content_id' => (int)getProp($chapterContent, 'id'),
- ];
- }
- // 执行批量更新
- $this->batchUpdateDb('chapters', $chaptersUpdateData);
- }
- /**
- * @param $chapters
- * @return array
- */
- private function buildChaptersData($chapters): array
- {
- if (empty($chapters)) {
- return [];
- }
- $result = [];
- foreach ($chapters as $chapter) {
- $bid = getProp($chapter, 'bid');
- $zwBid = getProp($chapter, 'zw_bid');
- $zwChapterId = getProp($chapter, 'zw_chapter_id');
- $key = $bid . '_' . $zwBid . '_' . $zwChapterId;
- if (!isset($result[$key])) {
- $result[$key] = $chapter;
- }
- }
- return $result;
- }
- /**
- * @param $bid
- * @return array
- */
- private function getChaptersByBid($bid): array
- {
- if (empty($bid)) {
- return [];
- }
- $chapters = Chapter::select('id', 'bid', 'zw_bid', 'zw_chapter_id')->where('bid', $bid)->get();
- return $chapters ? $chapters->toArray() : [];
- }
- /**
- * @param $bid
- * @return array
- */
- private function getChapterContentsByBid($bid): array
- {
- if (empty($bid)) {
- return [];
- }
- $chapters = ChapterContent::select('id', 'bid', 'zw_bid', 'zw_chapter_id')->where('bid', $bid)->get();
- return $chapters ? $chapters->toArray() : [];
- }
- /**
- * 查询内容平台章节列表
- *
- * @param $bid
- * @return array
- */
- private function getZwChapters($bid): array
- {
- if (empty($bid)) {
- return [];
- }
- $result = DB::connection('zw_content_mysql')
- ->table('chapters')
- ->select('id', 'bid', 'name', 'sequence', 'size', 'is_vip', 'chapter_content_id', 'is_deleted', 'is_draft')
- ->where('bid', $bid)
- // ->where('is_draft', 0)
- // ->where('is_check', 1)
- // ->where('is_deleted', 0)
- ->orderBy('sequence')
- ->get();
- return $result ? $result->toArray() : [];
- }
- /**
- * @param $zwChapterContentIds
- * @return array
- */
- private function getZwChaptersContent($zwChapterContentIds): array
- {
- if (empty($zwChapterContentIds)) {
- return [];
- }
- $result = DB::connection('zw_content_mysql')
- ->table('chapter_contents')
- ->select('id', 'content')
- ->whereIn('id', $zwChapterContentIds)
- ->get();
- return $result ? $result->toArray() : [];
- }
- }
|