Browse Source

Add Tenor support for GIF/videos search and integration in Chat

pull/978/head
Timothée Jaussoin 5 years ago
parent
commit
c556a34758
  1. 1
      CHANGELOG.md
  2. 1
      app/Configuration.php
  3. 19
      app/widgets/AdminMain/adminmain.tpl
  4. 6
      app/widgets/AdminMain/locales.ini
  5. 12
      app/widgets/Chat/chat.js
  6. 58
      app/widgets/Stickers/Stickers.php
  7. 5
      app/widgets/Stickers/_stickers.tpl
  8. 35
      app/widgets/Stickers/_stickers_gifs.tpl
  9. 10
      app/widgets/Stickers/_stickers_gifs_result.tpl
  10. 14
      app/widgets/Stickers/_stickers_smiley.tpl
  11. 7
      app/widgets/Stickers/locales.ini
  12. 37
      app/widgets/Stickers/stickers.css
  13. 54
      app/widgets/Stickers/stickers.js
  14. 21
      database/migrations/20201203221412_add_gifapikey_to_configuration_table.php

1
CHANGELOG.md

@ -24,6 +24,7 @@ v0.18.1 (trunk)
* Order Communities in Servers by last published
* Rename Communities page in Explore
* Add WebM and H264 video embedding support in the Chat
* Add Tenor support for GIF/videos search and integration in Chat
v0.18
---------------------------

1
app/Configuration.php

@ -14,6 +14,7 @@ class Configuration extends Model
'description',
'info',
'unregister',
'gifapikey',
'restrictsuggestions',
'locale',
'loglevel',

19
app/widgets/AdminMain/adminmain.tpl

@ -162,6 +162,25 @@
</li>
</ul>
<h3>{$c->__('tenor.title')}</h3>
<div>
<input type="text" name="gifapikey" id="gifapikey" placeholder="123ABC" value="{$conf->gifapikey}" />
<label for="info">{$c->__('tenor.label')}</label>
</div>
<ul class="list thick">
<li>
<span class="primary icon bubble color blue">
<i class="material-icons">gif</i>
</span>
<div>
<p>{$c->__('tenor.info1')}</p>
<p><a href="https://tenor.com/" target="_blank">{$c->__('tenor.info2')}</a></p>
</div>
</li>
</ul>
<br />
<h3>{$c->__('credentials.title')}</h3>

6
app/widgets/AdminMain/locales.ini

@ -41,6 +41,12 @@ description = Main XMPP server description
country = Main XMPP server country
country_pick= Pick a country in the list
[tenor]
title = Tenor integration
label = Yout Tenor API Key
info1 = Movim integrates the Tenor API to allow GIF search and publication in Chat
info2 = Access Tenor and get your API key
[log]
empty = Empty
syslog = Syslog

12
app/widgets/Chat/chat.js

