uiharu/src/Apis/v1_0.php

231 lines
9.0 KiB
PHP

<?php
namespace Uiharu\APIs;
use stdClass;
use DOMDocument;
use Exception;
use InvalidArgumentException;
use Uiharu\Colour;
use Uiharu\Config;
use Uiharu\FFMPEG;
use Uiharu\IHasMediaInfo;
use Uiharu\MediaTypeExts;
use Uiharu\UihContext;
use Uiharu\Url;
use Uiharu\Lookup\EEPROMLookupResult;
use Uiharu\Lookup\TwitterLookupResult;
use Uiharu\Lookup\TwitterLookupTweetResult;
use Uiharu\Lookup\TwitterLookupUserResult;
use Uiharu\Lookup\YouTubeLookupResult;
use Index\MediaType;
use Index\Data\IDbConnection;
use Index\Http\HttpFx;
use Index\Performance\Stopwatch;
final class v1_0 implements \Uiharu\IApi {
private UihContext $ctx;
private IDbConnection $db;
public function __construct(UihContext $ctx) {
$this->ctx = $ctx;
$this->db = $ctx->getDatabase();
}
public function match(string $url): string {
return !str_starts_with($url, '/v');
}
public function register(HttpFx $router): void {
$router->get('/metadata', [$this, 'handleGET']);
$router->post('/metadata', [$this, 'handlePOST']);
}
public function handleGET($response, $request) {
if($request->getMethod() === 'HEAD') {
$response->setTypeJson();
return;
}
return $this->handler(
$response, $request,
(string)$request->getParam('url')
);
}
public function handlePOST($response, $request) {
if(!$request->isStreamContent())
return 400;
return $this->handler(
$response, $request,
$request->getContent()->getStream()->read(1000)
);
}
private function handler($response, $request, string $targetUrl) {
$sw = Stopwatch::startNew();
$resp = new stdClass;
$response->setTypeJson();
if(empty($targetUrl)) {
$response->setStatusCode(400);
return $resp;
}
try {
$parsedUrl = Url::parse($targetUrl);
} catch(InvalidArgumentException $ex) {
$response->setStatusCode(400);
$resp->error = 'metadata:uri';
return $resp;
}
// if no scheme is specified, try https
if(!$parsedUrl->hasScheme())
$parsedUrl->setScheme('https');
$resp->uri = $parsedUrl->toV1();
$urlHash = $parsedUrl->calculateHash(false);
$enableCache = !UIH_DEBUG || $request->hasParam('_cache');
$includeRawResult = UIH_DEBUG || $request->hasParam('include_raw');
if($enableCache) {
$cacheFetch = $this->db->prepare('SELECT `metadata_resp` FROM `uih_metadata_cache` WHERE `metadata_url` = UNHEX(?) AND `metadata_created` > NOW() - INTERVAL 10 MINUTE');
$cacheFetch->addParameter(1, $urlHash);
$cacheFetch->execute();
$cacheResult = $cacheFetch->getResult();
if($cacheResult->next()) {
$cacheResp = json_decode($cacheResult->getString(0));
if($cacheResp !== null)
$resp = $cacheResp;
}
}
if(empty($resp->type)) {
$lookup = $this->ctx->matchLookup($parsedUrl);
if($lookup !== null)
try {
$result = $lookup->lookup($parsedUrl);
$resp->uri = $result->getUrl()->toV1();
$resp->type = $result->getObjectType();
if($result->hasMediaType())
$resp->content_type = MediaTypeExts::toV1($result->getMediaType());
if($result->hasColour())
$resp->color = Colour::toHexString($result->getColour());
if($result->hasTitle())
$resp->title = $result->getTitle();
if($result->hasSiteName())
$resp->site_name = $result->getSiteName();
if($result->hasDescription())
$resp->description = $result->getDescription();
if($result->hasPreviewImage())
$resp->image = $result->getPreviewImage();
if($result instanceof TwitterLookupResult) {
if($result instanceof TwitterLookupTweetResult)
$resp->tweet_id = $result->getTwitterTweetId();
if($result instanceof TwitterLookupUserResult)
$resp->twitter_user_name = $result->getTwitterUserName();
if(UIH_DEBUG)
$resp->dbg_twitter_info = $result->getTwitterResult();
}
if($result instanceof YouTubeLookupResult) {
$resp->youtube_video_id = $result->getYouTubeVideoId();
if($result->hasYouTubeVideoStartTime())
$resp->youtube_start_time = $result->getYouTubeVideoStartTime();
if($result->hasYouTubePlayListId())
$resp->youtube_playlist = $result->getYouTubePlayListId();
if($result->hasYouTubePlayListIndex())
$resp->youtube_playlist_index = $result->getYouTubePlayListIndex();
if(UIH_DEBUG) {
$resp->dbg_youtube_info = $result->getYouTubeVideoInfo();
$resp->dbg_youtube_query = $result->getYouTubeUrlQuery();
}
}
if($result instanceof IHasMediaInfo) {
if($result->isMedia()) {
$resp->is_image = $result->isImage();
$resp->is_audio = $result->isAudio();
$resp->is_video = $result->isVideo();
if($result->hasDimensions()) {
$resp->width = $result->getWidth();
$resp->height = $result->getHeight();
}
$resp->media = new stdClass;
$resp->media->confidence = $result->getConfidence();
if($result->hasAspectRatio())
$resp->media->aspect_ratio = $result->getAspectRatio();
if($result->hasDuration())
$resp->media->duration = $result->getDuration();
if($result->hasSize())
$resp->media->size = $result->getSize();
if($result->hasBitRate())
$resp->media->bitrate = $result->getBitRate();
if($result->hasAudioTags()) {
$audioTags = $result->getAudioTags();
$resp->media->tags = new stdClass;
if($audioTags->hasTitle())
$resp->media->tags->title = $audioTags->getTitle();
if($audioTags->hasArtist())
$resp->media->tags->artist = $audioTags->getArtist();
if($audioTags->hasAlbum())
$resp->media->tags->album = $audioTags->getAlbum();
if($audioTags->hasDate())
$resp->media->tags->date = $audioTags->getDate();
if($audioTags->hasComment())
$resp->media->tags->comment = $audioTags->getComment();
if($audioTags->hasGenre())
$resp->media->tags->genre = $audioTags->getGenre();
}
}
if($result instanceof EEPROMLookupResult) {
$resp->eeprom_file_id = $result->getEEPROMId();
$resp->eeprom_file_info = $result->getEEPROMInfo();
}
if(UIH_DEBUG && $result->hasMediaInfo())
$resp->dbg_media_info = $result->getMediaInfo();
}
} catch(Exception $ex) {
$resp->error = 'metadata:lookup';
if(UIH_DEBUG) {
$resp->dbg_msg = $ex->getMessage();
$resp->dbg_ex = (string)$ex;
}
$response->setStatusCode(500);
return $resp;
}
$sw->stop();
$resp->took = $sw->getElapsedTime() / 1000;
$respJson = json_encode($resp);
$replaceCache = $this->db->prepare('REPLACE INTO `uih_metadata_cache` (`metadata_url`, `metadata_resp`) VALUES (UNHEX(?), ?)');
$replaceCache->addParameter(1, $urlHash);
$replaceCache->addParameter(2, $respJson);
$replaceCache->execute();
}
if(!empty($respJson))
$response->setContent($respJson);
else
return $resp;
}
}