Ver Fonte

Merge branch 'master' of https://github.com/unaio/una

AntonLV há 5 anos atrás
pai
commit
c740cdc9cd
28 ficheiros alterados com 242 adições e 73 exclusões
  1. 58 3
      inc/classes/BxDolStorage.php
  2. 14 6
      inc/classes/BxDolStorageQuery.php
  3. 4 2
      inc/classes/BxDolTranscoder.php
  4. 16 0
      inc/classes/BxDolTranscoderVideo.php
  5. 6 4
      modules/base/general/classes/BxBaseModGeneralTemplate.php
  6. 2 2
      modules/base/text/classes/BxBaseModTextModule.php
  7. 2 1
      modules/boonex/ads/install/sql/install.sql
  8. 2 2
      modules/boonex/albums/classes/BxAlbumsModule.php
  9. 2 2
      modules/boonex/albums/classes/BxAlbumsTemplate.php
  10. 2 1
      modules/boonex/albums/install/sql/install.sql
  11. 2 1
      modules/boonex/classes/install/sql/install.sql
  12. 2 1
      modules/boonex/forum/install/sql/install.sql
  13. 36 7
      modules/boonex/help_tours/classes/BxHelpToursDb.php
  14. 35 3
      modules/boonex/help_tours/classes/BxHelpToursGridTours.php
  15. 7 1
      modules/boonex/help_tours/classes/BxHelpToursModule.php
  16. 0 1
      modules/boonex/help_tours/classes/BxHelpToursTemplate.php
  17. 4 0
      modules/boonex/help_tours/install/langs/en.xml
  18. 11 11
      modules/boonex/help_tours/template/images/icons/std-icon.svg
  19. 16 13
      modules/boonex/help_tours/template/tour.html
  20. 2 1
      modules/boonex/posts/install/sql/install.sql
  21. 3 2
      modules/boonex/reviews/install/sql/install.sql
  22. 4 0
      modules/boonex/russian/data/langs/bx_help_tours/ru.xml
  23. 2 1
      modules/boonex/tasks/install/sql/install.sql
  24. 2 2
      modules/boonex/timeline/classes/BxTimelineModule.php
  25. 2 1
      modules/boonex/timeline/install/sql/install.sql
  26. 2 2
      modules/boonex/videos/classes/BxVideosModule.php
  27. 2 2
      modules/boonex/videos/classes/BxVideosTemplate.php
  28. 2 1
      modules/boonex/videos/install/sql/install.sql

+ 58 - 3
inc/classes/BxDolStorage.php

@@ -79,7 +79,8 @@ define('BX_DOL_STORAGE_QUEUED_DELETIONS_PER_RUN', 200); ///< max number of file
  * - engine - storage engine, for now the following engines are supported:
  *     1. Local - local storage, by default files are stored in /storage/ subfolder 
  *     2. S3 - Amazon S3 storage, files are stored on Amazon S3 storage, you need to point AWS Access Key, AWS Secret Key and AWS Bucket in the settings
- * - params - custom storage engine params as php serialized string
+ * - params - custom storage engine params as php serialized string, supported params:
+ *      1. fields - list of additional fields to add to database as key(field name) and value(func or serialized service call to get the value)
  * - token_life - life of the security token in seconds for private files
  * - cache_control - control browser cache, allow browser to store files in browser's cache for this number of seconds, to disable browser cache,
  *   or let browser to decide on its own set it to 0(zero)
@@ -450,6 +451,21 @@ abstract class BxDolStorage extends BxDolFactory implements iBxDolFactoryObject
             return false;
         }
 
+        // process additional custom fields, like video duration and video dimension
+
+        $aAdditionalFields = array();
+        if (isset($this->_aParams['fields']) && is_array($this->_aParams['fields'])) {
+            foreach ($this->_aParams['fields'] as $sField => $mixedMethod) {
+                if (is_string($mixedMethod) && method_exists($this, $mixedMethod)) {
+                    $aAdditionalFields[$sField] = $this->$mixedMethod($sTmpFile, $sMimeType, $sExt, $this);
+                }
+                elseif (is_array($mixedMethod) && isset($mixedMethod['module']) && isset($mixedMethod['method'])) {
+                    $mixedMethod['params'] = array($sTmpFile, $sMimeType, $sExt, $this);
+                    $aAdditionalFields[$sField] = call_user_func_array('bx_srv', array($mixedMethod['module'], $mixedMethod['method'], $mixedMethod['params'], isset($mixedMethod['class']) ? $mixedMethod['class'] : 'Module'));
+                } 
+            }
+        }
+
         // store file to storage engine
 
         $sLocalId = $this->genRandName();
@@ -467,7 +483,7 @@ abstract class BxDolStorage extends BxDolFactory implements iBxDolFactoryObject
 
         $iTime = time();
         $iSize = $oHelper->getSize();