@ -984,9 +984,21 @@ var Chat = {
var video = document.createElement('video');
video.setAttribute('src', file.uri);
video.setAttribute('controls', 'controls');
video.setAttribute('loop', 'loop');
// Tenor implementation
if (file.host && file.host == 'media.tenor.com') {
video.setAttribute('autoplay', 'autoplay');
}
div.appendChild(video);
}
// Tenor implementation
if (file.host && file.host == 'media.tenor.com') {
return div;
}
var a = document.createElement('a');
if (sticker == null) {

58
app/widgets/Stickers/Stickers.php

@ -5,8 +5,12 @@ use Moxl\Xec\Action\BOB\Answer;
use Respect\Validation\Validator;
use App\Configuration;
class Stickers extends \Movim\Widget\Base
{
private $paginate = 20;
public function load()
{
$this->addcss('stickers.css');
@ -107,11 +111,13 @@ class Stickers extends \Movim\Widget\Base
return;
}
$packs = $this->getPacks();
$configuration = Configuration::get();
$isGifEnabled = !empty($configuration->gifapikey);
$packs = $this->getPacks();
$pack = isset($pack) ? $pack : current($packs);
if (in_array($pack, $packs)) {
if (!$isGifEnabled) {
$files = scandir(PUBLIC_PATH.'/stickers/'.$pack);
array_shift($files);
@ -122,10 +128,18 @@ class Stickers extends \Movim\Widget\Base
$view->assign('stickers', $files);
$view->assign('packs', $packs);
$view->assign('pack', $pack);
$view->assign('gifEnabled', $isGifEnabled);
$view->assign('info', parse_ini_file(PUBLIC_PATH.'/stickers/'.$pack.'/info.ini'));
$view->assign('path', $this->respath('stickers', false, false, true));
Drawer::fill($view->draw('_stickers'), true);
} else {
$view = $this->tpl();
$view->assign('jid', $to);
$view->assign('packs', $packs);
Drawer::fill($view->draw('_stickers_gifs'), true);
$this->rpc('Stickers.setGifsSearchEvent', $to);
}
}
@ -144,6 +158,46 @@ class Stickers extends \Movim\Widget\Base
$this->rpc('Stickers.setEmojisEvent', $mid);
}
/**
* @brief Search for gifs
*/
public function ajaxHttpSearchGifs($keyword, int $page = 0)
{
$configuration = Configuration::get();
$apiKey = $configuration->gifapikey;
if (empty($apiKey)) return;
$keyword = filter_var($keyword, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);
$results = requestURL(
'https://api.tenor.com/v1/search?q='.$keyword.
'&key='.$apiKey.
'&limit='.$this->paginate.
'&pos='.($page*$this->paginate)
);
$view = $this->tpl();
if ($results) {
$results = \json_decode($results);
if ($results) {
foreach ($results->results as $result) {
$gif = [
'url' => $result->media[0]->tinywebm->url,
'preview' => $result->media[0]->tinywebm->preview,
'width' => $result->media[0]->tinywebm->dims[0],
'height' => $result->media[0]->tinywebm->dims[1],
];
$view->assign('gif', $gif);
$this->rpc('MovimTpl.append', '#gifs .masonry', $view->draw('_stickers_gifs_result'));
}
}
}
$this->rpc('Stickers.setGifsEvents');
}
/**
* @brief Get the path of an emoji
*/

5
app/widgets/Stickers/_stickers.tpl

@ -28,6 +28,11 @@
</section>
<div>
<ul class="tabs narrow">
{if="$gifEnabled"}
<li onclick="Stickers_ajaxShow('{$jid}')">
<a href="#"><i class="material-icons" style="font-size: 5rem;">gif</i></a>
</li>
{/if}
{loop="$packs"}
<li onclick="Stickers_ajaxShow('{$jid}', '{$value}')" {if="$value == $pack"}class="active"{/if}>
<a href="#"><img alt=":sticker:" class="emoji medium" src="/stickers/{$value}/icon.png"></a>

35
app/widgets/Stickers/_stickers_gifs.tpl

@ -0,0 +1,35 @@
<section id="gifs" class="scroll">
<div class="masonry"></div>
<div class="placeholder">
<i class="material-icons">search</i>
<h1>{$c->__('sticker.gif_title')}</h1>
<h4>{$c->__('sticker.gif_text')}</h4>
</div>
</section>
<div>
<ul id="gifssearchbar" class="list fill thin">
<li>
<span class="primary icon gray">
<i class="material-icons">search</i>
</span>
<form name="search" onsubmit="return false;">
<div>
<input name="keyword" autocomplete="off"
title="{$c->__('sticker.keyword')}"
placeholder="{$c->__('sticker.keyword')}"
type="text">
</div>
</form>
</li>
</ul>
<ul class="tabs narrow">
<li onclick="Stickers_ajaxShow('{$jid}')" class="active">
<a href="#"><i class="material-icons" style="font-size: 5rem;">gif</i></a>
</li>
{loop="$packs"}
<li onclick="Stickers_ajaxShow('{$jid}', '{$value}')">
<a href="#"><img alt=":sticker:" class="emoji medium" src="/stickers/{$value}/icon.png"></a>
</li>
{/loop}
</ul>
</div>

10
app/widgets/Stickers/_stickers_gifs_result.tpl

@ -0,0 +1,10 @@
<video
class="brick"
poster="{$gif.preview}"
loop
preload="none"
width="{$gif.width}"
height="{$gif.height}"
src="{$gif.url}"
type="video/webm">
</video>

14
app/widgets/Stickers/_stickers_smiley.tpl

@ -1,14 +0,0 @@
<section>
{autoescape="off"}
{$emojis}
{/autoescape}
</section>
<div>
<ul class="tabs narrow">
{loop="$packs"}
<li onclick="Stickers_ajaxShow('{$jid}', '{$value}')">
<a href="#"><img alt=":sticker:" class="emoji medium" src="/stickers/{$value}/icon.png"></a>
</li>
{/loop}
</ul>
</div>

7
app/widgets/Stickers/locales.ini

@ -1,3 +1,6 @@
[sticker]
title = Stickers
sent = A sticker has been sent using Movim
title = Stickers
sent = A sticker has been sent using Movim
keyword = Type a keyword
gif_title = Find a GIF
gif_text = Powered by Tenor

37
app/widgets/Stickers/stickers.css

@ -22,3 +22,40 @@
transform: scale(1.3);
z-index: 2;
}
#gifssearchbar {
margin-bottom: 1rem;
}
#gifs {
height: calc(100% - 6rem);
overflow-x: hidden;
}
#gifs .masonry {
display: flex;
flex-flow: row wrap;
width: calc(100% - 1.25rem);
margin-left: 1.5rem;
margin-top: 1.5rem;
}
#gifs .masonry:not(:empty) + .placeholder {
display: none;
}
#gifs .masonry .brick {
flex: auto;
display: block;
height: 19rem;
min-width: 10rem;
max-width: 31.5rem;
object-fit: cover;
margin: 0 2rem 2rem 0;
border-radius: 0.5rem;
}
#gifs .masonry .brick:hover {
cursor: pointer;
box-shadow: 0 0 0.5rem rgba(var(--movim-font), 0.7);
}

