Improved media providers
authorMarcel Werk <burntime@woltlab.com>
Wed, 1 Mar 2017 16:31:25 +0000 (17:31 +0100)
committerMarcel Werk <burntime@woltlab.com>
Wed, 1 Mar 2017 16:31:25 +0000 (17:31 +0100)
* added ability to specify a class name that is used as a callback
* improved support for embedding youtube videos at a certain timestamp
* improved vimeo-support

Closes #2211

wcfsetup/install/files/acp/templates/bbcodeMediaProviderAdd.tpl
wcfsetup/install/files/lib/acp/form/BBCodeMediaProviderAddForm.class.php
wcfsetup/install/files/lib/acp/form/BBCodeMediaProviderEditForm.class.php
wcfsetup/install/files/lib/data/bbcode/media/provider/BBCodeMediaProvider.class.php
wcfsetup/install/files/lib/system/bbcode/media/provider/IBBCodeMediaProvider.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/bbcode/media/provider/YouTubeBBCodeMediaProvider.class.php [new file with mode: 0644]
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index cd40ed03ab3101d3c114756774f25437ef48b6f5..b4ae4ba487a643c8b678132eced5dcb013d4b60f 100644 (file)
@@ -41,7 +41,7 @@
                <dl{if $errorField == 'regex'} class="formError"{/if}>
                        <dt><label for="regex">{lang}wcf.acp.bbcode.mediaProvider.regex{/lang}</label></dt>
                        <dd>
-                               <textarea id="regex" name="regex" cols="40" rows="10" required>{$regex}</textarea>
+                               <textarea id="regex" name="regex" cols="40" rows="5" required>{$regex}</textarea>
                                {if $errorField == 'regex'}
                                        <small class="innerError">
                                                {if $errorType == 'empty'}
@@ -58,7 +58,7 @@
                <dl{if $errorField == 'html'} class="formError"{/if}>
                        <dt><label for="html">{lang}wcf.acp.bbcode.mediaProvider.html{/lang}</label></dt>
                        <dd>
-                               <textarea id="html" name="html" cols="40" rows="10" required>{$html}</textarea>
+                               <textarea id="html" name="html" cols="40" rows="10">{$html}</textarea>
                                {if $errorField == 'html'}
                                        <small class="innerError">
                                                {if $errorType == 'empty'}
                        </dd>
                </dl>
                
+               <dl{if $errorField == 'className'} class="formError"{/if}>
+                       <dt><label for="className">{lang}wcf.acp.bbcode.mediaProvider.className{/lang}</label></dt>
+                       <dd>
+                               <input type="text" id="className" name="className" value="{$className}" pattern="^\\?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\)*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$" class="long">
+                               {if $errorField == 'className'}
+                                       <small class="innerError">
+                                               {if $errorType == 'empty'}
+                                                       {lang}wcf.global.form.error.empty{/lang}
+                                               {else}
+                                                       {lang}wcf.acp.bbcode.mediaProvider.className.error.{@$errorType}{/lang}
+                                               {/if}
+                                       </small>
+                               {/if}
+                       </dd>
+               </dl>
+               
                {event name='dataFields'}
        </div>
        
