Initial Commit
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Post;
|
||||
use App\Services\PostMediaCacher;
|
||||
use Illuminate\Console\Attributes\Description;
|
||||
use Illuminate\Console\Attributes\Signature;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
#[Signature('posts:cache-media')]
|
||||
#[Description('Download and locally cache any post media still pointing at Instagram\'s CDN')]
|
||||
class CachePostMedia extends Command
|
||||
{
|
||||
public function handle(PostMediaCacher $mediaCacher): int
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
foreach (Post::query()->cursor() as $post) {
|
||||
$mediaCacher->cache($post);
|
||||
$count++;
|
||||
}
|
||||
|
||||
$this->info("Checked {$count} posts.");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Story;
|
||||
use App\Services\StoryMediaCacher;
|
||||
use Illuminate\Console\Attributes\Description;
|
||||
use Illuminate\Console\Attributes\Signature;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
#[Signature('stories:cache-media')]
|
||||
#[Description('Download and locally cache any story media still pointing at Instagram\'s CDN')]
|
||||
class CacheStoryMedia extends Command
|
||||
{
|
||||
public function handle(StoryMediaCacher $mediaCacher): int
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
foreach (Story::query()->cursor() as $story) {
|
||||
$mediaCacher->cache($story);
|
||||
$count++;
|
||||
}
|
||||
|
||||
$this->info("Checked {$count} stories.");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Post;
|
||||
use App\Services\PostMediaCacher;
|
||||
use Illuminate\Console\Attributes\Description;
|
||||
use Illuminate\Console\Attributes\Signature;
|
||||
|
||||
@@ -21,28 +22,45 @@ class ScrapeFeed extends RunsPlaywrightScript
|
||||
return;
|
||||
}
|
||||
|
||||
$mediaCacher = app(PostMediaCacher::class);
|
||||
$posts = json_decode(file_get_contents($path), true);
|
||||
|
||||
foreach ($posts as $post) {
|
||||
Post::updateOrCreate(
|
||||
['id' => $post['id']],
|
||||
[
|
||||
'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'],
|
||||
]
|
||||
);
|
||||
$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.');
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Story;
|
||||
use App\Services\StoryMediaCacher;
|
||||
use Illuminate\Console\Attributes\Description;
|
||||
use Illuminate\Console\Attributes\Signature;
|
||||
|
||||
@@ -21,25 +22,39 @@ class ScrapeStories extends RunsPlaywrightScript
|
||||
return;
|
||||
}
|
||||
|
||||
$mediaCacher = app(StoryMediaCacher::class);
|
||||
$items = json_decode(file_get_contents($path), true);
|
||||
|
||||
foreach ($items as $item) {
|
||||
Story::updateOrCreate(
|
||||
['id' => $item['id']],
|
||||
[
|
||||
'user_id' => $item['user_id'],
|
||||
'username' => $item['username'],
|
||||
'profile_pic_url' => $item['profile_pic_url'],
|
||||
'code' => $item['code'],
|
||||
'is_video' => $item['is_video'],
|
||||
'taken_at' => $item['taken_at'],
|
||||
'expiring_at' => $item['expiring_at'],
|
||||
'image_url' => $item['image_url'],
|
||||
'video_url' => $item['video_url'],
|
||||
'accessibility_caption' => $item['accessibility_caption'],
|
||||
'muted' => $item['muted'],
|
||||
]
|
||||
);
|
||||
$attributes = [
|
||||
'user_id' => $item['user_id'],
|
||||
'username' => $item['username'],
|
||||
'profile_pic_url' => $item['profile_pic_url'],
|
||||
'code' => $item['code'],
|
||||
'is_video' => $item['is_video'],
|
||||
'taken_at' => $item['taken_at'],
|
||||
'expiring_at' => $item['expiring_at'],
|
||||
'image_url' => $item['image_url'],
|
||||
'video_url' => $item['video_url'],
|
||||
'accessibility_caption' => $item['accessibility_caption'],
|
||||
'muted' => $item['muted'],
|
||||
];
|
||||
|
||||
$existing = Story::find($item['id']);
|
||||
|
||||
// Once a story'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']);
|
||||
}
|
||||
}
|
||||
|
||||
Story::updateOrCreate(['id' => $item['id']], $attributes);
|
||||
}
|
||||
|
||||
$this->info('Upserted ' . count($items) . ' story items.');
|
||||
|
||||
Reference in New Issue
Block a user