54
app/widgets/Stickers/stickers.js

@ -1,4 +1,7 @@
var Stickers = {
timer : null,
stickersPage : 0,
addSmiley: function(element) {
Chat.insertAtCursor(element.dataset.emoji);
Drawer.clear();
@ -36,6 +39,57 @@ var Stickers = {
Dialog_ajaxClear();
}
i++;
}
},
setGifsSearchEvent() {
const search = document.querySelector('#gifssearchbar input');
search.focus();
search.addEventListener('input', e => {
clearTimeout(Stickers.timer);
Stickers.timer = setTimeout(() => {
const gifs = document.querySelector('#gifs .masonry');
gifs.innerHTML = '';
Stickers.stickersPage = 0;
if (search.value !== '') {
document.querySelector('#gifssearchbar span.primary i').innerText = 'autorenew';
document.querySelector('#gifssearchbar span.primary').classList.add('spin');
Stickers_ajaxHttpSearchGifs(search.value, Stickers.stickersPage);
}
}, 400);
});
},
setGifsEvents() {
if (search.value !== '') {
document.querySelector('#gifssearchbar span.primary i').innerText = 'search';
document.querySelector('#gifssearchbar span.primary').classList.remove('spin');
}
const gifs = document.querySelectorAll('#gifs video');
let i = 0;
while (i < gifs.length) {
gifs[i].addEventListener('mouseover', e => {
e.target.play();
});
gifs[i].addEventListener('mouseout', e => {
e.target.pause();
});
gifs[i].addEventListener('click', e => {
Chat_ajaxHttpDaemonSendMessage(
Chat.getTextarea().dataset.jid,
e.target.src,
Boolean(Chat.getTextarea().dataset.muc)
);
Drawer.clear();
});
i++;
}
}

21
database/migrations/20201203221412_add_gifapikey_to_configuration_table.php

@ -0,0 +1,21 @@
<?php
use Movim\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddGifapikeyToConfigurationTable extends Migration
{
public function up()
{
$this->schema->table('configuration', function (Blueprint $table) {
$table->string('gifapikey')->nullable();
});
}
public function down()
{
$this->schema->table('configuration', function (Blueprint $table) {
$table->dropColumn('gifapikey');
});
}
}
Loading…
Cancel
Save