-        $bFileAdded = $this->_oDb->addFile($iProfileId, $sLocalId, $sRemoteNamePath, $oHelper->getName(), $sMimeType, $sExt, $iSize, $iTime, $isPrivate);
+        $bFileAdded = $this->_oDb->addFile($iProfileId, $sLocalId, $sRemoteNamePath, $oHelper->getName(), $sMimeType, $sExt, $iSize, $iTime, $isPrivate, $aAdditionalFields);
         $iId = $this->_oDb->lastId();
         if (!$bFileAdded || !$iId) {
             $this->deleteFileFromEngine($sPath . $sLocalId, $isPrivate);
@@ -689,7 +705,29 @@ abstract class BxDolStorage extends BxDolFactory implements iBxDolFactoryObject
      */
     public function getFile($iFileId)
     {
-        return $this->_oDb->getFileById($iFileId);
+        $a = $this->_oDb->getFileById($iFileId);
+
+        // update custom fields for previously uploaded files
+        if (!defined('BX_DOL_STORAGE_CUSTOM_FIELDS_UPDATE_SKIP') && isset($this->_aParams['fields']) && is_array($this->_aParams['fields'])) {
+            foreach ($this->_aParams['fields'] as $sField => $mixedMethod) {
+                if ($a[$sField])
+                    continue;
+
+                $sFileUrl = $this->getFileUrlById($iFileId);
+
+                if (is_string($mixedMethod) && method_exists($this, $mixedMethod)) {
+                    $a[$sField] = $this->$mixedMethod($sFileUrl, $a['mime_type'], $a['ext'], $this);
+                }
+                elseif (is_array($mixedMethod) && isset($mixedMethod['module']) && isset($mixedMethod['method'])) {
+                    $mixedMethod['params'] = array($sFileUrl, $a['mime_type'], $a['ext'], $this);
+                    $a[$sField] = call_user_func_array('bx_srv', array($mixedMethod['module'], $mixedMethod['method'], $mixedMethod['params'], isset($mixedMethod['class']) ? $mixedMethod['class'] : 'Module'));
+                } 
+                if ($a[$sField])
+                    $this->_oDb->modifyCustomField($iFileId, $sField, $a[$sField], false);
+            }
+        }
+
+        return $a;
     }
 
     /**
@@ -1201,6 +1239,23 @@ abstract class BxDolStorage extends BxDolFactory implements iBxDolFactoryObject
 
         return $this->queueFilesForDeletion($a);
     }
+
+    protected function getFileDuration($sFilePath, $sMimeType, $sExt, $oStorage)
+    {
+        if (strncmp('video/', $sMimeType, 6) === 0)
+            return (int)BxDolTranscoderVideo::getDuration($sFilePath);
+        return 0;
+    }
+
+    protected function getFileDimensions($sFilePath, $sMimeType, $sExt, $oStorage)
+    {
+        if (strncmp('video/', $sMimeType, 6) === 0 && $o = BxDolTranscoderVideo::getObjectVideoAbstract()) {
+            $a = $o->getVideoSize($sFilePath);
+            if ($a && isset($a['w']) && isset($a['h']))
+                return $a['w'] . 'x' . $a['h'];
+        }
+        return '';
+    }
 }
 
 

+ 14 - 6
inc/classes/BxDolStorageQuery.php

@@ -122,13 +122,21 @@ class BxDolStorageQuery extends BxDolDb
         return BxDolProfileQuery::getInstance()->updateProfileQuota($iProfileId, $iSize, $iNumber);
     }
 
-    public function addFile($iProfileId, $sLocalId, $sPath, $aFileName, $sMimeType, $sExt, $iSize, $iTime, $isPrivate)
+    public function addFile($iProfileId, $sLocalId, $sPath, $aFileName, $sMimeType, $sExt, $iSize, $iTime, $isPrivate, $aAdditionalFields = array())
     {
-        $sQuery = $this->prepare("INSERT INTO " . $this->_sTableFiles . " SET
-            `profile_id` = ?, `remote_id` = ?, `path` = ?, `file_name` = ?, `mime_type` = ?, `ext` = ?, `size` = ?, `added` = ?, `modified` = ?, `private` = ?",
-            $iProfileId, $sLocalId, $sPath, $aFileName, $sMimeType, $sExt, $iSize, $iTime, $iTime, $isPrivate ? 1 : 0
-        );
-        return $this->query($sQuery);
+        $aBind = array('profile_id' => $iProfileId, 'local_id' => $sLocalId, 'path' => $sPath, 'file_name' => $aFileName, 'mime_type' => $sMimeType, 'ext' => $sExt, 'size' => $iSize, 'time' => $iTime, 'private' => $isPrivate ? 1 : 0);
+
+        $sQuery = "INSERT INTO " . $this->_sTableFiles . " SET
+            `profile_id` = :profile_id, `remote_id` = :local_id, `path` = :path, `file_name` = :file_name, `mime_type` = :mime_type, `ext` = :ext, `size` = :size, `added` = :time, `modified` = :time, `private` = :private";
+
+        if ($aAdditionalFields && is_array($aAdditionalFields)) {
+            foreach ($aAdditionalFields as $sField => $sValue) {
+                $aBind[$sField] = $sValue;
+                $sQuery .= ", `$sField` = :$sField";
+            }
+        }
+
+        return $this->query($sQuery, $aBind);
     }
 
     public function modifyFilePrivate($iFileId, $isPrivate)

+ 4 - 2
inc/classes/BxDolTranscoder.php

@@ -885,13 +885,15 @@ class BxDolTranscoder extends BxDolFactory implements iBxDolFactoryObject
         return false;
     }
 
-    public function getMaxResizeDimention ()
+    public function getMaxResizeDimention ($sFilter = 'Resize', $sKey = '')
     {
-        $a = $this->_oDb->getTranscoderFilters('Resize');
+        $a = $this->_oDb->getTranscoderFilters($sFilter);
         if (!$a)
             return 0;
         $aFilter = array_pop($a);
         $aFilterParams = $aFilter['filter_params'] ? unserialize($aFilter['filter_params']) : array();
+        if ($sKey)
+            return isset($aFilterParams[$sKey]) ? $aFilterParams[$sKey] : 0;
         return $aFilterParams ? max(isset($aFilterParams['w']) ? $aFilterParams['w'] : 0, isset($aFilterParams['h']) ? $aFilterParams['h'] : 0) : 0;
     }
 

+ 16 - 0
inc/classes/BxDolTranscoderVideo.php

@@ -77,6 +77,16 @@ class BxDolTranscoderVideo extends BxDolTranscoder implements iBxDolFactoryObjec
         $this->_sQueueTable = $this->_oDb->getQueueTable();
     }
 
+    public static function getObjectVideoAbstract()
+    {
+        if (isset($GLOBALS['bxDolClasses'][__CLASS__ . '!Abstract']))
+            return $GLOBALS['bxDolClasses'][__CLASS__ . '!Abstract'];
+
+        $aObject = array('object' => 'abstract');
+        $o = new BxDolTranscoderVideo ($aObject, null);
+        return ($GLOBALS['bxDolClasses'][__CLASS__ . '!Abstract'] = $o);
+    }
+
     public static function getDuration($sFile)
     {
         $sCommand = escapeshellcmd(BX_SYSTEM_FFMPEG) . " -i " . escapeshellarg($sFile) . " 2>&1";
@@ -222,6 +232,12 @@ class BxDolTranscoderVideo extends BxDolTranscoder implements iBxDolFactoryObjec
         return true;
     }
 
+    public function isProcessHD ($sOrigVideoDim)
+    {
+        $iHeight = $this->getMaxResizeDimention('Mp4', 'h');
+        return ($aDim = explode('x', $sOrigVideoDim)) && isset($aDim[1]) && (int)$aDim[1] >= $iHeight ? true : false;
+    }
+
     /**
      * Get video size. 
      * It generated image from the video and returns size of the image.

+ 6 - 4
modules/base/general/classes/BxBaseModGeneralTemplate.php

@@ -498,8 +498,9 @@ class BxBaseModGeneralTemplate extends BxDolModuleTemplate
             $sVideoUrlHd = '';
             if($isVideo) {
                 $sVideoUrl = $oStorage->getFileUrlById($a['id']);
-                $aVideoSize = $aTranscodersVideo['mp4_hd']->getVideoSize($sVideoUrl);
-                if(!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+                $aVideoFile = $oStorage->getFile($a['id']);
+
+                if (!empty($aVideoFile['dimensions']) && $aTranscodersVideo['mp4_hd']->isProcessHD($aVideoFile['dimensions']))
                     $sVideoUrlHd = $aTranscodersVideo['mp4_hd']->getFileUrl($a['id']);
             }
 
@@ -562,8 +563,9 @@ class BxBaseModGeneralTemplate extends BxDolModuleTemplate
         // check HD video version
         $sVideoUrlHd = '';
         $sVideoUrl = $oStorage->getFileUrlById($a['id']);
-        $aVideoSize = $aTranscodersVideo['mp4_hd']->getVideoSize($sVideoUrl);
-        if (!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+        $aVideoFile = $oStorage->getFile($a['id']);
+
+        if (!empty($aVideoFile['dimensions']) && $aTranscodersVideo['mp4_hd']->isProcessHD($aVideoFile['dimensions']))
             $sVideoUrlHd = $aTranscodersVideo['mp4_hd']->getFileUrl($a['id']);
 
         // generate player code

+ 2 - 2
modules/base/text/classes/BxBaseModTextModule.php

@@ -784,10 +784,10 @@ class BxBaseModTextModule extends BxBaseModGeneralModule implements iBxDolConten
         $aResults = array();
         foreach ($aGhostFiles as $k => $a) {
             $sVideoUrl = $oStorage->getFileUrlById($a['id']);
-            $aVideoSize = $oTcMp4Hd->getVideoSize($sVideoUrl);
+            $aVideoFile = $oStorage->getFile($a['id']);
 
             $sVideoUrlHd = '';
-            if(!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+            if (!empty($aVideoFile['dimensions']) && $oTcMp4Hd->isProcessHD($aVideoFile['dimensions']))
                 $sVideoUrlHd = $oTcMp4Hd->getFileUrl($a['id']);
 
             $aResults[$a['id']] = array(

+ 2 - 1
modules/boonex/ads/install/sql/install.sql

@@ -263,6 +263,7 @@ CREATE TABLE IF NOT EXISTS `bx_ads_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -533,7 +534,7 @@ INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `
 ('bx_ads_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 ('bx_ads_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 
-('bx_ads_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_ads_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_ads_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_ads_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_videos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 
 ('bx_ads_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_ads_files', 'deny-allow', '', 'action,apk,app,bat,bin,cmd,com,command,cpl,csh,exe,gadget,inf,ins,inx,ipa,isu,job,jse,ksh,lnk,msc,msi,msp,mst,osx,out,paf,pif,prg,ps1,reg,rgs,run,sct,shb,shs,u3p,vb,vbe,vbs,vbscript,workflow,ws,wsf', 0, 0, 0, 0, 0, 0);

+ 2 - 2
modules/boonex/albums/classes/BxAlbumsModule.php

@@ -882,10 +882,10 @@ class BxAlbumsModule extends BxBaseModTextModule
                 continue;
 
             $sVideoUrl = $oStorage->getFileUrlById($aMedia['file_id']);
-            $aVideoSize = $oTcMp4Hd->getVideoSize($sVideoUrl);
+            $aVideoFile = $oStorage->getFile($aMedia['file_id']);
 
             $sVideoUrlHd = '';
-            if(!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+            if (!empty($aVideoFile['dimensions']) && $oTcMp4Hd->isProcessHD($aVideoFile['dimensions']))
                 $sVideoUrlHd = $oTcMp4Hd->getFileUrl($aMedia['file_id']);
 
             $aOutput[$aMedia['id']] = array(

+ 2 - 2
modules/boonex/albums/classes/BxAlbumsTemplate.php

@@ -286,10 +286,10 @@ class BxAlbumsTemplate extends BxBaseModTextTemplate
             $sVideoDuration = _t_format_duration($iVideoDuration);
 
             $sVideoUrl = $oStorage->getFileUrlById($aMediaInfo['file_id']);
-            $aVideoSize = $aTranscodersVideo['mp4_hd']->getVideoSize($sVideoUrl);
+            $aVideoFile = $oStorage->getFile($aMediaInfo['file_id']);
 
             $sVideoUrlHd = '';
-            if(!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+            if (!empty($aVideoFile['dimensions']) && $aTranscodersVideo['mp4_hd']->isProcessHD($aVideoFile['dimensions']))
                 $sVideoUrlHd = $aTranscodersVideo['mp4_hd']->getFileUrl($aMediaInfo['file_id']);
 
             $aTmplVarsVideo = array (

+ 2 - 1
modules/boonex/albums/install/sql/install.sql

@@ -38,6 +38,7 @@ CREATE TABLE IF NOT EXISTS `bx_albums_files` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `duration` int(11) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
@@ -349,7 +350,7 @@ CREATE TABLE IF NOT EXISTS `bx_albums_scores_media_track` (
 SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
 
 INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
-('bx_albums_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_albums_files', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_albums_files', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_albums_files', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_albums_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_albums_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0);
 
 INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES

+ 2 - 1
modules/boonex/classes/install/sql/install.sql

@@ -134,6 +134,7 @@ CREATE TABLE IF NOT EXISTS `bx_classes_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -403,7 +404,7 @@ INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `
 ('bx_classes_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_classes_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 ('bx_classes_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_classes_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 
-('bx_classes_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_classes_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_classes_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_classes_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_classes_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_classes_videos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 
 ('bx_classes_sounds', @sStorageEngine, '', 360, 2592000, 3, 'bx_classes_sounds', 'allow-deny', 'mp3,m4a,m4b,wma,wav,3gp', '', 0, 0, 0, 0, 0, 0),

+ 2 - 1
modules/boonex/forum/install/sql/install.sql

@@ -118,6 +118,7 @@ CREATE TABLE IF NOT EXISTS `bx_forum_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -363,7 +364,7 @@ INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `
 ('bx_forum_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_forum_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 ('bx_forum_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_forum_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 
-('bx_forum_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_forum_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_forum_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_forum_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_forum_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_forum_videos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 
 ('bx_forum_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_forum_files', 'deny-allow', '', 'action,apk,app,bat,bin,cmd,com,command,cpl,csh,exe,gadget,inf,ins,inx,ipa,isu,job,jse,ksh,lnk,msc,msi,msp,mst,osx,out,paf,pif,prg,ps1,reg,rgs,run,sct,shb,shs,u3p,vb,vbe,vbs,vbscript,workflow,ws,wsf', 0, 0, 0, 0, 0, 0),

+ 36 - 7
modules/boonex/help_tours/classes/BxHelpToursDb.php

@@ -66,14 +66,17 @@ class BxHelpToursDb extends BxDolModuleDb
         return $aData;
     }
 
-    public function putHelpTourOnPage($iTourId, $sOldPage) {
+    public function putHelpTourOnPage($iTourId, $sOldPage, $iPageBlockVisibility) {
         $aTour = $this->getTourDetails($iTourId);
         $sPage = $aTour['page'];
 
+        $sServiceCall = str_replace('__tour_id__', $iTourId, $this->_sTourBlockTemplate);
+
         if ($sOldPage != $sPage) {
             if (!empty($sOldPage)) {
-                $this->query("DELETE FROM `sys_pages_blocks` WHERE `object` = :page AND `module` = 'bx_help_tours'", [
+                $this->query("DELETE FROM `sys_pages_blocks` WHERE `object` = :page AND `module` = 'bx_help_tours' AND `content` = :service_call", [
                     'page' => $sOldPage,
+                    'service_call' => $sServiceCall,
                 ]);
             }
 
@@ -81,24 +84,39 @@ class BxHelpToursDb extends BxDolModuleDb
 
             $this->query("
                 INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
-                (:page, 1, 'bx_help_tours', '_bx_help_tours_page_block_caption', 0, 2147483647, 'service', :service_call, 0, 0, :order);
+                (:page, 1, 'bx_help_tours', '_bx_help_tours_page_block_caption', 0, :visibility, 'service', :service_call, 0, 0, :order);
             ", [
                 'page' => $sPage,
-                'service_call' => str_replace('__tour_id__', $iTourId, $this->_sTourBlockTemplate),
+                'service_call' => $sServiceCall,
                 'order' => $iOrder,
+                'visibility' => $iPageBlockVisibility,
+            ]);
+
+            // disable the built-in site tour on homepage to avoid tours conflicts
+            if ($sPage == 'sys_home') setParam('site_tour_home', '');
+        } else {
+            $this->query("UPDATE `sys_pages_blocks` SET `visible_for_levels` = :visibility WHERE `object` = :page AND `module` = 'bx_help_tours' AND `content` = :service_call", [
+                'page' => $sPage,
+                'service_call' => $sServiceCall,
+                'visibility' => $iPageBlockVisibility,
             ]);
         }
     }
 
-    function deleteHelpTourBlock($iTourId) {
+    public function deleteHelpTourBlock($iTourId) {
         $aTour = $this->getTourDetails($iTourId);
 
-        $this->query("DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_help_tours' AND `object` = :page", [
+        $this->query("DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_help_tours' AND `object` = :page AND `content` = :call", [
             'page' => $aTour['page'],
+            'call' => str_replace('__tour_id__', $iTourId, $this->_sTourBlockTemplate),
         ]);
     }
 
-    function getHelpTourItemsCount($iTourId) {
+    public function deleteHelpTourTrackingData($iTourId) {
+        $this->query("DELETE FROM `bx_help_tours_track_views` WHERE `tour` = :tour", ['tour' => $iTourId]);
+    }
+
+    public function getHelpTourItemsCount($iTourId) {
         return $this->getOne("SELECT COUNT(*) FROM `bx_help_tours_items` WHERE `tour` = :tour", [
             'tour' => $iTourId,
         ]);
@@ -143,8 +161,19 @@ class BxHelpToursDb extends BxDolModuleDb
     }
 
     public function isHelpTourSeen($iAccount, $iTour) {
+        if (isset($_COOKIE['bx-help-tours-seen-'.$iTour])) return true;
+        if (!$iAccount) return false;
         return $this->getOne("SELECT COUNT(*) FROM `bx_help_tours_track_views` WHERE `account` = :account AND `tour` = :tour", ['account' => $iAccount, 'tour' => $iTour]);
     }
+
+    public function getTourVisibility($iTour) {
+        $aTour = $this->getTourDetails($iTour);
+
+        return $this->getOne("SELECT `visible_for_levels` FROM `sys_pages_blocks` WHERE `module` = 'bx_help_tours' AND `object` = :page AND `content` = :call", [
+            'page' => $aTour['page'],
+            'call' => str_replace('__tour_id__', $iTour, $this->_sTourBlockTemplate),
+        ]);
+    }
 }
 
 /** @} */

+ 35 - 3
modules/boonex/help_tours/classes/BxHelpToursGridTours.php

@@ -9,6 +9,8 @@
  * @{
  */
 
+bx_import('BxDolStudioUtils');
+
 class BxHelpToursGridTours extends BxTemplGrid
 {
     public function __construct ($aOptions, $oTemplate = false)
@@ -60,7 +62,10 @@ class BxHelpToursGridTours extends BxTemplGrid
             }
         }
 
-        $oForm = $this->getAddEditFormObject($iEntry);
+        $iTourVisibility = !$iEntry ? BX_DOL_INT_MAX : $this->_oModule->_oDb->getTourVisibility($iEntry);
+        if (bx_get('visible_for'))
+            $iTourVisibility = BxDolStudioUtils::getVisibilityValue(bx_get('visible_for'), bx_get('visible_for_levels'));
+        $oForm = $this->getAddEditFormObject($iEntry, $iTourVisibility);
 
         $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT.'grid.php?o=' . $this->_sObject . '&a='.($aEntry ? 'edit' : 'add');
 
@@ -75,7 +80,7 @@ class BxHelpToursGridTours extends BxTemplGrid
             }
 
             if ($iResult) {
-                $this->_oModule->_oDb->putHelpTourOnPage($iResult, $aEntry ? $aEntry['page'] : '');
+                $this->_oModule->_oDb->putHelpTourOnPage($iResult, $aEntry ? $aEntry['page'] : '', $iTourVisibility);
                 $aRes = ['grid' => $this->getCode(false), 'blink' => $iResult];
             } else {
                 $aRes = ['msg' => "Error occured"]; // if record adding failed, display error message
@@ -102,6 +107,7 @@ class BxHelpToursGridTours extends BxTemplGrid
             echoJson(['popup' => [
                 'html' => BxTemplStudioFunctions::getInstance()->popupBox('bx-tour-details-popup', _t('_bx_help_tours_cpt_tour_details'), $s),
                 'options' => [
+                    'onBeforeShow' => empty($aEntry) ? "$('#grid-popup-bx_help_tours_tours-edit').remove();" : "$('#grid-popup-bx_help_tours_tours-add').remove();",
                     'closeOnOuterClick' => false,
                 ]]]
             );
@@ -149,6 +155,7 @@ class BxHelpToursGridTours extends BxTemplGrid
 
         foreach ($aIds as $iEntry) {
             $this->_oModule->_oDb->deleteHelpTourBlock($iEntry);
+            $this->_oModule->_oDb->deleteHelpTourTrackingData($iEntry);
 
             $aItems = $this->_oModule->_oDb->getHelpTourItems($iEntry);
             if ($aItems) foreach ($aItems as $aItem) {
@@ -165,7 +172,7 @@ class BxHelpToursGridTours extends BxTemplGrid
         ));
     }
 