index eade72a64b82515e96b295872a84c32a3a9b183f..810c7a62f7062d724d9920dfb0782c9d9c0d02a6 100644 (file)
@@ -21,6 +21,12 @@ class BBCodeMediaProviderAddForm extends AbstractForm {
         */
        public $activeMenuItem = 'wcf.acp.menu.link.bbcode.mediaProvider.add';
        
+       /**
+        * media provider class name
+        * @var string
+        */
+       public $className = '';
+       
        /**
         * html value
         * @var string
@@ -58,6 +64,7 @@ class BBCodeMediaProviderAddForm extends AbstractForm {
                if (isset($_POST['title'])) $this->title = StringUtil::trim($_POST['title']);
                if (isset($_POST['regex'])) $this->regex = StringUtil::trim($_POST['regex']);
                if (isset($_POST['html'])) $this->html = StringUtil::trim($_POST['html']);
+               if (isset($_POST['className'])) $this->className = StringUtil::trim($_POST['className']);
        }
        
        /**
@@ -73,9 +80,13 @@ class BBCodeMediaProviderAddForm extends AbstractForm {
                if (empty($this->regex)) {
                        throw new UserInputException('regex');
                }
-               if (empty($this->html)) {
+               if (empty($this->className) && empty($this->html)) {
                        throw new UserInputException('html');
                }
+               // validate class name
+               if (!empty($this->className) && !class_exists($this->className)) {
+                       throw new UserInputException('className', 'notFound');
+               }
                
                $lines = explode("\n", StringUtil::unifyNewlines($this->regex));
                
@@ -94,13 +105,14 @@ class BBCodeMediaProviderAddForm extends AbstractForm {
                $this->objectAction = new BBCodeMediaProviderAction([], 'create', ['data' => array_merge($this->additionalFields, [
                        'title' => $this->title,
                        'regex' => $this->regex,
-                       'html' => $this->html
+                       'html' => $this->html,
+                       'className' => $this->className
                ])]);
                $this->objectAction->executeAction();
                $this->saved();
                
                // reset values
-               $this->title = $this->regex = $this->html = '';
+               $this->title = $this->regex = $this->html = $this->className = '';
                
                // show success message
                WCF::getTPL()->assign('success', true);
@@ -116,7 +128,8 @@ class BBCodeMediaProviderAddForm extends AbstractForm {
                        'action' => 'add',
                        'title' => $this->title,
                        'regex' => $this->regex,
-                       'html' => $this->html
+                       'html' => $this->html,
+                       'className' => $this->className
                ]);
        }
 }
index a01f939d5be91c2a0cb9fcea76441d54c90cba42..0c302a3fa07667f6eed7d196bdaaa66f8cc90754 100644 (file)
@@ -60,7 +60,8 @@ class BBCodeMediaProviderEditForm extends BBCodeMediaProviderAddForm {
                $this->objectAction = new BBCodeMediaProviderAction([$this->providerID], 'update', ['data' => array_merge($this->additionalFields, [
                        'title' => $this->title,
                        'regex' => $this->regex,
-                       'html' => $this->html
+                       'html' => $this->html,
+                       'className' => $this->className
                ])]);
                $this->objectAction->executeAction();
                
@@ -80,6 +81,7 @@ class BBCodeMediaProviderEditForm extends BBCodeMediaProviderAddForm {
                        $this->title = $this->mediaProvider->title;
                        $this->regex = $this->mediaProvider->regex;
                        $this->html = $this->mediaProvider->html;
+                       $this->className = $this->mediaProvider->className;
                }
        }
        
index f57bae3cb50327492bf52d9d2851040325ad92f0..caec8b4756b7f8da7e8251512d74acf3af3b9d39 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace wcf\data\bbcode\media\provider;
 use wcf\data\DatabaseObject;
+use wcf\system\bbcode\media\provider\IBBCodeMediaProvider;
 use wcf\system\cache\builder\BBCodeMediaProviderCacheBuilder;
 use wcf\system\request\IRouteController;
 use wcf\system\Regex;
@@ -18,6 +19,7 @@ use wcf\util\StringUtil;
  * @property-read      string          $title          title of the bbcode media provider (shown in acp)
  * @property-read      string          $regex          regular expression to recognize media elements/element urls
  * @property-read      string          $html           html code used to render media elements
+ * @property-read      string          $className      callback class name                            
  */
 class BBCodeMediaProvider extends DatabaseObject implements IRouteController {
        /**
@@ -31,6 +33,12 @@ class BBCodeMediaProvider extends DatabaseObject implements IRouteController {
         */
        protected static $cache = null;
        
+       /**
+        * media provider callback instance
+        * @var IBBCodeMediaProvider
+        */
+       protected $callback;
+       
        /**
         * Loads the provider cache.
         * 
@@ -89,11 +97,16 @@ class BBCodeMediaProvider extends DatabaseObject implements IRouteController {
                        $regex = new Regex($line);
                        if (!$regex->match($url)) continue;
                        
-                       $output = $this->html;
-                       foreach ($regex->getMatches() as $name => $value) {
-                               $output = str_replace('{$'.$name.'}', $value, $output);
+                       if ($this->getCallback() !== null) {
+                               return $this->getCallback()->parse($url, $regex->getMatches());
+                       }
+                       else {
+                               $output = $this->html;
+                               foreach ($regex->getMatches() as $name => $value) {
+                                       $output = str_replace('{$' . $name . '}', $value, $output);
+                               }
+                               return $output;
                        }
-                       return $output;
                }
                
                return '';
@@ -105,4 +118,19 @@ class BBCodeMediaProvider extends DatabaseObject implements IRouteController {
        public function getTitle() {
                return $this->title;
        }
+       
+       /**
+        * Returns media provider callback instance.
+        * 
+        * @return      IBBCodeMediaProvider
+        */
+       public function getCallback() {
+               if (!$this->className) return null;
+               
+               if ($this->callback === null) {
+                       $this->callback = new $this->className;
+               }
+               
+               return $this->callback;
+       }
 }
diff --git a/wcfsetup/install/files/lib/system/bbcode/media/provider/IBBCodeMediaProvider.class.php b/wcfsetup/install/files/lib/system/bbcode/media/provider/IBBCodeMediaProvider.class.php
new file mode 100644 (file)
index 0000000..45f2655
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+namespace wcf\system\bbcode\media\provider;
+
+/**
+ * Interface for media provider callbacks.
+ *
+ * @author     Marcel Werk
+ * @copyright  2001-2017 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Bbcode\Media\Provider
+ */
+interface IBBCodeMediaProvider {
+       /**
+        * Parses given media url and returns output html.
+        * 
+        * @param       string          $url            media url
+        * @param       string[]        $matches
+        * @return      string          output html
+        */
+       public function parse($url, array $matches = []);
+}
diff --git a/wcfsetup/install/files/lib/system/bbcode/media/provider/YouTubeBBCodeMediaProvider.class.php b/wcfsetup/install/files/lib/system/bbcode/media/provider/YouTubeBBCodeMediaProvider.class.php
new file mode 100644 (file)
index 0000000..6067bd8
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+namespace wcf\system\bbcode\media\provider;
+
+/**
+ * Media provider callback for YouTube urls.
+ *
+ * @author     Marcel Werk
+ * @copyright  2001-2017 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Bbcode\Media\Provider
+ */
+class YouTubeBBCodeMediaProvider implements IBBCodeMediaProvider {
+       /**
+        * @inheritDoc
+        */
+       public function parse($url, array $matches = []) {
+               $start = 0;
+               if (!empty($matches['start'])) {
+                       if (preg_match('~^(?:(?:(?P<h>\d+)h)?(?P<m>\d+)m(?P<s>\d+))|(?P<t>\d+)~', $matches['start'], $match)) {
+                               if (!empty($match['h'])) {
+                                       $start += intval($match['h']) * 3600;
+                               }
+                               if (!empty($match['m'])) {
+                                       $start += intval($match['m']) * 60;
+                               }
+                               if (!empty($match['s'])) {
+                                       $start += intval($match['s']);
+                               }
+                               if (!empty($match['t'])) {
+                                       $start += intval($match['t']);
+                               }
+                       }
+               }
+               
+               return '<div class="videoContainer"><iframe src="https://www.youtube.com/embed/' . $matches['ID'] . '?wmode=transparent' . ($start ? '&amp;start='.$start : '') . '" allowfullscreen></iframe></div>';
+       }
+}
index 3ee64b894149bddfd9f0ec9232d03870871daa06..5866f135d2644aad6b9acdaa045365de3a8d8070 100644 (file)
                <item name="wcf.acp.bbcode.list"><![CDATA[BBCodes]]></item>
                
                <item name="wcf.acp.bbcode.mediaProvider.add"><![CDATA[Medienanbieter hinzufügen]]></item>
+               <item name="wcf.acp.bbcode.mediaProvider.className"><![CDATA[Klassen-Name]]></item>
+               <item name="wcf.acp.bbcode.mediaProvider.className.error.notFound"><![CDATA[Diese Klasse wurde nicht gefunden.]]></item>
                <item name="wcf.acp.bbcode.mediaProvider.delete.sure"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} den Medienanbieter <span class="confirmationObject">{$mediaProvider->title}</span> wirklich löschen?]]></item>
                <item name="wcf.acp.bbcode.mediaProvider.edit"><![CDATA[Medienanbieter bearbeiten]]></item>
                <item name="wcf.acp.bbcode.mediaProvider.html"><![CDATA[HTML-Code]]></item>
