Seditio Source
Root |
./othercms/b2evolution_7.2.3/plugins/videoplug_plugin/_videoplug.plugin.php
<?php
/**
 * This file implements the Video Plug plugin for b2evolution
 *
 * b2evolution - {@link http://b2evolution.net/}
 * Released under GNU GPL License - {@link http://b2evolution.net/about/gnu-gpl-license}
 * @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
 *
 * @package plugins
 */
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );

/**
 * Replaces Video Plug markup in HTML (not XML).
 *
 * @todo dh> Hook into AdminBeforeItemEditUpdate and validate provided video IDs
 *
 * @package plugins
 */
class videoplug_plugin extends Plugin
{
    var
$code = 'evo_videoplug';
    var
$name = 'Video Plug';
    var
$priority = 65;
    var
$group = 'rendering';
    var
$short_desc;
    var
$long_desc;
    var
$version = '7.2.3';
    var
$number_of_installs = 1;


   
/**
     * Init
     */
   
function PluginInit( & $params )
    {
       
$this->short_desc = T_('Video plug for a few popular video sites.');
       
$this->long_desc = T_('This plugin allows to quickly embed (plug) a video from a video hosting site such as YouTube, Vimeo, DailyMotion and Facebook. Use it through the toolbar or directly by entering a shortcode like [video:youtube:123xyz] or [video:vimeo:123xyz] into your post, where 123xyz is the ID of the video.');
    }


   
/**
     * Define the GLOBAL settings of the plugin here. These can then be edited in the backoffice in System > Plugins.
     *
     * @param array Associative array of parameters (since v1.9).
     *    'for_editing': true, if the settings get queried for editing;
     *                   false, if they get queried for instantiating {@link Plugin::$Settings}.
     * @return array see {@link Plugin::GetDefaultSettings()}.
     * The array to be returned should define the names of the settings as keys (max length is 30 chars)
     * and assign an array with the following keys to them (only 'label' is required):
     */
   
function GetDefaultSettings( & $params )
    {
        return array(
           
'youtube_load' => array(
               
'label' => 'YouTube',
               
'type' => 'radio',
               
'options' => array(
                    array(
'standard', T_('Standard').' <code>&lt;iframe&gt;</code>' ),
                    array(
'lazyload', T_('Lazy-Load') ),
                ),
               
'field_lines' => true,
               
'defaultvalue' => 'standard',
            ),
        );
    }


   
/**
     * Define here default custom settings that are to be made available
     *     in the backoffice for collections, private messages and newsletters.
     *
     * @param array Associative array of parameters.
     * @return array See {@link Plugin::GetDefaultSettings()}.
     */
   
function get_custom_setting_definitions( & $params )
    {
        return array(
               
'width' => array(
                   
'label' => T_('Video width (px or %)'),
                   
'note' => T_('100% width if left empty or 0'),
                   
'valid_pattern' => '/^(\d+(\.\d+)?%?)?$/',
                   
'defaultvalue' => '100%',
                ),
               
'height' => array(
                   
'label' => T_('Video height (px or %)'),
                   
'defaultvalue' => '',
                   
'allow_empty' => true,
                   
'valid_pattern' => '/^(\d+(\.\d+)?%?)?$/',
                   
'note' => T_('Leave empty for a 16/9 aspect ratio').' (16/9=56.25%)',
                   
'defaultvalue' => '56.25%',
                ),
            );
    }


   
/**
     * Define here default collection/blog settings that are to be made available in the backoffice.
     *
     * @param array Associative array of parameters.
     * @return array See {@link Plugin::GetDefaultSettings()}.
     */
   
function get_coll_setting_definitions( & $params )
    {
        return
array_merge( parent::get_coll_setting_definitions( $params ),
            array(
               
'replace_url_post' => array(
                       
'label' => T_('Replace full video URLs found in posts' ),
                       
'type' => 'checkbox',
                       
'defaultvalue' => 1,
                    ),
               
'replace_url_comment' => array(
                       
'label' => T_('Replace full video URLs found in comments' ),
                       
'type' => 'checkbox',
                       
'defaultvalue' => 1,
                    ),
            )
        );
    }


   
/**
     * Event handler: Called at the beginning of the skin's HTML HEAD section.
     *
     * Use this to add any HTML HEAD lines (like CSS styles or links to resource files (CSS, JavaScript, ..)).
     *
     * @param array Associative array of parameters
     */
   
function SkinBeginHtmlHead( & $params )
    {
       
$this->require_css( 'css/videoplug.min.css' );
       
// Initialize config for video plugin:
       
expose_var_to_js( 'evo_plugin_videoplug_config', array(
           
'youtube_lazyload_selector' => '.evo_youtube[data-embed]',
        ) );
    }


   
/**
     * Perform rendering
     *
     * @todo add more video sites, anyone...
     *
     * @see Plugin::RenderItemAsHtml()
     */
   
function RenderItemAsHtml( & $params )
    {
       
$content = & $params['data'];

        if(
$setting_Blog = & $this->get_Blog_from_params( $params ) )
        {    
// We are rendering Item, Comment or Widget now, Get the settings depending on Collection:
           
$this->video_width = $this->get_coll_setting( 'width', $setting_Blog );
           
$this->video_height = $this->get_coll_setting( 'height', $setting_Blog );
        }
        elseif( ! empty(
$params['Message'] ) )
        {    
// We are rendering Message now:
           
$this->video_width = $this->get_msg_setting( 'width' );
           
$this->video_height = $this->get_msg_setting( 'height' );
        }
        elseif( ! empty(
$params['EmailCampaign'] ) )
        {    
// We are rendering EmailCampaign now:
           
$this->video_width = $this->get_email_setting( 'width' );
           
$this->video_height = $this->get_email_setting( 'height' );
        }
        else
        {    
// Unknown call, Don't render this case:
           
return;
        }

        if( ! empty(
$setting_Blog ) && (
              (
$this->get_coll_setting( 'replace_url_comment', $setting_Blog ) && ! empty( $params['Comment'] ) && $params['Comment'] instanceof Comment ) ||
              (
$this->get_coll_setting( 'replace_url_post', $setting_Blog ) && ! empty( $params['Item'] ) && $params['Item'] instanceof Item )
          ) )
        {    
// Render full video URLs in post or comment content:
           
$content = replace_outside_code_and_short_tags( '#(<a[^>]+href=")?(https?://(.+\.)?(youtube.com|youtu.be|dailymotion.com|vimeo.com|facebook.com|wistia.com)([^"\s\n\r<]+))("[^>]*>(.+?)</a>)?#i',
                array(
$this, 'parse_video_url_callback' ), $content, 'replace_content', 'preg_callback' );
        }

       
// Move short tag outside of paragraph:
       
$content = move_short_tags( $content, '/\[video:(youtube|dailymotion|vimeo|facebook|wistia):?[^\[\]]*\]/i' );

       
// Replace video tags with html code:
       
$content = replace_outside_code_tags( '#\[video:(youtube|dailymotion|vimeo|facebook|wistia|google|livevideo|ifilm):([^:\[\]\\\/]*|https?:\/\/.*\.facebook\.com\/[^:]*):?(\d+%?)?:?(\d+%?)?:?([^:\[\]\\\/]*)\]#',
            array(
$this, 'parse_video_tag_callback' ), $content, 'replace_content', 'preg_callback' );

        return
true;
    }


   
/**
     * Callback function to build HTML video code from video URL or link tag <a> with video URL
     *
     * @param array Matches:
     *              0 - Full video URL or full link tag <a>
     *              1 - Start part of <a> tag, or empty string when simple URL without <a> tag
     *              2 - Full URL
     *              3 - domain prefix like "www." or "www.subdomain." or empty
     *              4 - Domain: youtube.com, youtu.be, dailymotion.com, vimeo.com, facebook.com, wistia.com
     *              5 - Part of video URL after domain
     *              6 - End part of <a> tag, or not defined when simple URL without <a> tag
     *              7 - Text of <a> tag, or not defined when simple URL without <a> tag
     * @return string HTML video code
     */
   
function parse_video_url_callback( $m )
    {
        if( isset(
$m[7] ) && $m[7] != $m[2] )
        {    
// Skip if link text is different than URL(e.g. <a href="https://youtu.be/abc123">Click to see Video!</a>):
           
return $m[0];
        }

       
// Try to extract video code from URL depending on video server:
       
switch( $m[4] )
        {
            case
'youtube.com':
            case
'youtu.be':
                if(
preg_match( '#(^/(embed/)?|[\?&]v=)([^&=\?]+)(&|$)#', $m[5], $code ) )
                {
                    if(
$this->get_setting( 'youtube_load' ) == 'standard' )
                    {    
// Use standard loading with iframe:
                       
$video_block = '<iframe id="ytplayer" type="text/html" src="//www.youtube.com/embed/'.$code[3].'" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
                    }
                    else
                    {    
// Use Lazy-loading:
                       
$video_block = '<div class="evo_youtube" data-embed="'.$code[3].'"><div class="evo_youtube__play_button"></div></div>';
                    }
                }
                break;

            case
'dailymotion.com':
                if(
preg_match( '#^/video/(.+)$#', $m[5], $code ) )
                {
                   
$video_block = '<iframe src="//www.dailymotion.com/embed/video/'.$code[1].'" frameborder="0" allowfullscreen></iframe>';
                }
                break;

            case
'vimeo.com':
                if(
preg_match( '#^/(.+)$#', $m[5], $code ) )
                {
                   
$video_block = '<iframe src="//player.vimeo.com/video/'.$code[1].'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
                }
                break;

            case
'facebook.com':
                if(
preg_match( '#(/videos/|[\?&]v=)(\d+)(/|$)#', $m[5], $code ) )
                {
                   
$video_block = '<iframe src="https://www.facebook.com/plugins/video.php?href='.urlencode( $m[2] ).'" scrolling="no" frameborder="0" allowTransparency="true" allowFullScreen="true"></iframe>';
                }
                break;

            case
'wistia.com':
                if(
preg_match( '#/medias/([a-z0-9]+)$#', $m[5], $code ) )
                {
                   
$video_block = '<script src="https://fast.wistia.com/embed/medias/'.$code[1].'.jsonp" async></script>'
                       
.'<script src="https://fast.wistia.com/assets/external/E-v1.js" async></script>'
                       
.'<div class="wistia_responsive_padding">'
                           
.'<div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;">'
                               
.'<span class="wistia_embed wistia_async_'.$code[1].' popover=true popoverAnimateThumbnail=true videoFoam=true" style="display:inline-block;height:100%;position:relative;width:100%"> </span>'
                           
.'</div>'
                       
.'</div>';
                }
                break;
        }

        if( ! isset(
$video_block ) )
        {    
// No found correct video code in the URL:
           
return $m[0];
        }

       
$style = '';

        if( ! empty(
$this->video_width ) )
        {    
// Set width depending on what units are used:
           
$style .= 'width:'.( strpos( $this->video_width, '%' ) === false ? $this->video_width.'px' : $this->video_width ).';';
        }

        if( ! empty(
$this->video_height ) )
        {    
// Set height depending on what units are used:
           
$style .= 'padding-bottom:'.( strpos( $this->video_height, '%' ) === false ? '0;height:'.$this->video_height.'px' : $this->video_height );
        }

        return
'<div class="videoblock"'.( $style == '' ? '' : ' style="'.$style.'"' ).'>'.$video_block.'</div>';
    }


   
/**
     * Callback function to build HTML video code from video tag
     *
     * @param array Matches:
     *              0 - Full video tag
     *              1 - Video type: youtube, dailymotion, vimeo, facebook, wistia, google, livevideo, ifilm
     *              2 - Video code/key
     *              3 - Width
     *              4 - Height
     *              5 - Extra params
     * @return string HTML video code
     */
   
function parse_video_tag_callback( $m )
    {
        switch(
$m[1] )
        {
            case
'youtube':
               
$video_block = '<iframe id="ytplayer" type="text/html" src="//www.youtube.com/embed/'.$m[2].( ! empty( $m[5] )? '?'.$m[5] : '' ).'" allowfullscreen="allowfullscreen" frameborder="0"></iframe>';
                break;

            case
'dailymotion':
               
$video_block = '<iframe src="//www.dailymotion.com/embed/video/'.$m[2].'" frameborder="0" allowfullscreen></iframe>';
                break;

            case
'vimeo':
               
$video_block = '<iframe src="//player.vimeo.com/video/'.$m[2].'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
                break;

            case
'facebook':
               
$video_block = '<iframe src="https://www.facebook.com/plugins/video.php?href='.urlencode( $m[2] ).'" scrolling="no" frameborder="0" allowTransparency="true" allowFullScreen="true"></iframe>';
                break;

            case
'wistia':
               
$video_block = '<script src="https://fast.wistia.com/embed/medias/'.$m[2].'.jsonp" async></script>'
                   
.'<script src="https://fast.wistia.com/assets/external/E-v1.js" async></script>'
                   
.'<div class="wistia_responsive_padding">'
                       
.'<div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;">'
                           
.'<span class="wistia_embed wistia_async_'.$m[2].' popover=true popoverAnimateThumbnail=true videoFoam=true" style="display:inline-block;height:100%;position:relative;width:100%"> </span>'
                       
.'</div>'
                   
.'</div>';
                break;

            default:
// google, livevideo, ifilm:
                // Unavailable services. Keep them for backwards compatibility:
               
$video_block = 'The '.$m[1].' video service is not available anymore.';
                break;
        }

       
$style = '';

       
// Get width from video tag or from settings:
       
$width = empty( $m[3] ) ? $this->video_width : $m[3];
        if( ! empty(
$width ) )
        {    
// Set width depending on what units are used:
           
$style .= 'width:'.( strpos( $width, '%' ) === false ? $width.'px' : $width ).';';
        }

       
// Get height from video tag or from settings:
       
$height = empty( $m[4] ) ? $this->video_height : $m[4];
        if( ! empty(
$height ) )
        {    
// Set height depending on what units are used:
           
$style .= 'padding-bottom:'.( strpos( $height, '%' ) === false ? '0;height:'.$height.'px' : $height );
        }

        return
'<div class="videoblock"'.( $style == '' ? '' : ' style="'.$style.'"' ).'>'.$video_block.'</div>';
    }


   
/**
     * Perform rendering for XML feeds
     *
     * @see Plugin::RenderItemAsXml()
     */
   
function RenderItemAsXml( & $params )
    {
        return
$this->RenderItemAsHtml( $params );
    }


   
/**
     * Event handler: Called when displaying editor toolbars on post/item form.
     *
     * This is for post/item edit forms only. Comments, PMs and emails use different events.
     *
     * @param array Associative array of parameters
     * @return boolean did we display a toolbar?
     */
   
function AdminDisplayToolbar( & $params )
    {
        if( !empty(
$params['Item'] ) )
        {    
// Item is set, get Blog from post:
           
$edited_Item = & $params['Item'];
           
$Collection = $Blog = & $edited_Item->get_Blog();
        }

        if( empty(
$Blog ) )
        {    
// Item is not set, try global Blog:
           
global $Collection, $Blog;
            if( empty(
$Blog ) )
            {    
// We can't get a Blog, this way "apply_rendering" plugin collection setting is not available:
               
return false;
            }
        }

       
$apply_rendering = $this->get_coll_setting( 'coll_apply_rendering', $Blog );
        if( empty(
$apply_rendering ) || $apply_rendering == 'never' )
        {    
// Plugin is not enabled for current case, so don't display a toolbar:
           
return false;
        }

        return
$this->DisplayCodeToolbar( $params );
    }


   
/**
     * Event handler: Called when displaying editor toolbars for message.
     *
     * @param array Associative array of parameters
     * @return boolean did we display a toolbar?
     */
   
function DisplayMessageToolbar( & $params )
    {
       
$apply_rendering = $this->get_msg_setting( 'msg_apply_rendering' );
        if( ! empty(
$apply_rendering ) && $apply_rendering != 'never' )
        {
            return
$this->DisplayCodeToolbar( $params );
        }

        return
false;
    }


   
/**
     * Event handler: Called when displaying editor toolbars for email.
     *
     * @param array Associative array of parameters
     * @return boolean did we display a toolbar?
     */
   
function DisplayEmailToolbar( & $params )
    {
       
$apply_rendering = $this->get_email_setting( 'email_apply_rendering' );
        if( ! empty(
$apply_rendering ) && $apply_rendering != 'never' )
        {
            return
$this->DisplayCodeToolbar( $params );
        }

        return
false;
    }


   
/**
     * Event handler: Called when displaying editor toolbars on comment form.
     *
     * @param array Associative array of parameters
     * @return boolean did we display a toolbar?
     */
   
function DisplayCommentToolbar( & $params )
    {
       
$Comment = & $params['Comment'];
        if(
$Comment )
        {    
// Get a post of the comment:
           
if( $comment_Item = & $Comment->get_Item() )
            {
               
$Collection = $Blog = & $comment_Item->get_Blog();
            }
        }

        if( empty(
$Blog ) )
        {    
// Item is not set, try global Blog
           
global $Collection, $Blog;
            if( empty(
$Blog ) )
            {    
// We can't get a Blog, this way "apply_rendering" plugin collection setting is not available
               
return false;
            }
        }

       
$apply_rendering = $this->get_coll_setting( 'coll_apply_comment_rendering', $Blog );
        if( empty(
$apply_rendering ) || $apply_rendering == 'never' )
        {    
// Plugin is not enabled for current case, so don't display a toolbar:
           
return false;
        }

        return
$this->DisplayCodeToolbar( $params );
    }


   
/**
     * Display a code toolbar
     *
     * @param array Params
     * @return boolean did we display a toolbar?
     */
   
function DisplayCodeToolbar( $params = array() )
    {
       
$params = array_merge( array(
               
'js_prefix' => '', // Use different prefix if you use several toolbars on one page
           
), $params );

        echo
$this->get_template( 'toolbar_before', array( '$toolbar_class$' => $params['js_prefix'].$this->code.'_toolbar' ) );

        echo
$this->get_template( 'toolbar_title_before' ).T_('Video').': '.$this->get_template( 'toolbar_title_after' );
        echo
$this->get_template( 'toolbar_group_before' );
        echo
'<input type="button" id="video_youtube" title="'.T_('Insert Youtube video').'" class="'.$this->get_template( 'toolbar_button_class' ).'" data-func="videotag|youtube|'.$params['js_prefix'].'" value="YouTube" />';
        echo
'<input type="button" id="video_vimeo" title="'.T_('Insert vimeo video').'" class="'.$this->get_template( 'toolbar_button_class' ).'" data-func="videotag|vimeo|'.$params['js_prefix'].'" value="Vimeo" />';
        echo
'<input type="button" id="video_dailymotion" title="'.T_('Insert DailyMotion video').'" class="'.$this->get_template( 'toolbar_button_class' ).'" data-func="videotag|dailymotion|'.$params['js_prefix'].'" value="DailyMotion" />';
        echo
'<input type="button" id="video_facebook" title="'.T_('Insert Facebook video').'" class="'.$this->get_template( 'toolbar_button_class' ).'" data-func="videotag|facebook|'.$params['js_prefix'].'" value="Facebook" />';
        echo
'<input type="button" id="video_wistia" title="'.T_('Insert Wistia video').'" class="'.$this->get_template( 'toolbar_button_class' ).'" data-func="videotag|wistia|'.$params['js_prefix'].'" value="Wistia" />';
        echo
$this->get_template( 'toolbar_group_after' );

        echo
$this->get_template( 'toolbar_after' );

       
// Load js to work with textarea
       
require_js_defer( 'functions.js', 'blog', true );

       
?><script>
            //<![CDATA[
            function videotag( tag, prefix )
            {
                while( 1 )
                {
                    var p = '<?php echo TS_('Copy/paste the URL or the ID of your video from %s:') ?>';
                    var video_ID = prompt( p.replace( /%s/, tag ), '' );
                    if( ! video_ID )
                    {
                        return;
                    }

                    // Validate Video ID or URL:
                    var regexp_ID = false;
                    var regexp_URL = false;
                    switch( tag )
                    {
                        case 'youtube':
                            // Allow HD video code with ?hd=1 at the end
                            regexp_ID = /^[a-z0-9_-]+$/i;
                            regexp_URL = /^(.+youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|.+youtu\.be\/)([a-z0-9_-]{11})((?:\?|&).*)?/i;
                            break;

                        case 'dailymotion':
                            regexp_ID = /^[a-z0-9]+$/i;
                            regexp_URL = /^(.+\/video\/)?([a-z0-9]+)(_[a-z0-9_-]+)?(\?.+)?$/i;
                            break;

                        case 'vimeo':
                            regexp_ID = /^\d+$/;
                            regexp_URL = /^(.+\/)?(\d+)(\?.+)?$/;
                            break;

                        case 'facebook':
                            regexp_ID = /^https:\/\/.+\.facebook\.com\/.+/i;
                            regexp_URL = /^((https:\/\/.+\.facebook\.com\/.+))$/i;
                            break;

                        case 'wistia':
                            regexp_ID = /^[a-z0-9]+$/i;
                            regexp_URL = /^(.+\/medias\/)?([a-z0-9]+)$/i;
                            break;

                        default:
                            // Don't allow unknown video:
                            break;
                    }

                    if( regexp_ID && regexp_URL )
                    {    // Check the entered data by regexp:
                        if( video_ID.match( regexp_ID ) )
                        {    // Valid video ID
                            break;
                        }
                        else if( video_ID.match( /^https?:\/\// ) )
                        {    // If this is URL, Check to correct format:
                            if( video_ID.match( regexp_URL ) )
                            {    // Valid video URL
                                // Extract ID from URL:
                                if( tag == 'youtube' )
                                {
                                    var params = video_ID.replace( regexp_URL, '$3' ).trim();
                                    params = params.replace( /^[&\?]/, '' );
                                    params = params.replace( /&$/, '' );
                                    params = params.replace( /rel=\d+&?/, '' ); // remove rel=
                                    video_ID = video_ID.replace( regexp_URL, '$2' );
                                    if( params.length )
                                    {
                                        video_ID = video_ID + ':::' + params;
                                    }
                                }
                                else
                                {
                                    video_ID = video_ID.replace( regexp_URL, '$2' );
                                }
                                break;
                            }
                            else
                            {    // Display error when URL doesn't match:
                                alert( '<?php echo TS_('The URL you provided could not be recognized.'); ?>' );
                                continue;
                            }
                        }
                    }

                    // Display error of wrong entered data:
                    alert( '<?php echo TS_('The URL or video ID is invalid.'); ?>' );
                }

                tag = '[video:'+tag+':'+video_ID+']';

                textarea_wrap_selection( window[ ( prefix ? prefix : '' ) + 'b2evoCanvas' ], tag, '', 1 );
            }
            //]]>
        </script><?php

       
return true;
    }
}

?>