-    private function getAddEditFormObject($iEntry) {
+    private function getAddEditFormObject($iEntry, $iVisibility = BX_DOL_INT_MAX) {
         $aForm = [
             'form_attrs' => [
                 'method' => 'post',
@@ -211,6 +218,29 @@ class BxHelpToursGridTours extends BxTemplGrid
                         'pass' => 'Int',
                     ],
                 ],
+                'visible_for' => [
+                    'type' => 'select',
+                    'name' => 'visible_for',
+                    'caption' => _t('_bx_help_tours_form_field_visible_for'),
+                    'value' => $iVisibility == BX_DOL_INT_MAX ? BX_DOL_STUDIO_VISIBLE_ALL : BX_DOL_STUDIO_VISIBLE_SELECTED,
+                    'values' => [
+                        ['key' => BX_DOL_STUDIO_VISIBLE_ALL, 'value' => _t('_bx_help_tours_form_field_visible_for_all')],
+                        ['key' => BX_DOL_STUDIO_VISIBLE_SELECTED, 'value' => _t('_bx_help_tours_form_field_visible_for_selected')],
+                    ],
+                    'attrs' => [
+                        'onchange' => "$('#bx-form-element-visible_for_levels').bx_anim(this.value == 'all' ? 'hide' : 'show')",
+                    ],
+                ],
+                'visible_for_levels' => [
+                    'type' => 'checkbox_set',
+                    'name' => 'visible_for_levels',
+                    'caption' => _t('_bx_help_tours_form_field_visible_for_levels'),
+                    'value' => '',
+                    'values' => [],
+                    'tr_attrs' => [
+                        'style' => $iVisibility == BX_DOL_INT_MAX ? 'display:none' : ''
+                    ],
+                ],
                 'actions' => [
                     'type' => 'input_set',
                     0 => [
@@ -230,6 +260,8 @@ class BxHelpToursGridTours extends BxTemplGrid
                 ],
             ],
         ];
+        BxDolStudioUtils::getVisibilityValues($iVisibility, $aForm['inputs']['visible_for_levels']['values'], $aForm['inputs']['visible_for_levels']['value']);
+
         return new BxTemplFormView($aForm);
     }
 }

