Skip to content

Commit

Permalink
Feature/editor toolbar provider tabs (#2398)
Browse files Browse the repository at this point in the history
* Library Search : New event for list of providers, adjusted provider filter.

* Library Search : Do not dispatch the ProviderListEvent, not needed here.

* Toolbar: Add Pixabay as a toolbar option instead of in images
relates to xibosignageltd/xibo-private#629

---------

Co-authored-by: Peter <peter@xibosignage.com>
  • Loading branch information
maurofmferrao and PeterMis authored Feb 29, 2024
1 parent 3811aee commit 2cc16ee
Show file tree
Hide file tree
Showing 14 changed files with 445 additions and 187 deletions.
235 changes: 130 additions & 105 deletions lib/Connector/PixabayConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Xibo\Entity\SearchResult;
use Xibo\Event\LibraryProviderEvent;
use Xibo\Event\LibraryProviderImportEvent;
use Xibo\Event\LibraryProviderListEvent;
use Xibo\Support\Sanitizer\SanitizerInterface;

/**
Expand All @@ -41,6 +42,7 @@ public function registerWithDispatcher(EventDispatcherInterface $dispatcher): Co
{
$dispatcher->addListener('connector.provider.library', [$this, 'onLibraryProvider']);
$dispatcher->addListener('connector.provider.library.import', [$this, 'onLibraryImport']);
$dispatcher->addListener('connector.provider.library.list', [$this, 'onLibraryList']);
return $this;
}

Expand Down Expand Up @@ -98,127 +100,131 @@ public function onLibraryProvider(LibraryProviderEvent $event)
return;
}

// We do! Let's get some results from Pixabay
// first we look at paging
$start = $event->getStart();
$perPage = $event->getLength();
if ($start == 0) {
$page = 1;
} else {
$page = floor($start / $perPage) + 1;
}
// was Pixabay requested?
if ($event->getProviderName() === $this->getSourceName()) {
// We do! Let's get some results from Pixabay
// first we look at paging
$start = $event->getStart();
$perPage = $event->getLength();
if ($start == 0) {
$page = 1;
} else {
$page = floor($start / $perPage) + 1;
}

$query = [
'key' => $apiKey,
'page' => $page,
'per_page' => $perPage,
'safesearch' => 'true'
];

// Now we handle any other search
if ($event->getOrientation() === 'landscape') {
$query['orientation'] = 'horizontal';
} else if ($event->getOrientation() === 'portrait') {
$query['orientation'] = 'vertical';
}
$query = [
'key' => $apiKey,
'page' => $page,
'per_page' => $perPage,
'safesearch' => 'true'
];

if (!empty($event->getSearch())) {
$query['q'] = urlencode($event->getSearch());
}
// Now we handle any other search
if ($event->getOrientation() === 'landscape') {
$query['orientation'] = 'horizontal';
} else if ($event->getOrientation() === 'portrait') {
$query['orientation'] = 'vertical';
}

// Pixabay either returns images or videos, not both.
if (count($event->getTypes()) !== 1) {
return;
}
if (!empty($event->getSearch())) {
$query['q'] = urlencode($event->getSearch());
}

$type = $event->getTypes()[0];
if (!in_array($type, ['image', 'video'])) {
return;
}
// Pixabay either returns images or videos, not both.
if (count($event->getTypes()) !== 1) {
return;
}

// Pixabay require a 24-hour cache of each result set.
$key = md5($type . '_' . json_encode($query));
$cache = $this->getPool()->getItem($key);
$body = $cache->get();
$type = $event->getTypes()[0];
if (!in_array($type, ['image', 'video'])) {
return;
}

if ($cache->isMiss()) {
$this->getLogger()->debug('onLibraryProvider: cache miss, generating.');
// Pixabay require a 24-hour cache of each result set.
$key = md5($type . '_' . json_encode($query));
$cache = $this->getPool()->getItem($key);
$body = $cache->get();

// Make the request
$request = $this->getClient()->request('GET', $baseUrl . ($type === 'video' ? 'videos' : ''), [
'query' => $query
]);
if ($cache->isMiss()) {
$this->getLogger()->debug('onLibraryProvider: cache miss, generating.');

$body = $request->getBody()->getContents();
if (empty($body)) {
$this->getLogger()->debug('onLibraryProvider: Empty body');
return;
}
// Make the request
$request = $this->getClient()->request('GET', $baseUrl . ($type === 'video' ? 'videos' : ''), [
'query' => $query
]);

$body = json_decode($body);
if ($body === null || $body === false) {
$this->getLogger()->debug('onLibraryProvider: non-json body or empty body returned.');
return;
$body = $request->getBody()->getContents();
if (empty($body)) {
$this->getLogger()->debug('onLibraryProvider: Empty body');
return;
}

$body = json_decode($body);
if ($body === null || $body === false) {
$this->getLogger()->debug('onLibraryProvider: non-json body or empty body returned.');
return;
}

// Cache for next time
$cache->set($body);
$cache->expiresAt(Carbon::now()->addHours(24));
$this->getPool()->saveDeferred($cache);
} else {
$this->getLogger()->debug('onLibraryProvider: serving from cache.');
}

// Cache for next time
$cache->set($body);
$cache->expiresAt(Carbon::now()->addHours(24));
$this->getPool()->saveDeferred($cache);
} else {
$this->getLogger()->debug('onLibraryProvider: serving from cache.');
}
$providerDetails = new ProviderDetails();
$providerDetails->id = 'pixabay';
$providerDetails->link = 'https://pixabay.com';
$providerDetails->logoUrl = '/theme/default/img/connectors/pixabay_logo.svg';
$providerDetails->iconUrl = '/theme/default/img/connectors/pixabay_logo_square.svg';
$providerDetails->backgroundColor = '';

$providerDetails = new ProviderDetails();
$providerDetails->id = 'pixabay';
$providerDetails->link = 'https://pixabay.com';
$providerDetails->logoUrl = '/theme/default/img/connectors/pixabay_logo.svg';
$providerDetails->backgroundColor = '';
// Process each hit into a search result and add it to the overall results we've been given.
foreach ($body->hits as $result) {
$searchResult = new SearchResult();
// TODO: add more info
$searchResult->source = $this->getSourceName();
$searchResult->id = $result->id;
$searchResult->title = $result->tags;
$searchResult->provider = $providerDetails;

// Process each hit into a search result and add it to the overall results we've been given.
foreach ($body->hits as $result) {
$searchResult = new SearchResult();
// TODO: add more info
$searchResult->source = $this->getSourceName();
$searchResult->id = $result->id;
$searchResult->title = $result->tags;
$searchResult->provider = $providerDetails;

if ($type === 'video') {
$searchResult->type = 'video';
$searchResult->thumbnail = $result->videos->tiny->url;
$searchResult->duration = $result->duration;
$searchResult->videoThumbnailUrl = str_replace('pictureId', $result->picture_id, 'https://i.vimeocdn.com/video/pictureId_960x540.png');
if (!empty($result->videos->large)) {
$searchResult->download = $result->videos->large->url;
$searchResult->width = $result->videos->large->width;
$searchResult->height = $result->videos->large->height;
$searchResult->fileSize = $result->videos->large->size;
} else if (!empty($result->videos->medium)) {
$searchResult->download = $result->videos->medium->url;
$searchResult->width = $result->videos->medium->width;
$searchResult->height = $result->videos->medium->height;
$searchResult->fileSize = $result->videos->medium->size;
} else if (!empty($result->videos->small)) {
$searchResult->download = $result->videos->small->url;
$searchResult->width = $result->videos->small->width;
$searchResult->height = $result->videos->small->height;
$searchResult->fileSize = $result->videos->small->size;
if ($type === 'video') {
$searchResult->type = 'video';
$searchResult->thumbnail = $result->videos->tiny->url;
$searchResult->duration = $result->duration;
$searchResult->videoThumbnailUrl = str_replace('pictureId', $result->picture_id, 'https://i.vimeocdn.com/video/pictureId_960x540.png');
if (!empty($result->videos->large)) {
$searchResult->download = $result->videos->large->url;
$searchResult->width = $result->videos->large->width;
$searchResult->height = $result->videos->large->height;
$searchResult->fileSize = $result->videos->large->size;
} else if (!empty($result->videos->medium)) {
$searchResult->download = $result->videos->medium->url;
$searchResult->width = $result->videos->medium->width;
$searchResult->height = $result->videos->medium->height;
$searchResult->fileSize = $result->videos->medium->size;
} else if (!empty($result->videos->small)) {
$searchResult->download = $result->videos->small->url;
$searchResult->width = $result->videos->small->width;
$searchResult->height = $result->videos->small->height;
$searchResult->fileSize = $result->videos->small->size;
} else {
$searchResult->download = $result->videos->tiny->url;
$searchResult->width = $result->videos->tiny->width;
$searchResult->height = $result->videos->tiny->height;
$searchResult->fileSize = $result->videos->tiny->size;
}
} else {
$searchResult->download = $result->videos->tiny->url;
$searchResult->width = $result->videos->tiny->width;
$searchResult->height = $result->videos->tiny->height;
$searchResult->fileSize = $result->videos->tiny->size;
$searchResult->type = 'image';
$searchResult->thumbnail = $result->previewURL;
$searchResult->download = $result->fullHDURL ?? $result->largeImageURL;
$searchResult->width = $result->imageWidth;
$searchResult->height = $result->imageHeight;
$searchResult->fileSize = $result->imageSize;
}
} else {
$searchResult->type = 'image';
$searchResult->thumbnail = $result->previewURL;
$searchResult->download = $result->fullHDURL ?? $result->largeImageURL;
$searchResult->width = $result->imageWidth;
$searchResult->height = $result->imageHeight;
$searchResult->fileSize = $result->imageSize;
$event->addResult($searchResult);
}
$event->addResult($searchResult);
}
}

Expand All @@ -234,4 +240,23 @@ public function onLibraryImport(LibraryProviderImportEvent $event)
}
}
}

public function onLibraryList(LibraryProviderListEvent $event)
{
$this->getLogger()->debug('onLibraryList:event');

if (empty($this->getSetting('apiKey'))) {
$this->getLogger()->debug('onLibraryList: No api key');
return;
}

$providerDetails = new ProviderDetails();
$providerDetails->id = 'pixabay';
$providerDetails->link = 'https://pixabay.com';
$providerDetails->logoUrl = '/theme/default/img/connectors/pixabay_logo.svg';
$providerDetails->iconUrl = '/theme/default/img/connectors/pixabay_logo_square.svg';
$providerDetails->backgroundColor = '';

$event->addProvider($providerDetails);
}
}
2 changes: 2 additions & 0 deletions lib/Connector/ProviderDetails.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ProviderDetails implements \JsonSerializable
public $message;
public $link;
public $logoUrl;
public $iconUrl;
public $backgroundColor;

public function jsonSerialize(): array
Expand All @@ -40,6 +41,7 @@ public function jsonSerialize(): array
'message' => $this->message,
'link' => $this->link,
'logoUrl' => $this->logoUrl,
'iconUrl' => $this->iconUrl,
'backgroundColor' => $this->backgroundColor
];
}
Expand Down
1 change: 1 addition & 0 deletions lib/Connector/XiboExchangeConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public function onTemplateProvider(TemplateProviderEvent $event)
$providerDetails = new ProviderDetails();
$providerDetails->id = $this->getSourceName();
$providerDetails->logoUrl = $this->getThumbnail();
$providerDetails->iconUrl = $this->getThumbnail();
$providerDetails->message = $this->getTitle();
$providerDetails->backgroundColor = '';

Expand Down
34 changes: 26 additions & 8 deletions lib/Controller/Library.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use GuzzleHttp\Client;
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Img;
use Psr\Http\Message\ResponseInterface;
use Respect\Validation\Validator as v;
use Slim\Http\Response as Response;
use Slim\Http\ServerRequest as Request;
Expand All @@ -36,6 +37,7 @@
use Xibo\Entity\SearchResults;
use Xibo\Event\LibraryProviderEvent;
use Xibo\Event\LibraryProviderImportEvent;
use Xibo\Event\LibraryProviderListEvent;
use Xibo\Event\MediaDeleteEvent;
use Xibo\Event\MediaFullLoadEvent;
use Xibo\Factory\DisplayFactory;
Expand Down Expand Up @@ -816,10 +818,10 @@ public function grid(Request $request, Response $response)
public function search(Request $request, Response $response): Response
{
$parsedQueryParams = $this->getSanitizer($request->getQueryParams());
$provider = $parsedQueryParams->getString('provider', ['default' => 'both']);
$provider = $parsedQueryParams->getString('provider', ['default' => 'local']);

$searchResults = new SearchResults();
if ($provider === 'both' || $provider === 'local') {
if ($provider === 'local') {
// Sorting options.
// only allow from a preset list
$sortCol = match ($parsedQueryParams->getString('sortCol')) {
Expand Down Expand Up @@ -876,10 +878,8 @@ public function search(Request $request, Response $response): Response
// Add the result
$searchResults->data[] = $searchResult;
}
}

if ($provider === 'both' || $provider === 'remote') {
$this->getLog()->debug('Dispatching event.');
} else {
$this->getLog()->debug('Dispatching event, for provider ' . $provider);

// Do we have a type filter
$types = $parsedQueryParams->getArray('types');
Expand All @@ -895,11 +895,12 @@ public function search(Request $request, Response $response): Response
$parsedQueryParams->getInt('length', ['default' => 10]),
$parsedQueryParams->getString('media'),
$types,
$parsedQueryParams->getString('orientation')
$parsedQueryParams->getString('orientation'),
$provider
);

try {
$this->getDispatcher()->dispatch($event->getName(), $event);
$this->getDispatcher()->dispatch($event, $event->getName());
} catch (\Exception $exception) {
$this->getLog()->error('Library search: Exception in dispatched event: ' . $exception->getMessage());
$this->getLog()->debug($exception->getTraceAsString());
Expand All @@ -909,6 +910,23 @@ public function search(Request $request, Response $response): Response
return $response->withJson($searchResults);
}

/**
* Get list of Library providers with their details.
*
* @param Request $request
* @param Response $response
* @return Response|ResponseInterface
*/
public function providersList(Request $request, Response $response): Response|\Psr\Http\Message\ResponseInterface
{
$event = new LibraryProviderListEvent();
$this->getDispatcher()->dispatch($event, $event->getName());

$providers = $event->getProviders();

return $response->withJson($providers);
}

/**
* Media Delete Form
* @param Request $request
Expand Down
Loading

0 comments on commit 2cc16ee

Please sign in to comment.