index e5062800cdf4bdfc141959853c0f75cbb9faa282..00c3157523bdf6a267859fa1454c35b4c3807791 100644 (file)
                <item name="wcf.acp.bbcode.list"><![CDATA[BBCodes]]></item>
                
                <item name="wcf.acp.bbcode.mediaProvider.add"><![CDATA[Add Media Provider]]></item>
+               <item name="wcf.acp.bbcode.mediaProvider.className"><![CDATA[PHP Class Name]]></item>
+               <item name="wcf.acp.bbcode.mediaProvider.className.error.notFound"><![CDATA[Unable to find specified class.]]></item>
                <item name="wcf.acp.bbcode.mediaProvider.delete.sure"><![CDATA[Do you really want to delete the media provider <span class="confirmationObject">{$mediaProvider->title}</span>?]]></item>
                <item name="wcf.acp.bbcode.mediaProvider.edit"><![CDATA[Edit Media Provider]]></item>
                <item name="wcf.acp.bbcode.mediaProvider.html"><![CDATA[HTML Code]]></item>
index 271e3c10d90c5535d5a4bb1229481a8e89fe746e..4f1ad9df3ca58813b4e38dbb14901112ff21a345 100644 (file)
@@ -263,7 +263,8 @@ CREATE TABLE wcf1_bbcode_media_provider (
        providerID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
        title VARCHAR(255) NOT NULL,
        regex TEXT NOT NULL,
-       html TEXT NOT NULL
+       html TEXT NOT NULL,
+       className varchar(255) NOT NULL DEFAULT ''
 );
 
 DROP TABLE IF EXISTS wcf1_box;
