xref: /plugin/vshare/syntax/video.php (revision b82f24af674525b493dac939915358a71279a32e)
1<?php
2
3/**
4 * Easily embed videos from various Video Sharing sites
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Andreas Gohr <andi@splitbrain.org>
8 */
9class syntax_plugin_vshare_video extends DokuWiki_Syntax_Plugin
10{
11    protected $sites;
12
13    protected $sizes = [
14        'small' => [255, 143],
15        'medium' => [425, 239],
16        'large' => [520, 293],
17        'full' => ['100%', ''],
18        'half' => ['50%', ''],
19    ];
20
21    protected $alignments = [
22        0 => 'none',
23        1 => 'right',
24        2 => 'left',
25        3 => 'center',
26    ];
27
28    /**
29     * Constructor.
30     * Intitalizes the supported video sites
31     */
32    public function __construct()
33    {
34        $this->sites = helper_plugin_vshare::loadSites();
35    }
36
37    /** @inheritdoc */
38    public function getType()
39    {
40        return 'substition';
41    }
42
43    /** @inheritdoc */
44    public function getPType()
45    {
46        return 'block';
47    }
48
49    /** @inheritdoc */
50    public function getSort()
51    {
52        return 159;
53    }
54
55    /** @inheritdoc */
56    public function connectTo($mode)
57    {
58        $pattern = join('|', array_keys($this->sites));
59        $this->Lexer->addSpecialPattern('\{\{\s?(?:' . $pattern . ')>[^}]*\}\}', $mode, 'plugin_vshare_video');
60    }
61
62    /** @inheritdoc */
63    public function handle($match, $state, $pos, Doku_Handler $handler)
64    {
65        $command = substr($match, 2, -2);
66
67        // title
68        list($command, $title) = array_pad(explode('|', $command), 2, '');
69        $title = trim($title);
70
71        // alignment
72        $align = 0;
73        if (substr($command, 0, 1) == ' ') $align += 1;
74        if (substr($command, -1) == ' ') $align += 2;
75        $command = trim($command);
76
77        // get site and video
78        list($site, $vid) = explode('>', $command);
79        if (!$this->sites[$site]) return null; // unknown site
80        if (!$vid) return null; // no video!?
81
82        // what size?
83        list($vid, $pstr) = array_pad(explode('?', $vid, 2), 2, '');
84        parse_str($pstr, $userparams);
85        list($width, $height) = $this->parseSize($userparams);
86
87        // get URL
88        $url = $this->insertPlaceholders($this->sites[$site]['url'], $vid, $width, $height);
89        list($url, $urlpstr) = array_pad(explode('?', $url, 2), 2, '');
90        parse_str($urlpstr, $urlparams);
91
92        // merge parameters
93        $params = array_merge($urlparams, $userparams);
94        $url = $url . '?' . buildURLparams($params, '&');
95
96        return array(
97            'site' => $site,
98            'domain' => parse_url($url, PHP_URL_HOST),
99            'video' => $vid,
100            'url' => $url,
101            'align' => $this->alignments[$align],
102            'width' => $width,
103            'height' => $height,
104            'title' => $title,
105        );
106    }
107
108    /** @inheritdoc */
109    public function render($mode, Doku_Renderer $R, $data)
110    {
111        if ($mode != 'xhtml') return false;
112        if (is_null($data)) return false;
113
114        if (is_a($R, 'renderer_plugin_dw2pdf')) {
115            $R->doc .= $this->pdf($data);
116        } else {
117            $R->doc .= $this->iframe($data, $this->getConf('gdpr') ? 'div' : 'iframe');
118        }
119        return true;
120    }
121
122    /**
123     * Prepare the HTML for output of the embed iframe
124     * @param array $data
125     * @param string $element Can be used to not directly embed the iframe
126     * @return string
127     */
128    public function iframe($data, $element = 'iframe')
129    {
130        return "<$element "
131            . buildAttributes(array(
132                'src' => $data['url'],
133                'width' => $data['width'],
134                'height' => $data['height'],
135                'style' => $this->sizeToStyle($data['width'], $data['height']),
136                'class' => 'vshare vshare__' . $data['align'],
137                'allowfullscreen' => '',
138                'frameborder' => 0,
139                'scrolling' => 'no',
140                'data-domain' => $data['domain'],
141            ))
142            . '><h3>' . hsc($data['title']) . "</h3></$element>";
143    }
144
145    /**
146     * Create a style attribute for the given size
147     *
148     * @param int|string $width
149     * @param int|string $height
150     * @return string
151     */
152    public function sizeToStyle($width, $height)
153    {
154        // no unit? use px
155        if ($width && $width == (int)$width) {
156            $width = $width . 'px';
157        }
158        // no unit? use px
159        if ($height && $height == (int)$height) {
160            $height = $height . 'px';
161        }
162
163        $style = '';
164        if ($width) $style .= 'width:' . $width . ';';
165        if ($height) $style .= 'height:' . $height . ';';
166        return $style;
167    }
168
169    /**
170     * Prepare the HTML for output in PDF exports
171     *
172     * @param array $data
173     * @return string
174     */
175    public function pdf($data)
176    {
177        $html = '<div class="vshare vshare__' . $data['align'] . '"
178                      width="' . $data['width'] . '"
179                      height="' . $data['height'] . '">';
180
181        $html .= '<a href="' . $data['url'] . '" class="vshare">';
182        $html .= '<img src="' . DOKU_BASE . 'lib/plugins/vshare/video.png" />';
183        $html .= '</a>';
184
185        $html .= '<br />';
186
187        $html .= '<a href="' . $data['url'] . '" class="vshare">';
188        $html .= ($data['title'] ? hsc($data['title']) : 'Video');
189        $html .= '</a>';
190
191        $html .= '</div>';
192
193        return $html;
194    }
195
196    /**
197     * Fill the placeholders in the given URL
198     *
199     * @param string $url
200     * @param string $vid
201     * @param int|string $width
202     * @param int|string $height
203     * @return string
204     */
205    public function insertPlaceholders($url, $vid, $width, $height)
206    {
207        global $INPUT;
208        $url = str_replace('@VIDEO@', rawurlencode($vid), $url);
209        $url = str_replace('@DOMAIN@', rawurlencode($INPUT->server->str('HTTP_HOST')), $url);
210        $url = str_replace('@WIDTH@', $width, $url);
211        $url = str_replace('@HEIGHT@', $height, $url);
212
213        return $url;
214    }
215
216    /**
217     * Extract the wanted size from the parameter list
218     *
219     * @param array $params
220     * @return int[]
221     */
222    public function parseSize(&$params)
223    {
224        $known = join('|', array_keys($this->sizes));
225
226        foreach ($params as $key => $value) {
227            if (preg_match("/^((\d+)x(\d+))|($known)\$/i", $key, $m)) {
228                unset($params[$key]);
229                if (isset($m[4])) {
230                    return $this->sizes[strtolower($m[4])];
231                } else {
232                    return [$m[2], $m[3]];
233                }
234            }
235        }
236
237        // default
238        return $this->sizes['medium'];
239    }
240}
241