0.1.2
This commit is contained in:
@@ -3,10 +3,11 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helper\ZhConversion;
|
||||
use App\Jobs\ImageUpsert;
|
||||
use App\Jobs\RemotePrefetch;
|
||||
use App\Models\Author;
|
||||
use App\Models\Chapter;
|
||||
use App\Models\Comic;
|
||||
use App\Models\Image;
|
||||
use App\Remote\CopyManga;
|
||||
use App\Remote\ImageFetcher;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
@@ -22,13 +23,26 @@ use Illuminate\Support\Facades\Cache;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
/**
|
||||
* Comic Controller
|
||||
*/
|
||||
class ComicController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @param CopyManga $copyManga
|
||||
* @param ZhConversion $zhConversion
|
||||
*/
|
||||
public function __construct(private readonly CopyManga $copyManga, private readonly ZhConversion $zhConversion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert SC to ZH
|
||||
*
|
||||
* @param mixed $string
|
||||
* @return mixed
|
||||
*/
|
||||
protected function scToZh(mixed $string): mixed
|
||||
{
|
||||
if (gettype($string) !== 'string') {
|
||||
@@ -323,24 +337,8 @@ class ComicController extends Controller
|
||||
$chapterObj = Chapter::where('chapter_uuid', $chapter['chapter']['uuid'])->first();
|
||||
$comicObj = Comic::where('pathword', $pathword)->first();
|
||||
|
||||
$arrayForUpsert = [];
|
||||
|
||||
foreach ($chapter['sorted'] as $k => $image) {
|
||||
$metadata = $chapter;
|
||||
unset($metadata['sorted']);
|
||||
unset($metadata['chapter']['contents'], $metadata['chapter']['words']);
|
||||
|
||||
$arrayForUpsert[] = [
|
||||
'comic_id' => $comicObj->id,
|
||||
'chapter_id' => $chapterObj->id,
|
||||
'order' => $k,
|
||||
'url' => $image['url'],
|
||||
'metadata' => json_encode($metadata),
|
||||
];
|
||||
}
|
||||
|
||||
// Do an upsert
|
||||
Image::upsert($arrayForUpsert, uniqueBy: 'url');
|
||||
// Image Upsert
|
||||
ImageUpsert::dispatch($comicObj->id, $chapterObj->id, $chapter);
|
||||
|
||||
// Update history
|
||||
$request->user()->readingHistories()->attach($chapterObj->id, ['comic_id' => $comicObj->id]);
|
||||
@@ -348,6 +346,15 @@ class ComicController extends Controller
|
||||
// Get chapters from DB
|
||||
$chapters = $comicObj->chapters()->where('metadata->group_path_word', $chapter['chapter']['group_path_word'])->orderBy('order')->get(['name', 'chapter_uuid']);
|
||||
|
||||
// Do remote prefetch if needed
|
||||
if ($chapter['chapter']['next'] !== null) {
|
||||
try {
|
||||
Chapter::where('chapter_uuid', $chapter['chapter']['next'])->firstOrFail()->images()->firstOrFail();
|
||||
} catch (ModelNotFoundException $e) {
|
||||
RemotePrefetch::dispatch('chapter', ['pathword' => $pathword, 'uuid' => $chapter['chapter']['next']]);
|
||||
}
|
||||
}
|
||||
|
||||
return Inertia::render('Comic/Read', [
|
||||
'comic' => $this->scToZh($comic),
|
||||
'chapter' => $this->scToZh($chapter),
|
||||
|
||||
51
app/Jobs/ImageUpsert.php
Normal file
51
app/Jobs/ImageUpsert.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Image;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ImageUpsert implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public int $comicId,
|
||||
public int $chapterId,
|
||||
public array $chapter
|
||||
){}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
Log::info("JOB ImageUpsert START, comicId: {$this->comicId}, chapterId: {$this->chapterId}");
|
||||
|
||||
$arrayForUpsert = [];
|
||||
|
||||
foreach ($this->chapter['sorted'] as $k => $image) {
|
||||
$metadata = $this->chapter;
|
||||
unset($metadata['sorted']);
|
||||
unset($metadata['chapter']['contents'], $metadata['chapter']['words']);
|
||||
|
||||
$arrayForUpsert[] = [
|
||||
'comic_id' => $this->comicId,
|
||||
'chapter_id' => $this->chapterId,
|
||||
'order' => $k,
|
||||
'url' => $image['url'],
|
||||
'metadata' => json_encode($metadata),
|
||||
];
|
||||
}
|
||||
|
||||
// Do an upsert
|
||||
Image::upsert($arrayForUpsert, uniqueBy: 'url');
|
||||
|
||||
Log::info('JOB ImageUpsert END');
|
||||
}
|
||||
}
|
||||
51
app/Jobs/RemotePrefetch.php
Normal file
51
app/Jobs/RemotePrefetch.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Remote\CopyManga;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RemotePrefetch implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct(public string $action, public array $parameters = [])
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$copyManga = new CopyManga();
|
||||
|
||||
switch ($this->action) {
|
||||
case 'chapter':
|
||||
Log::info("JOB RemotePrefetch START, action '{$this->action}', Pathword: {$this->parameters['pathword']}, UUID: {$this->parameters['uuid']}");
|
||||
|
||||
$copyManga->chapter($this->parameters['pathword'], $this->parameters['uuid']);
|
||||
|
||||
Log::info("JOB RemotePrefetch END, action '{$this->action}'");
|
||||
break;
|
||||
case 'chapters':
|
||||
// TODO:
|
||||
break;
|
||||
case 'index':
|
||||
// TODO
|
||||
break;
|
||||
case 'tags':
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
Log::info("JOB RemotePrefetch Unknown action '{$this->action}'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ class CopyManga
|
||||
|
||||
/**
|
||||
* @var array Caching options
|
||||
* @deprecated
|
||||
*/
|
||||
protected array $options = [
|
||||
'caching' => true,
|
||||
@@ -101,17 +102,17 @@ class CopyManga
|
||||
*
|
||||
* @param string $url
|
||||
* @param array $value
|
||||
* @param int $ttl
|
||||
* @return void
|
||||
*/
|
||||
protected function writeToCache(string $url, array $value): void
|
||||
protected function writeToCache(string $url, array $value, int $ttl = 0): void
|
||||
{
|
||||
if ($this->options['caching']) {
|
||||
Cache::add("URL_{$url}", array_merge($value, ['CACHE' => [
|
||||
'CACHE' => true,
|
||||
'CACHED_AT' => Date::now(),
|
||||
'EXPIRE_AT' => Date::now()->addSeconds($this->options['cachingTimeout'])]
|
||||
]),
|
||||
$this->options['cachingTimeout']);
|
||||
'EXPIRE_AT' => Date::now()->addSeconds(($ttl !== 0) ? $ttl : $this->options['cachingTimeout'])]
|
||||
]), $this->options['cachingTimeout']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,10 +122,11 @@ class CopyManga
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param string $userAgent
|
||||
* @param int $ttl
|
||||
* @return mixed|string
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
protected function execute(string $url, string $method = 'GET', string $userAgent = ""): mixed
|
||||
protected function execute(string $url, string $method = 'GET', string $userAgent = "", int $ttl = 0): mixed
|
||||
{
|
||||
if ($this->options['caching']) {
|
||||
// Check cache exist
|
||||
@@ -156,7 +158,7 @@ class CopyManga
|
||||
if ($userAgent !== "") {
|
||||
// Directly send html to method to process
|
||||
$html = $response->getBody()->getContents();
|
||||
$this->writeToCache($url, ['response' => $html, 'type' => 'HTML']);
|
||||
$this->writeToCache($url, ['response' => $html, 'type' => 'HTML'], $ttl);
|
||||
|
||||
return $html;
|
||||
}
|
||||
@@ -166,7 +168,7 @@ class CopyManga
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
// Save to cache if needed
|
||||
$this->writeToCache($url, $json['results']);
|
||||
$this->writeToCache($url, $json['results'], $ttl);
|
||||
return $json['results'];
|
||||
} else {
|
||||
throw new Exception($json['code']);
|
||||
@@ -209,11 +211,8 @@ class CopyManga
|
||||
$parameters['limit'] = $limit;
|
||||
$parameters['offset'] = $offset;
|
||||
$parameters['top'] = $top;
|
||||
//OPTIONS
|
||||
// https://api.mangacopy.com/api/v3/comics?format=json&platform=1&q=x&limit=30&offset=0&top=all"
|
||||
// https://api.mangacopy.com/api/v3/search/comic?platform=1&q=x&limit=20&offset=0&q_type=&_update=true
|
||||
|
||||
return $this->execute($this->buildUrl("comics", $parameters));
|
||||
return $this->execute($this->buildUrl("comics", $parameters), ttl: 15 * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +232,7 @@ class CopyManga
|
||||
$parameters['limit'] = $limit;
|
||||
$parameters['offset'] = $offset;
|
||||
|
||||
return $this->execute($this->buildUrl("search/comic", $parameters));
|
||||
return $this->execute($this->buildUrl("search/comic", $parameters), ttl: 15 * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,7 +245,7 @@ class CopyManga
|
||||
*/
|
||||
public function comic(string $comic, array $parameters = []): mixed
|
||||
{
|
||||
return $this->execute($this->buildUrl("comic2/{$comic}", $parameters));
|
||||
return $this->execute($this->buildUrl("comic2/{$comic}", $parameters), ttl: 24 * 60 * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,7 +265,7 @@ class CopyManga
|
||||
$parameters['offset'] = $offset;
|
||||
$options = $this->execute($this->buildUrl("comic/{$comic}/group/{$group}/chapters", $parameters, false), 'OPTIONS');
|
||||
|
||||
return $this->execute($this->buildUrl("comic/{$comic}/group/{$group}/chapters", $parameters));
|
||||
return $this->execute($this->buildUrl("comic/{$comic}/group/{$group}/chapters", $parameters), ttl: 24 * 60 * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,7 +296,7 @@ class CopyManga
|
||||
public function legacyChapter(string $comic, string $chapter): array
|
||||
{
|
||||
$userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36";
|
||||
$responses = $this->execute($this->legacyBuildUrl("comic/{$comic}/chapter/{$chapter}"), "GET", $userAgent);
|
||||
$responses = $this->execute($this->legacyBuildUrl("comic/{$comic}/chapter/{$chapter}"), "GET", $userAgent, ttl: 24 * 60 * 60);
|
||||
|
||||
// Get Content Key
|
||||
$dom = new DOMDocument();
|
||||
@@ -347,11 +346,12 @@ class CopyManga
|
||||
*/
|
||||
public function chapter(string $comic, string $chapter, array $parameters = []): array
|
||||
{
|
||||
$responses = $this->execute($this->buildUrl("comic/{$comic}/chapter2/{$chapter}", $parameters));
|
||||
$responses['sorted'] = $this->sort($responses['chapter']['contents'], $responses['chapter']['words']);
|
||||
$responses = $this->execute($this->buildUrl("comic/{$comic}/chapter2/{$chapter}", $parameters), ttl: 24 * 60 * 60);
|
||||
|
||||
if ($this->legacyImagesFetch) {
|
||||
$responses['sorted'] = $this->legacyChapter($comic, $chapter);
|
||||
} else {
|
||||
$responses['sorted'] = $this->sort($responses['chapter']['contents'], $responses['chapter']['words']);
|
||||
}
|
||||
|
||||
return $responses;
|
||||
|
||||
Reference in New Issue
Block a user