warn('No output file found — nothing to upsert.'); return; } $mediaCacher = app(PostMediaCacher::class); $posts = json_decode(file_get_contents($path), true); foreach ($posts as $post) { $attributes = [ 'code' => $post['code'], 'username' => $post['username'], 'full_name' => $post['full_name'], 'caption' => $post['caption'], 'accessibility_caption' => $post['accessibility_caption'], 'is_video' => $post['is_video'], 'is_carousel' => $post['is_carousel'], 'like_count' => $post['like_count'], 'comment_count' => $post['comment_count'], 'taken_at' => $post['taken_at'], 'image_url' => $post['image_url'], 'video_url' => $post['video_url'], 'carousel_images' => $post['carousel_images'], 'profile_pic_url' => $post['profile_pic_url'], ]; $existing = Post::find($post['id']); // Once a post's media has been cached locally, its url columns // no longer point at Instagram — don't let a re-scrape clobber // them with a freshly (and just as temporarily) signed CDN url. if ($existing) { if (! $mediaCacher->isInstagramUrl($existing->image_url)) { unset($attributes['image_url']); } if (! $mediaCacher->isInstagramUrl($existing->video_url)) { unset($attributes['video_url']); } if ($existing->carousel_images && ! $mediaCacher->isInstagramUrl($existing->carousel_images[0]['url'] ?? null)) { unset($attributes['carousel_images']); } } Post::updateOrCreate(['id' => $post['id']], $attributes); } $this->info('Upserted ' . count($posts) . ' posts.'); } }