+ 7 - 1
modules/boonex/help_tours/classes/BxHelpToursModule.php

@@ -17,7 +17,12 @@ class BxHelpToursModule extends BxDolModule
     }
 
     public function serviceGetHelpTour($iTourId) {
-        if (!isLogged() || !$iTourId) return;
+        static $_bAlreadyPlacedATour;
+
+        // avoid running multiple tours at once on a single page
+        if ($_bAlreadyPlacedATour) return;
+
+        if (!$iTourId) return;
 
         $aTour = $this->_oDb->getTourDetails($iTourId);
         if (!$aTour) return;
@@ -27,6 +32,7 @@ class BxHelpToursModule extends BxDolModule
 
         if ((!isAdmin() || !bx_get('help_tour_preview')) && $this->_oDb->isHelpTourSeen(getLoggedId(), $iTourId)) return;
 
+        $_bAlreadyPlacedATour = true;
         return $this->_oTemplate->getHelpTourCode($aTour, $aHelpTourItems);
     }
 

+ 0 - 1
modules/boonex/help_tours/classes/BxHelpToursTemplate.php

@@ -29,7 +29,6 @@ class BxHelpToursTemplate extends BxBaseModGeneralTemplate
             $aStep = [
                 'id' => 'bx-help-tour-step-'.$aItem['id'],
                 'text' => _t($aItem['text']),
-                'attachTo' => ['element' => $aItem['element'], 'on' => $aItem['arrow']],
             ];
 
             if ($aItem['title']) $aStep['title'] = _t($aItem['title']);

