From 3f282d6ecd9fe51ceeb52330a068584cef485587 Mon Sep 17 00:00:00 2001 From: User Date: Sat, 11 Jan 2025 13:07:32 -0500 Subject: [PATCH] 0.1.2 --- app/Http/Controllers/ComicController.php | 45 +++++++++-------- app/Jobs/ImageUpsert.php | 51 ++++++++++++++++++++ app/Jobs/RemotePrefetch.php | 51 ++++++++++++++++++++ app/Remote/CopyManga.php | 34 ++++++------- bun.lockb | Bin 171074 -> 170744 bytes composer.json | 1 + composer.lock | 53 +++++++++++++++++++-- package.json | 8 ++-- resources/js/Layouts/AppLayout.jsx | 3 +- resources/js/Pages/Comic/Chapters.jsx | 2 +- resources/js/Pages/Pages/Updates.jsx | 12 +++++ resources/js/components/ui/app-sidebar.jsx | 2 +- 12 files changed, 215 insertions(+), 47 deletions(-) create mode 100644 app/Jobs/ImageUpsert.php create mode 100644 app/Jobs/RemotePrefetch.php diff --git a/app/Http/Controllers/ComicController.php b/app/Http/Controllers/ComicController.php index e99d766..c6c7f2b 100644 --- a/app/Http/Controllers/ComicController.php +++ b/app/Http/Controllers/ComicController.php @@ -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), diff --git a/app/Jobs/ImageUpsert.php b/app/Jobs/ImageUpsert.php new file mode 100644 index 0000000..c708f8f --- /dev/null +++ b/app/Jobs/ImageUpsert.php @@ -0,0 +1,51 @@ +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'); + } +} diff --git a/app/Jobs/RemotePrefetch.php b/app/Jobs/RemotePrefetch.php new file mode 100644 index 0000000..70da749 --- /dev/null +++ b/app/Jobs/RemotePrefetch.php @@ -0,0 +1,51 @@ +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; + } + } +} diff --git a/app/Remote/CopyManga.php b/app/Remote/CopyManga.php index 9b626c9..4ee88d6 100644 --- a/app/Remote/CopyManga.php +++ b/app/Remote/CopyManga.php @@ -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; diff --git a/bun.lockb b/bun.lockb index 4c59ecf2b93da2c1d236ba2321acebc44605fea0..d95ba2f57aa5d2308101702eb953ec0c00324e94 100755 GIT binary patch delta 17156 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�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 z z#F?lW&tdcca$j7Bzw9wt{0>Jsc(QP?ko_!U@lfxA38g-(m<0tI@vI_FSjbMejg?qn z6trE4P2Nc8XEW6br)YhH5eq|kVC*0H? zEUgkMdDDP)DCDN?Xe{}lZ&_6B-1>%gqi1+vaQZ)c;DzuigY0j3r%3sm_Y85$fD=?8 zZb4-;guSI4#cqfcONjl&IHF47*%D)JyL@)UY}F5ULN#7DQPU8XDTV)+rR3HnqM4O!ufsHq6pfpp_O9Zp6>gCb z)M^Ie=ORqLEU~o-CQrWjioBFOwYZaN3I}W1-pusCuH=i6O=TB$PAsuP5v94$ip||CDpBM>2mAtr~+$KSYU9N?+j69P1iC!oZvBi%%~sdR*X9h4?Ok-KW|DwM!sm-TXqyTddcU+z236D zxmrSWNs)a-bc*aO;`+!|!aqf}5jiRHU_5!J^+8ruZ@HP04iOJiWLqr_Z%-wi2&(KM zw-RMTWt*xiedLjL_yKofYuQs+k3=Wm36njof~k3=7.0.0", + "php": ">=7.4" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "PleskExtLaravel\\Providers\\ConsoleServiceProvider" + ] + }, + "component": "package" + }, + "autoload": { + "psr-4": { + "PleskExtLaravel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Plesk Laravel Toolkit integration with Laravel applications.", + "keywords": [ + "laravel", + "plesk" + ], + "support": { + "issues": "https://github.com/plesk/ext-laravel-integration/issues", + "source": "https://github.com/plesk/ext-laravel-integration/tree/7.0.0" + }, + "time": "2023-01-20T09:40:57+00:00" + }, { "name": "predis/predis", "version": "v2.3.0", diff --git a/package.json b/package.json index b0fad8b..632efc7 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "devDependencies": { "@headlessui/react": "^2.2.0", "@inertiajs/react": "^2.0.0", - "@tailwindcss/forms": "^0.5.9", + "@tailwindcss/forms": "^0.5.10", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.20", "axios": "^1.7.9", @@ -21,7 +21,7 @@ "vite": "^6.0.7" }, "dependencies": { - "@hookform/resolvers": "^3.9.1", + "@hookform/resolvers": "^3.10.0", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-collapsible": "^1.1.2", @@ -35,8 +35,8 @@ "@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-toast": "^1.2.4", "@radix-ui/react-tooltip": "^1.1.6", - "@sentry/react": "^8.47.0", - "@sentry/vite-plugin": "^2.22.7", + "@sentry/react": "^8.48.0", + "@sentry/vite-plugin": "^2.23.0", "@tanstack/react-table": "^8.20.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/resources/js/Layouts/AppLayout.jsx b/resources/js/Layouts/AppLayout.jsx index 64359fb..e6184ce 100644 --- a/resources/js/Layouts/AppLayout.jsx +++ b/resources/js/Layouts/AppLayout.jsx @@ -35,8 +35,7 @@ export default function AppLayout({ auth, header, children, toolbar }) { const [theme, setTheme] = useState(getTheme()); useEffect(() => { - getTheme(); - setTheme(theme); + setTheme(getTheme()); }, []); return ( diff --git a/resources/js/Pages/Comic/Chapters.jsx b/resources/js/Pages/Comic/Chapters.jsx index 88cf7b6..4b732c8 100644 --- a/resources/js/Pages/Comic/Chapters.jsx +++ b/resources/js/Pages/Comic/Chapters.jsx @@ -215,7 +215,7 @@ export default function Chapters({ auth, comic, chapters, histories, offset }) { { chapters.list.sort((a, b) => ascending ? (a.index - b.index) : (b.index - a.index)).map(c => ( ) ) } - { (chapters.total > chapters.limit && chapters.offset === 0) && ( + { (chapters.total > chapters.limit && chapters.total > chapters.offset) && (