Browse Source

Ticket #5281 - Improve default embed mechanism.

AntonLV 11 months ago
parent
commit
fac807e9fb

+ 61 - 10
inc/classes/BxDolEmbed.php

@@ -38,8 +38,21 @@
  */
 class BxDolEmbed extends BxDolFactoryObject
 {
+    protected $_bAsync = false;
+
+    protected $_sTableData = '';
+
     protected $_bCssJsAdded = false;
-    protected $_sTableName = '';
+        
+    public function __construct ($aObject, $oTemplate = null)
+    {
+        parent::__construct($aObject, $oTemplate, 'BxDolEmbedQuery');
+
+        $this->_oDb->setParams([
+            'table_data' => $this->_sTableData
+        ]);
+    }
+
     /**
      * Get embed provider object instance by object name
      * @param $sObject object name
@@ -80,16 +93,14 @@ class BxDolEmbed extends BxDolFactoryObject
     {
         // override this function in particular embed provider class
     }
-    
+
     public function getData ($sUrl, $sTheme)
     {
         $sUrl = $this->cleanYoutubeUrl($sUrl);
-        $sData = BxDolEmbedQuery::getLocal($sUrl, $sTheme, $this->_sTableName);
-        if(!$sData) {
-            $sData = $this->getDataFromApi($sUrl, $sTheme); 
-            if($sData)
-                BxDolEmbedQuery::setLocal($sUrl, $sTheme, $this->_sTableName, $sData);
-        }
+
+        $sData = $this->_oDb->getLocal($sUrl, $sTheme);
+        if(!$sData)
+            $sData = $this->{'_getData' . ($this->_bAsync ? 'Async' : '')}($sUrl, $sTheme);
 
         return json_decode($sData, true);
     }
@@ -98,8 +109,23 @@ class BxDolEmbed extends BxDolFactoryObject
     {
         // override this function in particular embed provider class
     }
-    
-    function cleanYoutubeUrl($url) {
+
+    public function process ($sUrl, $sTheme)
+    {
+        $sData = $this->getDataFromApi($sUrl, $sTheme);
+        if($sData) {
+            $this->_oDb->updateLocal($sUrl, $sTheme, $sData);
+
+            bx_alert('embed', 'processed', 0, false, [
+                'url' => $sUrl,
+                'theme' => $sTheme,
+                'data' => $sData
+            ]);
+        }
+    }
+
+    public function cleanYoutubeUrl($url)
+    {
         $parsedUrl = parse_url($url);
         if (isset($parsedUrl['host']) && $parsedUrl['host'] === 'youtu.be') {
             if (isset($parsedUrl['query'])) {
@@ -118,6 +144,31 @@ class BxDolEmbed extends BxDolFactoryObject
         }
         return $url;
     }
+    
+    protected function _getData($sUrl, $sTheme)
+    {
+        $sData = $this->getDataFromApi($sUrl, $sTheme);
+        if($sData)
+            $this->_oDb->insertLocal($sUrl, $sTheme, $sData);
+
+        return $sData;
+    }
+
+    protected function _getDataAsync($sUrl, $sTheme)
+    {
+        $sName = 'embed_for_' . $sUrl . ($sTheme ? '_' . $sTheme : '');
+        if(($oCronQuery = BxDolCronQuery::getInstance()) && !$oCronQuery->isTransientJobService($sName)) {
+            $this->_oDb->insertLocal($sUrl, $sTheme);
+
+            $oCronQuery->addTransientJobService($sName, ['system', 'process_embed', [$sUrl, $sTheme], 'TemplServices']);
+        }
+
+        return json_encode([
+            'url' => $sUrl,
+            'title' => $sUrl,
+            'domain' => parse_url($sUrl, PHP_URL_HOST)
+        ]);
+    }
 }
 
 /** @} */

+ 30 - 10
inc/classes/BxDolEmbedQuery.php

@@ -13,6 +13,8 @@
  */
 class BxDolEmbedQuery extends BxDolFactoryObjectQuery
 {
+    protected $_sTableData;
+
     static public function getObject($sObject)
     {
         return parent::getObjectFromTable($sObject, 'sys_objects_embeds', true);
@@ -22,19 +24,37 @@ class BxDolEmbedQuery extends BxDolFactoryObjectQuery
     {
         return parent::getObjectsFromTable('sys_objects_embeds');
     }
-    
-    static public function getLocal ($sUrl, $sTheme, $sTableName)
+
+    public function setParams($aParams)
+    {
+        $this->_sTableData = $aParams['table_data'] ?? '';
+    }
+
+    public function getLocal ($sUrl, $sTheme)
     {
-        $oDb = BxDolDb::getInstance();
-        $sQuery = $oDb->prepare("SELECT `data` FROM `" . $sTableName . "` WHERE `url` = ? AND  `theme` = ?", $sUrl, $sTheme);
-        return $oDb->getOne($sQuery);
+        return $this->getOne("SELECT `data` FROM `" . $this->_sTableData . "` WHERE `url` = :url AND  `theme` = :theme", [
+            'url' => $sUrl, 
+            'theme' => $sTheme
+        ]);
     }
-    
-    static public function setLocal ($sUrl, $sTheme, $sTableName, $sData)
+
+    public function insertLocal ($sUrl, $sTheme, $sData = '')
+    {
+        return (int)$this->query("INSERT INTO `" . $this->_sTableData . "` (`url`, `theme`, `data`, `added`) VALUES (:url, :theme, :data, :added)", [
+            'url' => $sUrl,
+            'theme' => $sTheme,
+            'data' => $sData,
+            'added' => time(),
+        ]) > 0;
+    }
+
+    public function updateLocal ($sUrl, $sTheme, $sData = '')
     {
-        $oDb = BxDolDb::getInstance();
-        $sQuery = $oDb->prepare("INSERT INTO `" . $sTableName . "` (`url`, `theme`, `data`, `added`) VALUES (?, ?, ?, ?)", $sUrl, $sTheme, $sData, time());
-        $oDb->query($sQuery);
+        return (int)$this->query("UPDATE `" . $this->_sTableData . "` SET `data` = :data WHERE `url` = :url AND `theme` = :theme", [
+            'url' => $sUrl,
+            'theme' => $sTheme,
+            'data' => $sData
+        ]) > 0;
     }
 }
 

+ 22 - 17
install/sql/system.sql

@@ -128,11 +128,14 @@ CREATE TABLE `sys_objects_embeds` (
 
 
 INSERT INTO `sys_objects_embeds` (`object`, `title`, `override_class_name`, `override_class_file`) VALUES
-('sys_system', 'System', 'BxTemplEmbedSystem', ''),
+('sys_system', '_adm_stg_cpt_option_sys_embed_system', 'BxTemplEmbedSystem', ''),
+('sys_microlink', '_adm_stg_cpt_option_sys_embed_microlink', 'BxTemplEmbedMicrolink', ''),
+('sys_peekalink', '_adm_stg_cpt_option_sys_embed_peekalink', 'BxTemplEmbedPeekalink', ''),
 ('sys_embedly', 'Embedly', 'BxTemplEmbedEmbedly', ''),
 ('sys_iframely', 'Iframely', 'BxTemplEmbedIframely', ''),
 ('sys_oembed', 'Oembed', 'BxTemplEmbedOembed', '');
 
+-- --------------------------------------------------------
 
 CREATE TABLE `sys_iframely_data` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -143,7 +146,7 @@ CREATE TABLE `sys_iframely_data` (
   PRIMARY KEY (id)
 );
 
-
+-- --------------------------------------------------------
 
 CREATE TABLE `sys_embeded_data` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -153,8 +156,8 @@ CREATE TABLE `sys_embeded_data` (
   `theme` varchar(10) DEFAULT NULL,
   PRIMARY KEY (id)
 );
--- --------------------------------------------------------
 
+-- --------------------------------------------------------
 
 CREATE TABLE IF NOT EXISTS `sys_objects_file_handlers` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -460,8 +463,6 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex
 (@iCategoryId, 'sys_std_show_header_right_site', '_adm_stg_cpt_option_sys_std_show_header_right_site', '', 'checkbox', '', '', '', '', 282),
 (@iCategoryId, 'sys_std_show_launcher_left', '_adm_stg_cpt_option_sys_std_show_launcher_left', '', 'checkbox', '', '', '', '', 285),
 
-(@iCategoryId, 'sys_embed_microlink_key', '_adm_stg_cpt_option_sys_embed_microlink_key', '', 'digit', '', '', '', '', 300),
-
 (@iCategoryId, 'sys_maintenance_mode', '_adm_stg_cpt_option_sys_maintenance_mode', '', 'checkbox', '', '', '', '', 400),
 (@iCategoryId, 'sys_maintenance_mode_html', '_adm_stg_cpt_option_sys_maintenance_mode_html', '', 'code', '', '', '', '', 402);
 
@@ -574,23 +575,27 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `info`, `value`, `ty
 INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, 'general', '_adm_stg_cpt_category_general', 0, 5);
 SET @iCategoryId = LAST_INSERT_ID();
 
-INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
-(@iCategoryId, 'sys_oauth_key', '_adm_stg_cpt_option_sys_oauth_key', '', 'digit', '', '', '', 20),
-(@iCategoryId, 'sys_oauth_secret', '_adm_stg_cpt_option_sys_oauth_secret', '', 'digit', '', '', '', 21),
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `info`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'sys_oauth_key', '_adm_stg_cpt_option_sys_oauth_key', '', '', 'digit', '', '', '', 20),
+(@iCategoryId, 'sys_oauth_secret', '_adm_stg_cpt_option_sys_oauth_secret', '', '', 'digit', '', '', '', 21),
+
+(@iCategoryId, 'currency_code', '_adm_stg_cpt_option_currency_code', '', 'USD', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:33:"get_options_currency_code_default";s:5:"class";s:21:"TemplPaymentsServices";}', 'Avail', '_adm_stg_err_option_currency_code', 30),
+(@iCategoryId, 'currency_sign', '_adm_stg_cpt_option_currency_sign', '', '$', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:33:"get_options_currency_sign_default";s:5:"class";s:21:"TemplPaymentsServices";}', 'Avail', '_adm_stg_err_option_currency_sign', 31),
+(@iCategoryId, 'sys_default_payment', '_adm_stg_cpt_option_sys_default_payment', '', '', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:12:"get_payments";s:5:"class";s:21:"TemplPaymentsServices";}', '', '', 35),
+
+(@iCategoryId, 'client_image_resize_width', '_adm_stg_cpt_option_client_image_resize_width', '', '0', 'digit', '', '', '', 42),
+(@iCategoryId, 'client_image_resize_height', '_adm_stg_cpt_option_client_image_resize_height', '', '0', 'digit', '', '', '', 43),
 
-(@iCategoryId, 'currency_code', '_adm_stg_cpt_option_currency_code', 'USD', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:33:"get_options_currency_code_default";s:5:"class";s:21:"TemplPaymentsServices";}', 'Avail', '_adm_stg_err_option_currency_code', 30),
-(@iCategoryId, 'currency_sign', '_adm_stg_cpt_option_currency_sign', '$', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:33:"get_options_currency_sign_default";s:5:"class";s:21:"TemplPaymentsServices";}', 'Avail', '_adm_stg_err_option_currency_sign', 31),
-(@iCategoryId, 'sys_default_payment', '_adm_stg_cpt_option_sys_default_payment', '', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:12:"get_payments";s:5:"class";s:21:"TemplPaymentsServices";}', '', '', 35),
+(@iCategoryId, 'useLikeOperator', '_adm_stg_cpt_option_use_like_operator', '', 'on', 'checkbox', '', '', '', 45),
 
-(@iCategoryId, 'client_image_resize_width', '_adm_stg_cpt_option_client_image_resize_width', '0', 'digit', '', '', '', 42),
-(@iCategoryId, 'client_image_resize_height', '_adm_stg_cpt_option_client_image_resize_height', '0', 'digit', '', '', '', 43),
+(@iCategoryId, 'sys_embed_default', '_adm_stg_cpt_option_sys_embed_default', '', 'sys_system', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_options_embed_default";s:5:"class";s:13:"TemplServices";}', '', '', 79),
+(@iCategoryId, 'sys_embedly_api_key', '_adm_stg_cpt_option_sys_embedly_api_key', '', '', 'digit', '', '', '', 80),
 
-(@iCategoryId, 'useLikeOperator', '_adm_stg_cpt_option_use_like_operator', 'on', 'checkbox', '', '', '', 45),
+(@iCategoryId, 'sys_iframely_api_key', '_adm_stg_cpt_option_sys_iframely_api_key', '', '', 'digit', '', '', '', 90),
 
-(@iCategoryId, 'sys_embed_default', '_adm_stg_cpt_option_sys_embed_default', 'sys_system', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_options_embed_default";s:5:"class";s:13:"TemplServices";}', '', '', 79),
-(@iCategoryId, 'sys_embedly_api_key', '_adm_stg_cpt_option_sys_embedly_api_key', '', 'digit', '', '', '', 80),
+(@iCategoryId, 'sys_embed_microlink_key', '_adm_stg_cpt_option_sys_embed_microlink_key', '_adm_stg_inf_option_sys_embed_microlink_key', '', 'digit', '', '', '', 100),
 
-(@iCategoryId, 'sys_iframely_api_key', '_adm_stg_cpt_option_sys_iframely_api_key', '', 'digit', '', '', '', 90);
+(@iCategoryId, 'sys_embed_peekalink_api_key', '_adm_stg_cpt_option_sys_embed_peekalink_api_key', '', '', 'digit', '', '', '', 110);
 
 
 --

+ 7 - 3
modules/boonex/english/data/langs/system/en.xml

@@ -1685,9 +1685,14 @@
     <string name="_adm_stg_cpt_option_sys_location_normalize_names"><![CDATA[Normalize geographic names]]></string>
     <string name="_adm_stg_cpt_option_sys_maps_api_key"><![CDATA[Google Maps API key]]></string>
     <string name="_adm_stg_cpt_option_sys_embed_default"><![CDATA[Embeds provider]]></string>
-    <string name="_adm_stg_cpt_option_sys_embedly_api_key"><![CDATA[Embed.ly API key (fill in to use instead of Iframely)]]></string>
-    <string name="_adm_stg_cpt_option_sys_embedly_api_pattern"><![CDATA[Embed.ly API pattern (fill in to use instead of Iframely)]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_system"><![CDATA[System]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_microlink"><![CDATA[Microlink]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_peekalink"><![CDATA[Peekalink]]></string>
+    <string name="_adm_stg_cpt_option_sys_embedly_api_key"><![CDATA[Embed.ly API key]]></string>
     <string name="_adm_stg_cpt_option_sys_iframely_api_key"><![CDATA[Iframely API key]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_microlink_key"><![CDATA[Microlink API key]]></string>
+    <string name="_adm_stg_inf_option_sys_embed_microlink_key"><![CDATA[Leave empty to use in Free mode.]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_peekalink_api_key"><![CDATA[Peekalink API key]]></string>
     <string name="_adm_stg_cpt_option_sys_eq_time"><![CDATA[Email queue execution flag]]></string>
     <string name="_adm_stg_cpt_option_sys_eq_send_per_start"><![CDATA[Number of messages to send from mail queue per run]]></string>
     <string name="_adm_stg_cpt_option_sys_eq_send_per_start_to_recipient"><![CDATA[Number of messages to send from mail queue per run to the same recipient]]></string>
@@ -1864,7 +1869,6 @@
     <string name="_adm_stg_cpt_option_sys_std_show_header_right_search"><![CDATA[Studio: Show search in header right]]></string>
     <string name="_adm_stg_cpt_option_sys_std_show_header_right_site"><![CDATA[Studio: Show 'site' link in header]]></string>
     <string name="_adm_stg_cpt_option_sys_std_show_launcher_left"><![CDATA[Studio: Show left area with menu in Launcher]]></string>
-    <string name="_adm_stg_cpt_option_sys_embed_microlink_key"><![CDATA[Studio: Microlink API key for embeds processing]]></string>
     <string name="_adm_stg_cpt_option_sys_maintenance_mode"><![CDATA[Maintenance mode]]></string>
     <string name="_adm_stg_cpt_option_sys_maintenance_mode_html"><![CDATA[Maintenance mode custom HTML code]]></string>
 

+ 7 - 3
modules/boonex/russian/data/langs/system/ru.xml

@@ -1660,9 +1660,14 @@
     <string name="_adm_stg_cpt_option_sys_location_normalize_names"><![CDATA[Нормализация географических названий]]></string>
     <string name="_adm_stg_cpt_option_sys_maps_api_key"><![CDATA[Ключ Google Maps API]]></string>
     <string name="_adm_stg_cpt_option_sys_embed_default"><![CDATA[Поставщик встраиваемого кода]]></string>
-    <string name="_adm_stg_cpt_option_sys_embedly_api_key"><![CDATA[Ключ Embed.ly API (заполните, чтобы использовать вместо Iframely)]]></string>
-    <string name="_adm_stg_cpt_option_sys_embedly_api_pattern"><![CDATA[Шаблон Embed.ly API (заполните, чтобы использовать вместо Iframely)]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_system"><![CDATA[Системный]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_microlink"><![CDATA[Microlink]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_peekalink"><![CDATA[Peekalink]]></string>
+    <string name="_adm_stg_cpt_option_sys_embedly_api_key"><![CDATA[Ключ Embed.ly API]]></string>
     <string name="_adm_stg_cpt_option_sys_iframely_api_key"><![CDATA[Ключ Iframely API]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_microlink_key"><![CDATA[Ключ Microlink API]]></string>
+    <string name="_adm_stg_inf_option_sys_embed_microlink_key"><![CDATA[Оставьте пустым для использования в бесплатном режиме.]]></string>
+    <string name="_adm_stg_cpt_option_sys_embed_peekalink_api_key"><![CDATA[Ключ Peekalink API]]></string>
     <string name="_adm_stg_cpt_option_sys_eq_time"><![CDATA[Флаг выполнения email очереди]]></string>
     <string name="_adm_stg_cpt_option_sys_eq_send_per_start"><![CDATA[Количество сообщенией, отправляемое из email очереди при каждом запуске]]></string>
     <string name="_adm_stg_cpt_option_sys_eq_send_per_start_to_recipient"><![CDATA[Количество сообщенией, отправляемое из email очереди одному и тому же получателю при каждом запуске]]></string>
@@ -1839,7 +1844,6 @@
     <string name="_adm_stg_cpt_option_sys_std_show_header_right_search"><![CDATA[Студия: Показать поиск в заголовке справа]]></string>
     <string name="_adm_stg_cpt_option_sys_std_show_header_right_site"><![CDATA[Студия: Показывать ссылку 'сайт' в заголовке]]></string>
     <string name="_adm_stg_cpt_option_sys_std_show_launcher_left"><![CDATA[Студия: Показать левую область с меню в лаунчере]]></string>
-    <string name="_adm_stg_cpt_option_sys_embed_microlink_key"><![CDATA[Studio: Microlink API ключДля обработки вложений]]></string>
     <string name="_adm_stg_cpt_option_sys_maintenance_mode"><![CDATA[Режим технического обслуживания]]></string>
     <string name="_adm_stg_cpt_option_sys_maintenance_mode_html"><![CDATA[Пользовательский HTML-код для режима обслуживания]]></string>
     

+ 6 - 2
template/embed_system_link.html

@@ -1,13 +1,17 @@
 <a href="__link__" target="_blank" style="text-decoration: none; " class="bx-embeded-link" __attrs__>
     <div class="bx-embeded" style="display: flex; flex-direction: row; border: 1px solid #cccccc; border-radius:0.5rem; align-items: stretch;">
         <div style="flex: 0 0 8rem; height: 8rem; border-radius:0.5rem 0 0 0.5rem; overflow:hidden;">
-            <img class="bx-embeded-image" src="__image__" style="width: 8rem; height: 8rem; object-fit: cover;" />
+            <bx_if:show_image>
+                <img class="bx-embeded-image" src="__image__" style="width: 8rem; height: 8rem; object-fit: cover;" />
+            </bx_if:show_image>
         </div>
         <div style="flex: 1 1 auto;display: flex; flex-direction: column; justify-content: space-between; overflow: hidden;margin: 0 1rem; ">
             <div style="padding-top: 0.5rem; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;  overflow: hidden; text-overflow: ellipsis; max-height:30px"><b>__title__</b></div>
             <div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;  overflow: hidden; text-overflow: ellipsis;max-height:52px">__description__</div>
             <div style="display: flex; flex-direction: row; column-gap: 0.5rem; align-items: center; padding-bottom: 0.5rem;">
-              <img src="__logo__" width=24 height=24  style="margin-right:0.5rem">__domain__
+                <bx_if:show_logo>
+                    <img src="__logo__" width=24 height=24  style="margin-right:0.5rem">
+                </bx_if:show_logo>__domain__
            </div>
         </div>
     </div>

+ 1 - 6
template/scripts/BxBaseEmbedEmbedly.php

@@ -15,12 +15,7 @@ class BxBaseEmbedEmbedly extends BxDolEmbed
 {
     public function __construct ($aObject, $oTemplate)
     {
-        parent::__construct ($aObject);
-
-        if ($oTemplate)
-            $this->_oTemplate = $oTemplate;
-        else
-            $this->_oTemplate = BxDolTemplate::getInstance();
+        parent::__construct ($aObject, $oTemplate);
     }
 
     public function getLinkHTML ($sLink, $sTitle = '', $sMaxWidth = '', $sTheme = '')

+ 2 - 6
template/scripts/BxBaseEmbedIframely.php

@@ -15,13 +15,9 @@ class BxBaseEmbedIframely extends BxDolEmbed
 {
     public function __construct ($aObject, $oTemplate)
     {
-        $this->_sTableName = 'sys_iframely_data';
-        parent::__construct ($aObject);
+        $this->_sTableData = 'sys_iframely_data';
 
-        if ($oTemplate)
-            $this->_oTemplate = $oTemplate;
-        else
-            $this->_oTemplate = BxDolTemplate::getInstance();
+        parent::__construct ($aObject, $oTemplate);
     }
 
     public function getLinkHTML ($sLink, $sTitle = '', $sMaxWidth = '')

+ 57 - 0
template/scripts/BxBaseEmbedMicrolink.php

@@ -0,0 +1,57 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaBaseView UNA Base Representation Classes
+ * @{
+ */
+
+/**
+ * Microlink integration.
+ * 
+ * @see BxDolEmbed
+ */
+class BxBaseEmbedMicrolink extends BxTemplEmbedSystem
+{
+    protected $_sEndpoint;
+    protected $_sEndpointPro;
+
+    public function __construct ($aObject, $oTemplate)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        $this->_bAsync = true;
+
+        $this->_sEndpoint = "https://api.microlink.io/?url=";
+        $this->_sEndpointPro = "https://pro.microlink.io/?url=";
+    }
+
+    public function getDataFromApi ($sUrl, $sTheme)
+    {
+        $sResponse = '';
+        if(($sApiKey = getParam('sys_embed_microlink_key')) != '')
+            $sResponse = bx_file_get_contents($this->_sEndpointPro . $sUrl, [], 'get', ['x-api-key: ' . $sApiKey]);
+        else
+            $sResponse = bx_file_get_contents($this->_sEndpoint . $sUrl);
+
+        $aResponse = [];
+        if(!$sResponse || !($aResponse = json_decode($sResponse, true)) || empty($aResponse['data']) || !is_array($aResponse['data']))
+            return '';
+
+        $aResult = [
+            'title' => $aResponse['data']['title'],
+            'description' => $aResponse['data']['description'],
+            'image' => $aResponse['data']['image']['url'],
+            'logo' => $aResponse['data']['logo']['url'],
+            'url' => $sUrl,
+            'domain' => parse_url($sUrl, PHP_URL_HOST)
+        ];
+
+        $this->_storeImages($aResult);
+
+        return json_encode($aResult);
+    }
+}
+
+/** @} */

+ 1 - 6
template/scripts/BxBaseEmbedOembed.php

@@ -17,12 +17,7 @@ class BxBaseEmbedOembed extends BxDolEmbed
 
     public function __construct ($aObject, $oTemplate)
     {
-        parent::__construct ($aObject);
-
-        if ($oTemplate)
-            $this->_oTemplate = $oTemplate;
-        else
-            $this->_oTemplate = BxDolTemplate::getInstance();
+        parent::__construct ($aObject, $oTemplate);
     }
 
     public function getLinkHTML ($sLink, $sTitle = '', $sMaxWidth = '')

+ 63 - 0
template/scripts/BxBaseEmbedPeekalink.php

@@ -0,0 +1,63 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaBaseView UNA Base Representation Classes
+ * @{
+ */
+
+/**
+ * Peekalink integration.
+ * 
+ * @see BxDolEmbed
+ */
+class BxBaseEmbedPeekalink extends BxTemplEmbedSystem
+{
+    protected $_sEndpoint;
+
+    public function __construct ($aObject, $oTemplate)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        $this->_bAsync = true;
+
+        $this->_sEndpoint = 'https://api.peekalink.io/';
+    }
+
+    public function getDataFromApi ($sUrl, $sTheme)
+    {
+        $sResponse = '';
+        if(($sApiKey = getParam('sys_embed_peekalink_api_key')) != '')
+            $sResponse = bx_file_get_contents($this->_sEndpoint, ['link' => $sUrl], 'post-json', [
+                'Authorization: Bearer ' . $sApiKey
+            ]);
+
+        $aResponse = [];
+        if(!$sResponse || !($aResponse = json_decode($sResponse, true)) || !is_array($aResponse))
+            return '';
+
+        $aResult = [
+            'title' => $aResponse['title'],
+            'description' => $aResponse['description'],
+            'image' => '',
+            'logo' => '',
+            'url' => $aResponse['url'],
+            'domain' => $aResponse['domain']
+        ];
+
+        $aIs = array_flip(['thumbnail', 'medium', 'large', 'original']);
+
+        if(($aP = $aResponse['page'] ?? false) && ($aPs = $aP['screenshot'] ?? false) && ($aPs = array_intersect_key($aPs, $aIs)) && (($aImg = $aPs['medium'] ?? false) || ($aImg = reset($aPs))))
+            $aResult['image'] = $aImg['url'];
+
+        if(($aI = $aResponse['image'] ?? false) && ($aI = array_intersect_key($aI, $aIs)) && (($aImg = $aI['thumbnail'] ?? false) || ($aImg = reset($aI))))
+            $aResult['logo'] = $aImg['url'];
+
+        $this->_storeImages($aResult);
+
+        return json_encode($aResult);
+    }
+}
+
+/** @} */

+ 43 - 49
template/scripts/BxBaseEmbedSystem.php

@@ -16,13 +16,9 @@ class BxBaseEmbedSystem extends BxDolEmbed
 {
     public function __construct ($aObject, $oTemplate)
     {
-        $this->_sTableName = 'sys_embeded_data';
-        parent::__construct ($aObject);
+        $this->_sTableData = 'sys_embeded_data';
 
-        if ($oTemplate)
-            $this->_oTemplate = $oTemplate;
-        else
-            $this->_oTemplate = BxDolTemplate::getInstance();
+        parent::__construct ($aObject, $oTemplate);
     }
 
     public function getLinkHTML ($sLink, $sTitle = '', $sMaxWidth = '')
@@ -48,26 +44,35 @@ class BxBaseEmbedSystem extends BxDolEmbed
                 $aAttrs['rel'] = 'nofollow';
         }
 
-        $oStorage = BxDolStorage::getObjectInstance('sys_images');
-
-        $sImage = $aData['image'];
-        if ($sImage && is_numeric($sImage) && $oStorage) {
-            $sImage = $oStorage->getFileUrlById($sImage);
-        }
+        $sImage = $aData['image'] ?? '';
+        $sLogo = $aData['logo'] ?? '';
+        if(($oStorage = BxDolStorage::getObjectInstance('sys_images')) !== false) {
+            if($sImage && is_numeric($sImage))
+                $sImage = $oStorage->getFileUrlById($sImage);
 
-        $sLogo = $aData['logo'];
-        if ($sLogo && is_numeric($sLogo) && $oStorage) {
-            $sLogo = $oStorage->getFileUrlById($sLogo);
+            if($sLogo && is_numeric($sLogo))
+                $sLogo = $oStorage->getFileUrlById($sLogo);
         }
+        $sImage = $sImage ?: $sLogo;
 
         return $this->_oTemplate->parseHtmlByName('embed_system_link.html', [
             'link' => $aData['url'],
             'attrs' => bx_convert_array2attrs($aAttrs),
             'width' => $sMaxWidth,
-            'image' => $sImage ? $sImage : $sLogo,
-            'logo' => $sLogo,
+            'bx_if:show_image' => [
+                'condition' => (bool)$sImage,
+                'content' => [
+                    'image' => $sImage
+                ]
+            ],
+            'bx_if:show_logo' => [
+                'condition' => (bool)$sLogo,
+                'content' => [
+                    'logo' => $sLogo,
+                ]
+            ],
             'title' => $aData['title'],
-            'description' => $aData['description'],
+            'description' => $aData['description'] ?? '',
             'domain' => $aData['domain'],
         ]);
     }
@@ -81,45 +86,34 @@ class BxBaseEmbedSystem extends BxDolEmbed
             'icon2' => ['tag' => 'link', 'name_attr' => 'rel', 'name' => 'icon', 'content_attr' => 'href'],
             'icon3' => ['tag' => 'link', 'name_attr' => 'rel', 'name' => 'apple-touch-icon', 'content_attr' => 'href'],
         ]);
-        
+
         $a = array_merge($a, [
-           'image' => $a['OGImage'] ? $a['OGImage'] : $a['thumbnailUrl'],
-           'logo' => $a['icon2'] ? $a['icon2'] : ($a['icon3'] ? $a['icon3'] : $a['icon']),
-           'url' => $sUrl
+            'image' => $a['OGImage'] ? $a['OGImage'] : $a['thumbnailUrl'],
+            'logo' => $a['icon2'] ? $a['icon2'] : ($a['icon3'] ? $a['icon3'] : $a['icon']),
+            'url' => $sUrl,
+            'domain' => parse_url($sUrl, PHP_URL_HOST)
         ]);
 
         unset($a['OGImage'], $a['thumbnailUrl'], $a['icon'], $a['icon2'], $a['icon3']);
 
-        if($a['image'] == '') {
-            $c = [];
-            if (getParam('sys_embed_microlink_key') != ''){
-                $c = bx_file_get_contents("https://pro.microlink.io/?url=" . $sUrl, [], 'get', ['x-api-key: ' . getParam('sys_embed_microlink_key')]);
-            }
-            else{
-                $c = bx_file_get_contents("https://api.microlink.io/?url=" . $sUrl);
-            }
-                
-            $b = json_decode($c, true);
-            $a = [
-                'title' => $b['data']['title'],
-                'description' => $b['data']['description'],
-                'image' => $b['data']['image']['url'],
-                'logo' => $b['data']['logo']['url'],
-                'url' => $sUrl,
-            ];
-        }
-
-        if($a['image'] && ($oStorage = BxDolStorage::getObjectInstance('sys_images')) !== false && ($iMediaId = $oStorage->storeFileFromUrl($a['image'], false)))
-            $a['image'] = $oStorage->getFileUrlById($iMediaId);
-
-        if($a['logo'] && ($oStorage = BxDolStorage::getObjectInstance('sys_images')) !== false && ($iMediaId = $oStorage->storeFileFromUrl($a['logo'], false)))
-            $a['logo'] = $oStorage->getFileUrlById($iMediaId);
-
-        $aUrl = parse_url($sUrl);
-        $a['domain'] = $aUrl['host'];
+        $this->_storeImages($a);
 
         return json_encode($a);
     }
+    
+    protected function _storeImages (&$a)
+    {
+        $oStorage = BxDolStorage::getObjectInstance('sys_images');
+        if($oStorage === false)
+            return;
+
+        foreach(['image', 'logo'] as $sKey)
+            if(($sMediaUrl = $a[$sKey] ?? false) && ($iMediaId = $oStorage->storeFileFromUrl($sMediaUrl, false)))
+                $a = array_merge($a, [
+                    $sKey . '_id' =>  $iMediaId,
+                    $sKey => $oStorage->getFileUrlById($iMediaId)
+                ]);
+    }
 }
 
 /** @} */

+ 6 - 1
template/scripts/BxBaseServices.php

@@ -1342,7 +1342,7 @@ class BxBaseServices extends BxDol implements iBxDolProfileService
 
         $aObjects = BxDolEmbedQuery::getObjects();
         foreach($aObjects as $aObject)
-            $aResults[$aObject['object']] = $aObject['title'];
+            $aResults[$aObject['object']] = _t($aObject['title']);
 
         return $aResults;
     }
@@ -1702,6 +1702,11 @@ class BxBaseServices extends BxDol implements iBxDolProfileService
         header("Location:" . BX_DOL_URL_ROOT, true, 301);
         exit;        
     }
+
+    public function serviceProcessEmbed($sUrl, $sTheme)
+    {
+        BxDolEmbed::getObjectInstance()->process($sUrl, $sTheme);
+    }
 }
 
 /** @} */

+ 21 - 0
template/scripts_templ/BxTemplEmbedMicrolink.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolEmbed
+ */
+class BxTemplEmbedMicrolink extends BxBaseEmbedMicrolink
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 21 - 0
template/scripts_templ/BxTemplEmbedPeekalink.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolEmbed
+ */
+class BxTemplEmbedPeekalink extends BxBaseEmbedPeekalink
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+
+/** @} */