uiharu/src/Lookup/NicoNicoLookup.php

91 lines
2.9 KiB
PHP

<?php
namespace Uiharu\Lookup;
use DOMDocument;
use RuntimeException;
use Uiharu\Url;
final class NicoNicoLookup implements \Uiharu\ILookup {
private const SHORT_DOMAINS = [
'nico.ms',
'www.nico.ms',
];
private const LONG_DOMAINS = [
'www.nicovideo.jp',
'nicovideo.jp',
];
public static function isShortDomain(string $host): bool {
return in_array($host, self::SHORT_DOMAINS);
}
public static function isLongDomain(string $host): bool {
return in_array($host, self::LONG_DOMAINS);
}
public function match(Url $url): bool {
if(!$url->isWeb())
return false;
if(self::isShortDomain($url->getHost()))
return true;
if(self::isLongDomain($url->getHost()) && str_starts_with($url->getPath(), '/watch/sm'))
return true;
return false;
}
public function lookup(Url $url): NicoNicoLookupResult {
if(self::isShortDomain($url->getHost()))
$videoId = explode('/', trim($url->getPath(), '/'))[0] ?? '';
else
$videoId = explode('/', trim($url->getPath(), '/'))[1] ?? '';
if(empty($videoId))
throw new RuntimeException('Nico Nico Douga video id missing.');
$thumbDoc = self::lookupThumbInfo($videoId);
$thumbResp = $thumbDoc->getElementsByTagName('nicovideo_thumb_response')[0] ?? null;
if(empty($thumbResp) || !$thumbResp->hasAttribute('status') || $thumbResp->getAttribute('status') !== 'ok')
throw new RuntimeException('Nico Nico Douga video with the given id could not be found.');
$thumbInfo = $thumbResp->getElementsByTagName('thumb')[0] ?? null;
if(empty($thumbInfo))
throw new RuntimeException('Nico Nico Douga thumb info missing from API result????');
parse_str($url->getQuery(), $urlQuery);
return new NicoNicoLookupResult($url, $videoId, $thumbInfo, $urlQuery);
}
private static function lookupThumbInfo(string $videoId): DOMDocument {
$curl = curl_init("https://ext.nicovideo.jp/api/getthumbinfo/{$videoId}");
curl_setopt_array($curl, [
CURLOPT_AUTOREFERER => false,
CURLOPT_CERTINFO => false,
CURLOPT_FAILONERROR => false,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TCP_FASTOPEN => true,
CURLOPT_CONNECTTIMEOUT => 2,
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
CURLOPT_TIMEOUT => 5,
CURLOPT_USERAGENT => 'Uiharu/' . UIH_VERSION,
]);
$resp = curl_exec($curl);
curl_close($curl);
if(empty($resp))
throw new RuntimeException('Nico Nico Douga API request failed.');
$doc = new DOMDocument;
if(!$doc->loadXML($resp))
throw new RuntimeException('Failed to parse Nico Nico Douga API response.');
return $doc;
}
}