@@ -2145,11 +2146,11 @@ INSERT INTO wcf1_template_group (parentTemplateGroupID, templateGroupName, templ
 -- media providers
 -- Videos
        -- Youtube
-       INSERT INTO wcf1_bbcode_media_provider (title, regex, html) VALUES ('YouTube', 'https?://(?:.+?\\.)?youtu(?:\\.be/|be\\.com/(?:#/)?watch\\?(?:.*?&)?v=)(?P<ID>[a-zA-Z0-9_-]+)(?:(?:\\?|&)t=(?P<start>\\d+)$)?', '<div class="videoContainer"><iframe src="https://www.youtube.com/embed/{$ID}?wmode=transparent&amp;start={$start}" allowfullscreen></iframe></div>');
+       INSERT INTO wcf1_bbcode_media_provider (title, regex, html, className) VALUES ('YouTube', 'https?://(?:.+?\\.)?youtu(?:\\.be/|be\\.com/(?:#/)?watch\\?(?:.*?&)?v=)(?P<ID>[a-zA-Z0-9_-]+)(?:(?:\\?|&)t=(?P<start>[0-9hms]+)$)?', '', 'wcf\\system\\bbcode\\media\\provider\\YouTubeBBCodeMediaProvider');
        -- Youtube playlist
        INSERT INTO wcf1_bbcode_media_provider (title, regex, html) VALUES ('YouTube Playlist', 'https?://(?:.+?\\.)?youtu(?:\\.be/|be\\.com/)playlist\\?(?:.*?&)?list=(?P<ID>[a-zA-Z0-9_-]+)', '<div class="videoContainer"><iframe src="https://www.youtube.com/embed/videoseries?list={$ID}" allowfullscreen></iframe></div>');
        -- Vimeo
-       INSERT INTO wcf1_bbcode_media_provider (title, regex, html) VALUES ('Vimeo', 'https?://vimeo\\.com/(?:channels/[^/]+/)?(?P<ID>\\d+)', '<iframe src="https://player.vimeo.com/video/{$ID}" width="400" height="225" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>');
+       INSERT INTO wcf1_bbcode_media_provider (title, regex, html) VALUES ('Vimeo', 'https?://vimeo\\.com/(?:channels/[^/]+/)?(?P<ID>\\d+)\nhttps?://vimeo\\.com/groups/[^/]+/videos/(?P<ID>\\d+)', '<div class="videoContainer"><iframe src="https://player.vimeo.com/video/{$ID}" allowfullscreen></iframe></div>');
        -- Clipfish
        INSERT INTO wcf1_bbcode_media_provider (title, regex, html) VALUES ('Clipfish', 'http://(?:www\\.)?clipfish\\.de/(?:.*?/)?video/(?P<ID>\\d+)/', '<div style="width:464px; height:404px;"><div style="width:464px; height:384px;"><iframe src="http://www.clipfish.de/embed_video/?vid={$ID}&amp;as=0&amp;col=990000" name="Clipfish Embedded Video" width="464" height="384" align="left" marginheight="0" marginwidth="0" scrolling="no"></iframe></div></div>');
        -- Veoh