<?php namespace App\MetadataResolver; class PixivResolver implements Resolver { /** * サムネイル画像 URL から最大長辺 1200px の画像 URL に変換する * * @param string $thumbnailUrl サムネイル画像 URL * @return string 1200px の画像 URL */ public function thumbnailToMasterUrl(string $thumbnailUrl): string { $temp = str_replace("/c/128x128", "", $thumbnailUrl); $largeUrl = str_replace("square1200.jpg", "master1200.jpg", $temp); return $largeUrl; } /** * 直リン可能な pixiv.cat のプロキシ URL に変換する * HUGE THANKS TO PIXIV.CAT! * * @param string $pixivUrl i.pximg URL * @return string i.pixiv.cat URL */ public function proxize(string $pixivUrl): string { return str_replace("i.pximg.net", "i.pixiv.cat", $pixivUrl); } public function resolve(string $url): Metadata { preg_match("~illust_id=(\d+)~", parse_url($url)["query"], $match); $illustId = $match[1]; // 漫画ページかつページ数あり if (strpos(parse_url($url)["query"], "mode=manga_big") && strpos(parse_url($url)["query"], "page=")) { preg_match("~page=(\d+)~", parse_url($url)["query"], $match); $page = $match[1]; // 未ログインでは漫画ページを開けないため、URL を作品ページに変換する $url = str_replace("mode=manga_big", "mode=medium", $url); $client = new \GuzzleHttp\Client(); $res = $client->get($url); if ($res->getStatusCode() === 200) { $ogpResolver = new OGPResolver(); $metadata = $ogpResolver->parse($res->getBody()); preg_match("~https://i\.pximg\.net/c/128x128/img-master/img/\d{4}/\d{2}/\d{2}/\d{2}/\d{2}/\d{2}/{$illustId}_p0_square1200\.jpg~", $res->getBody(), $match); $illustThumbnailUrl = $match[0]; $illustUrl = $this->thumbnailToMasterUrl($illustThumbnailUrl); // 指定ページに変換 $illustUrl = str_replace("p0_master", "p{$page}_master", $illustUrl); $metadata->image = $this->proxize($illustUrl); return $metadata; } else { throw new \RuntimeException("{$res->getStatusCode()}: $url"); } } else { $client = new \GuzzleHttp\Client(); $res = $client->get($url); if ($res->getStatusCode() === 200) { $ogpResolver = new OGPResolver(); $metadata = $ogpResolver->parse($res->getBody()); // OGP がデフォルト画像であるようならなんとかして画像を取得する if (strpos($metadata->image, "pixiv_logo.gif") || strpos($metadata->image, "pictures.jpg")) { // 作品ページの場合のみ対応 if (strpos(parse_url($url)["query"], "mode=medium")) { preg_match("~https://i\.pximg\.net/c/128x128/img-master/img/\d{4}/\d{2}/\d{2}/\d{2}/\d{2}/\d{2}/{$illustId}(_p0)?_square1200\.jpg~", $res->getBody(), $match); $illustThumbnailUrl = $match[0]; $illustUrl = $this->thumbnailToMasterUrl($illustThumbnailUrl); $metadata->image = $this->proxize($illustUrl); } } return $metadata; } else { throw new \RuntimeException("{$res->getStatusCode()}: $url"); } } } }