+ 4 - 0
modules/boonex/help_tours/install/langs/en.xml

@@ -49,4 +49,8 @@
 	<string name="_bx_help_tours_form_field_option_custom"><![CDATA[Custom]]></string>
 
 	<string name="_bx_help_tours_page_block_caption"><![CDATA[Help Tour]]></string>
+	<string name="_bx_help_tours_form_field_visible_for"><![CDATA[Visible For]]></string>
+	<string name="_bx_help_tours_form_field_visible_for_levels"><![CDATA[Select Levels]]></string>
+	<string name="_bx_help_tours_form_field_visible_for_all"><![CDATA[Anyone]]></string>
+	<string name="_bx_help_tours_form_field_visible_for_selected"><![CDATA[Selected levels]]></string>
 </resources>

+ 11 - 11
modules/boonex/help_tours/template/images/icons/std-icon.svg

@@ -1,16 +1,16 @@
-<svg width="150" height="150" viewBox="0 0 150 150" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M0 75C0 18.75 18.75 0 75 0C131.25 0 150 18.75 150 75C150 131.25 131.25 150 75 150C18.75 150 0 131.25 0 75Z" fill="url(#paint0_linear)"/>
+<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0 256C0 64 64 0 256 0C448 0 512 64 512 256C512 448 448 512 256 512C64 512 0 448 0 256Z" fill="url(#paint0_linear)"/>
 <g filter="url(#filter0_d)">
-<path d="M101.46 79.5407C108.165 86.246 107.442 97.5539 99.3006 103.272C94.1194 106.909 86.8823 106.909 81.7011 103.272C73.5549 97.5591 72.8368 86.246 79.5419 79.5407C85.5961 73.4864 95.4108 73.4864 101.46 79.5407" stroke="white" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M112 112L102 102" stroke="white" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M50.26 48.96C50.248 48.96 50.24 48.968 50.24 48.98C50.24 48.992 50.248 49 50.26 49C50.272 49 50.28 48.992 50.28 48.98C50.28 48.968 50.272 48.96 50.26 48.96" stroke="#F3F4F6" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M60.432 48.96C60.42 48.96 60.412 48.968 60.412 48.98C60.412 48.992 60.424 49 60.432 49C60.444 49 60.452 48.992 60.452 48.98C60.452 48.968 60.444 48.96 60.432 48.96" stroke="#F3F4F6" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M70.588 48.96C70.576 48.96 70.568 48.968 70.568 48.98C70.568 48.992 70.576 49 70.588 49C70.6 49 70.608 48.992 70.608 48.98C70.608 48.968 70.6 48.96 70.588 48.96" stroke="#F3F4F6" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M111 71V47C111 42.58 107.42 39 103 39H47C42.58 39 39 42.58 39 47V103C39 107.42 42.58 111 47 111H71" stroke="#F3F4F6" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M39.144 59H111" stroke="#F3F4F6" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M373.599 276.181C403.4 305.982 400.185 356.24 364.003 381.655C340.975 397.819 308.81 397.819 285.783 381.655C249.577 356.263 246.386 305.982 276.186 276.181C303.094 249.273 346.715 249.273 373.599 276.181" stroke="white" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M408.444 408.444L376 376" stroke="white" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M146.044 140.267C145.991 140.267 145.956 140.302 145.956 140.356C145.956 140.409 145.991 140.444 146.044 140.444C146.098 140.444 146.133 140.409 146.133 140.356C146.133 140.302 146.098 140.267 146.044 140.267" stroke="#D1FAE5" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M191.253 140.267C191.2 140.267 191.164 140.302 191.164 140.356C191.164 140.409 191.218 140.444 191.253 140.444C191.307 140.444 191.342 140.409 191.342 140.356C191.342 140.302 191.307 140.267 191.253 140.267" stroke="#D1FAE5" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M236.391 140.267C236.338 140.267 236.302 140.302 236.302 140.356C236.302 140.409 236.338 140.444 236.391 140.444C236.445 140.444 236.48 140.409 236.48 140.356C236.48 140.302 236.445 140.267 236.391 140.267" stroke="#D1FAE5" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M416 238.222V131.556C416 111.911 400.089 96 380.444 96H131.556C111.911 96 96 111.911 96 131.556V380.444C96 400.089 111.911 416 131.556 416H238.222" stroke="#D1FAE5" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M96.6401 184.889H416" stroke="#D1FAE5" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
 </g>
 <defs>
-<filter id="filter0_d" x="34" y="35" width="83" height="83" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<filter id="filter0_d" x="78" y="79" width="356" height="356" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
 <feFlood flood-opacity="0" result="BackgroundImageFix"/>
 <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
 <feOffset dy="1"/>
@@ -19,7 +19,7 @@
 <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
 <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
 </filter>
-<linearGradient id="paint0_linear" x1="75" y1="0" x2="75" y2="150" gradientUnits="userSpaceOnUse">
+<linearGradient id="paint0_linear" x1="256" y1="0" x2="256" y2="512" gradientUnits="userSpaceOnUse">
 <stop stop-color="#10B981"/>
 <stop offset="1" stop-color="#059669"/>
 </linearGradient>

+ 16 - 13
modules/boonex/help_tours/template/tour.html

@@ -10,6 +10,7 @@
 
     <bx_if:not_preview>
     Shepherd.on('cancel', function () {
+        $.cookie('bx-help-tours-seen-__tour_id__', 1, {expires: 9999});
         $.post('__finish_callback_url__', {tour: __tour_id__});
     })
     </bx_if:not_preview>
@@ -17,22 +18,24 @@
     var bx_help_tour_steps =  __steps__;
     var bx_help_tour_steps_filtered = [];
     for (i in bx_help_tour_steps) {
-        //do not show help items for missing elements.
-        if (bx_help_tour_steps[i].attachTo.element.length && !$(bx_help_tour_steps[i].attachTo.element).length) continue;
+        if (typeof bx_help_tour_steps[i].attachTo !== 'undefined' && bx_help_tour_steps[i].attachTo.element.length) {
+            //do not show help items for missing elements.
+            if (!$(bx_help_tour_steps[i].attachTo.element).length) continue;
 
-        // if this is a help for a field that is sitting inside a collapsed section then
-        // we are `uncollapsing` it on this page load
-        if (!$(bx_help_tour_steps[i].attachTo.element).is(':visible')) {
-            var sect = $(bx_help_tour_steps[i].attachTo.element).closest('.bx-form-section-hidden');
-            if (sect.length && sect.hasClass('bx-form-section-hidden')) {
-                $(sect).children('legend').trigger('click');
-                sect.removeClass('bx-form-collapsed');
-                sect.removeClass('bx-form-section-hidden');
+            // if this is a help for a field that is sitting inside a collapsed section then
+            // we are `uncollapsing` it on this page load
+            if (!$(bx_help_tour_steps[i].attachTo.element).is(':visible')) {
+                var sect = $(bx_help_tour_steps[i].attachTo.element).closest('.bx-form-section-hidden');
+                if (sect.length && sect.hasClass('bx-form-section-hidden')) {
+                    $(sect).children('legend').trigger('click');
+                    sect.removeClass('bx-form-collapsed');
+                    sect.removeClass('bx-form-section-hidden');
+                }
             }
-        }
 
-        //do not process hidden elements
-        if (!$(bx_help_tour_steps[i].attachTo.element).is(':visible')) continue;
+            //do not process hidden elements
+            if (!$(bx_help_tour_steps[i].attachTo.element).is(':visible')) continue;
+        }
 
         bx_help_tour_steps_filtered.push(bx_help_tour_steps[i]);
     }

+ 2 - 1
modules/boonex/posts/install/sql/install.sql

@@ -106,6 +106,7 @@ CREATE TABLE IF NOT EXISTS `bx_posts_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -385,7 +386,7 @@ INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `
 ('bx_posts_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 ('bx_posts_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 
-('bx_posts_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_posts_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_posts_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_videos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 
 ('bx_posts_sounds', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_sounds', 'allow-deny', 'mp3,m4a,m4b,wma,wav,3gp', '', 0, 0, 0, 0, 0, 0),

+ 3 - 2
modules/boonex/reviews/install/sql/install.sql

@@ -112,6 +112,7 @@ CREATE TABLE IF NOT EXISTS `bx_reviews_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -387,7 +388,7 @@ INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `
 ('bx_reviews_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_reviews_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 ('bx_reviews_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_reviews_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 
-('bx_reviews_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_reviews_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_reviews_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_reviews_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_reviews_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_reviews_videos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 
 ('bx_reviews_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_reviews_files', 'deny-allow', '', 'action,apk,app,bat,bin,cmd,com,command,cpl,csh,exe,gadget,inf,ins,inx,ipa,isu,job,jse,ksh,lnk,msc,msi,msp,mst,osx,out,paf,pif,prg,ps1,reg,rgs,run,sct,shb,shs,u3p,vb,vbe,vbs,vbscript,workflow,ws,wsf', 0, 0, 0, 0, 0, 0);
@@ -629,4 +630,4 @@ SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE
 INSERT INTO `sys_std_widgets` (`page_id`, `module`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
 (@iPageId, 'bx_reviews', 'content', '{url_studio}module.php?name=bx_reviews', '', 'bx_reviews@modules/boonex/reviews/|std-icon.svg', '_bx_reviews', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
 INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
-(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));

+ 4 - 0
modules/boonex/russian/data/langs/bx_help_tours/ru.xml

@@ -49,4 +49,8 @@
 	<string name="_bx_help_tours_form_field_option_custom"><![CDATA[Пользовательский]]></string>
 
 	<string name="_bx_help_tours_page_block_caption"><![CDATA[Тур Помощи]]></string>
+	<string name="_bx_help_tours_form_field_visible_for"><![CDATA[Видимо для]]></string>
+	<string name="_bx_help_tours_form_field_visible_for_levels"><![CDATA[Выбрать уровни]]></string>
+	<string name="_bx_help_tours_form_field_visible_for_all"><![CDATA[Всех]]></string>
+	<string name="_bx_help_tours_form_field_visible_for_selected"><![CDATA[Выбранные уровни]]></string>
 </resources>

+ 2 - 1
modules/boonex/tasks/install/sql/install.sql

@@ -128,6 +128,7 @@ CREATE TABLE IF NOT EXISTS `bx_tasks_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -311,7 +312,7 @@ INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `
 ('bx_tasks_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_tasks_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 ('bx_tasks_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_tasks_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 
-('bx_tasks_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_tasks_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_tasks_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_tasks_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_tasks_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_tasks_videos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 
 ('bx_tasks_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_tasks_files', 'deny-allow', '', 'action,apk,app,bat,bin,cmd,com,command,cpl,csh,exe,gadget,inf,ins,inx,ipa,isu,job,jse,ksh,lnk,msc,msi,msp,mst,osx,out,paf,pif,prg,ps1,reg,rgs,run,sct,shb,shs,u3p,vb,vbe,vbs,vbscript,workflow,ws,wsf', 0, 0, 0, 0, 0, 0);

+ 2 - 2
modules/boonex/timeline/classes/BxTimelineModule.php

@@ -3910,10 +3910,10 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         $aResult = array();
         foreach($aVideos as $iVideoId) {
             $sVideoUrl = $oStorage->getFileUrlById($iVideoId);
-            $aVideoSize = $oTranscoderMp4Hd->getVideoSize($sVideoUrl);
+            $aVideoFile = $oStorage->getFile($iVideoId);
 
             $sVideoUrlHd = '';
-            if(!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+            if (!empty($aVideoFile['dimensions']) && $oTranscoderMp4Hd->isProcessHD($aVideoFile['dimensions']))
                 $sVideoUrlHd = $oTranscoderMp4Hd->getFileUrl($iVideoId);
 
             $aResult[$iVideoId] = array(

+ 2 - 1
modules/boonex/timeline/install/sql/install.sql

@@ -133,6 +133,7 @@ CREATE TABLE IF NOT EXISTS `bx_timeline_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -354,7 +355,7 @@ INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `
 ('bx_timeline_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 ('bx_timeline_photos_processed', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_photos_processed', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
 
-('bx_timeline_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_timeline_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_timeline_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_timeline_videos_processed', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_videos_processed', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0);
 
 INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES

+ 2 - 2
modules/boonex/videos/classes/BxVideosModule.php

@@ -122,10 +122,10 @@ class BxVideosModule extends BxBaseModTextModule
             $sPoster = $oTcvPoster->getFileUrl($iFile);
 
         $sVideoUrl = $oStorage->getFileUrlById($iFile);
-        $aVideoSize = $oTcvMp4Hd->getVideoSize($sVideoUrl);
+        $aVideoFile = $oStorage->getFile($iFile);
 
         $sVideoUrlHd = '';
-        if(!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+        if (!empty($aVideoFile['dimensions']) && $oTcvMp4Hd->isProcessHD($aVideoFile['dimensions']))
             $sVideoUrlHd = $oTcvMp4Hd->getFileUrl($iFile);
 
         return array(

+ 2 - 2
modules/boonex/videos/classes/BxVideosTemplate.php

@@ -101,10 +101,10 @@ class BxVideosTemplate extends BxBaseModTextTemplate
             $sPoster = $aTranscodersVideo['poster']->getFileUrl($iFile);
 
         $sVideoUrl = $oStorage->getFileUrlById($iFile);
-        $aVideoSize = $aTranscodersVideo['mp4_hd']->getVideoSize($sVideoUrl);
+        $aVideoFile = $oStorage->getFile($iFile);
 
         $sVideoUrlHd = '';
-        if(!empty($aVideoSize) && is_array($aVideoSize) && (int)$aVideoSize['h'] >= 720)
+        if (!empty($aVideoFile['dimensions']) && $aTranscodersVideo['mp4_hd']->isProcessHD($aVideoFile['dimensions']))
             $sVideoUrlHd = $aTranscodersVideo['mp4_hd']->getFileUrl($iFile);
 
         return array(

+ 2 - 1
modules/boonex/videos/install/sql/install.sql

@@ -61,6 +61,7 @@ CREATE TABLE IF NOT EXISTS `bx_videos_videos` (
   `mime_type` varchar(128) NOT NULL,
   `ext` varchar(32) NOT NULL,
   `size` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
   `added` int(11) NOT NULL,
   `modified` int(11) NOT NULL,
   `private` int(11) NOT NULL,
@@ -282,7 +283,7 @@ SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_sto
 
 INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
 ('bx_videos_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_videos_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
-('bx_videos_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_videos_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
+('bx_videos_videos', @sStorageEngine, 'a:1:{s:6:"fields";a:1:{s:10:"dimensions";s:17:"getFileDimensions";}}', 360, 2592000, 3, 'bx_videos_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0),
 ('bx_videos_media_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_videos_media_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 0, 0, 0, 0, 0, 0);
 
 INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES