135 lines
4.7 KiB
PHP
135 lines
4.7 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
namespace App\Console\Commands;
|
||
|
|
|
||
|
|
use App\Jobs\ImportBookFromGutendex;
|
||
|
|
use App\Models\Book;
|
||
|
|
use Illuminate\Console\Command;
|
||
|
|
|
||
|
|
class SyncBookFromGutendex extends Command
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* The name and signature of the console command.
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
*/
|
||
|
|
protected $signature = 'gutendex:sync-book
|
||
|
|
{gutenberg_id : The Gutenberg book ID to import}
|
||
|
|
{--force : Force re-import even if book exists}
|
||
|
|
{--no-summary : Skip summary generation}';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The console command description.
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
*/
|
||
|
|
protected $description = 'Import or update a specific book from Gutendex by its ID';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Execute the console command.
|
||
|
|
*/
|
||
|
|
public function handle(): int
|
||
|
|
{
|
||
|
|
$gutenbergId = (int) $this->argument('gutenberg_id');
|
||
|
|
$force = $this->option('force');
|
||
|
|
$generateSummary = !$this->option('no-summary');
|
||
|
|
|
||
|
|
if ($gutenbergId <= 0) {
|
||
|
|
$this->error('Invalid Gutenberg ID. Must be a positive integer.');
|
||
|
|
return self::FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->info("Syncing book from Gutendex (ID: {$gutenbergId})");
|
||
|
|
$this->newLine();
|
||
|
|
|
||
|
|
// Check if book already exists
|
||
|
|
$existingBook = Book::where('gutenberg_id', $gutenbergId)->first();
|
||
|
|
|
||
|
|
if ($existingBook && !$force) {
|
||
|
|
$this->warn('Book already exists in the database!');
|
||
|
|
$this->newLine();
|
||
|
|
$this->table(
|
||
|
|
['Field', 'Value'],
|
||
|
|
[
|
||
|
|
['Database ID', $existingBook->id],
|
||
|
|
['Title', $existingBook->title],
|
||
|
|
['Author', $existingBook->author],
|
||
|
|
['Slug', $existingBook->slug],
|
||
|
|
['Category', $existingBook->category->name ?? 'N/A'],
|
||
|
|
['Has Summary', $existingBook->summary ? 'Yes' : 'No'],
|
||
|
|
['Summary Status', $existingBook->summary->processing_status ?? 'N/A'],
|
||
|
|
]
|
||
|
|
);
|
||
|
|
$this->newLine();
|
||
|
|
|
||
|
|
if (!$this->confirm('Use --force to re-import. Continue anyway?', false)) {
|
||
|
|
$this->info('Operation cancelled.');
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Delete existing book to re-import
|
||
|
|
$this->warn('Deleting existing book...');
|
||
|
|
$existingBook->delete();
|
||
|
|
$this->info('✓ Existing book deleted.');
|
||
|
|
$this->newLine();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fetch book info from Gutendex first to show details
|
||
|
|
$this->info('Fetching book details from Gutendex...');
|
||
|
|
$gutendexClient = app(\App\Services\GutendexClient::class);
|
||
|
|
$gutendexBook = $gutendexClient->getBook($gutenbergId);
|
||
|
|
|
||
|
|
if (!$gutendexBook) {
|
||
|
|
$this->error("Failed to fetch book {$gutenbergId} from Gutendex API.");
|
||
|
|
$this->comment('The book may not exist or the API may be unavailable.');
|
||
|
|
return self::FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Display book info
|
||
|
|
$this->info('✓ Book found on Gutendex');
|
||
|
|
$this->newLine();
|
||
|
|
$this->table(
|
||
|
|
['Field', 'Value'],
|
||
|
|
[
|
||
|
|
['Gutenberg ID', $gutendexBook->id],
|
||
|
|
['Title', $gutendexBook->title],
|
||
|
|
['Author(s)', $gutendexBook->getAuthorNamesString()],
|
||
|
|
['Language', $gutendexBook->getPrimaryLanguage()],
|
||
|
|
['Public Domain', $gutendexBook->isPublicDomain() ? 'Yes' : 'No'],
|
||
|
|
['Plain Text Available', $gutendexBook->getPlainTextUrl() ? 'Yes' : 'No'],
|
||
|
|
['Download Count', number_format($gutendexBook->downloadCount)],
|
||
|
|
]
|
||
|
|
);
|
||
|
|
$this->newLine();
|
||
|
|
|
||
|
|
// Validate book
|
||
|
|
if (!$gutendexBook->isPublicDomain()) {
|
||
|
|
$this->error('This book is not in the public domain and cannot be imported.');
|
||
|
|
return self::FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!$gutendexBook->getPlainTextUrl()) {
|
||
|
|
$this->error('This book does not have a plain text version available.');
|
||
|
|
return self::FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Dispatch import job
|
||
|
|
$this->info('Dispatching import job...');
|
||
|
|
ImportBookFromGutendex::dispatch($gutenbergId, $generateSummary);
|
||
|
|
|
||
|
|
$this->newLine();
|
||
|
|
$this->info('✓ Import job dispatched successfully!');
|
||
|
|
$this->newLine();
|
||
|
|
$this->comment('The book will be imported in the background.');
|
||
|
|
$this->comment('Run the queue worker: php artisan queue:work');
|
||
|
|
|
||
|
|
if ($generateSummary) {
|
||
|
|
$this->comment('Summary will be generated automatically after import.');
|
||
|
|
} else {
|
||
|
|
$this->comment('Summary generation was skipped (--no-summary flag).');
|
||
|
|
}
|
||
|
|
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
}
|