-
Notifications
You must be signed in to change notification settings - Fork 46
/
Plugin.php
300 lines (284 loc) · 12.5 KB
/
Plugin.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* DPlayer for typecho
*
* @package DPlayer
* @author player
* @version 1.1.1
* @link https://niconiconi.net
*/
class DPlayer_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件方法,如果激活失败,直接抛出异常
*
* @access public
* @return void
*/
public static function activate()
{
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = ['DPlayer_Plugin', 'replacePlayer'];
Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = ['DPlayer_Plugin', 'replacePlayer'];
Typecho_Plugin::factory('Widget_Archive')->header = ['DPlayer_Plugin', 'playerHeader'];
Typecho_Plugin::factory('Widget_Archive')->footer = ['DPlayer_Plugin', 'playerFooter'];
Typecho_Plugin::factory('admin/write-post.php')->bottom = ['DPlayer_Plugin', 'addEditorButton'];
Typecho_Plugin::factory('admin/write-page.php')->bottom = ['DPlayer_Plugin', 'addEditorButton'];
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*
* @static
* @access public
* @return void
*/
public static function deactivate()
{
}
/**
* 插入顶部代码
*/
public static function playerHeader()
{
echo <<<EOF
<link rel="stylesheet" type="text/css" href="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/dplayer/1.25.0/DPlayer.min.css" />
EOF;
}
/**
* 插入底部代码
* @throws Typecho_Exception
*/
public static function playerFooter()
{
$url = Helper::options()->pluginUrl . '/DPlayer';
if (Typecho_Widget::widget('Widget_Options')->plugin('DPlayer')->hls) {
echo "<script type=\"text/javascript\" src=\"$url/plugin/hls.min.js\"></script>\n";
}
if (Typecho_Widget::widget('Widget_Options')->plugin('DPlayer')->flv) {
echo "<script type=\"text/javascript\" src=\"$url/plugin/flv.min.js\"></script>\n";
}
echo <<<EOF
<script type="text/javascript" src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/dplayer/1.25.0/DPlayer.min.js"></script>
<script type="text/javascript" src="$url/assets/player.js"></script>
EOF;
}
/**
* 内容标签替换
*
* @param $text
* @param $widget
* @param $last
* @return string
*/
public static function replacePlayer($text, $widget, $last)
{
$text = empty($last) ? $text : $last;
if ($widget instanceof Widget_Archive) {
$pattern = self::get_shortcode_regex(['dplayer']);
$text = preg_replace_callback("/$pattern/", ['DPlayer_Plugin', 'parseCallback'], $text);
}
return $text;
}
/**
* 回调解析
* @param $matches
* @return string
* @throws Typecho_Exception
*/
public static function parseCallback($matches)
{
/*
$mathes array
* 1 - An extra [ to allow for escaping shortcodes with double [[]]
* 2 - The shortcode name
* 3 - The shortcode argument list
* 4 - The self closing /
* 5 - The content of a shortcode when it wraps some content.
* 6 - An extra ] to allow for escaping shortcodes with double [[]]
*/
// allow [[player]] syntax for escaping the tag
if ($matches[1] == '[' && $matches[6] == ']') {
return substr($matches[0], 1, -1);
}
//还原转义后的html
//[dplayer title="Test Abc" artist="haha" id="1234543"/]
$tag = htmlspecialchars_decode($matches[3]);
//[dplayer]标签的属性,类型为array
$attrs = self::shortcode_parse_atts($tag);
return DPlayer_Plugin::parsePlayer($attrs);
}
public static function parsePlayer($attrs)
{
//播放器设置
$theme = Typecho_Widget::widget('Widget_Options')->plugin('DPlayer')->theme ?: '#FADFA3';
$api = Typecho_Widget::widget('Widget_Options')->plugin('DPlayer')->api;
//播放器属性
$config = [
'live' => false,
'autoplay' => isset($attrs['autoplay']) && $attrs['autoplay'] == 'true',
'theme' => isset($attrs['theme']) ? $attrs['theme'] : $theme,
'loop' => isset($attrs['loop']) && $attrs['loop'] == 'true',
'screenshot' => isset($attrs['screenshot']) && $attrs['screenshot'] == 'true',
'hotkey' => true,
'preload' => 'metadata',
'lang' => isset($attrs['lang']) ? $attrs['lang'] : 'zh-cn',
'logo' => isset($attrs['logo']) ? $attrs['logo'] : null,
'volume' => isset($attrs['volume']) ? $attrs['volume'] : 0.7,
'mutex' => true,
'video' => [
'url' => isset($attrs['url']) ? $attrs['url'] : null,
'pic' => isset($attrs['pic']) ? $attrs['pic'] : null,
'type' => isset($attrs['type']) ? $attrs['type'] : 'auto',
'thumbnails' => isset($attrs['thumbnails']) ? $attrs['thumbnails'] : null,
],
];
if (isset($attrs['danmu']) && $attrs['danmu'] == 'true') {
$config['danmaku'] = [
'id' => md5(isset($attrs['url']) ? $attrs['url'] : ''),
'api' => $api,
'maximum' => isset($attrs['maximum']) ? $attrs['maximum'] : 1000,
'user' => isset($attrs['user']) ? $attrs['user'] : 'DIYgod',
'bottom' => isset($attrs['bottom']) ? $attrs['bottom'] : '15%',
'unlimited' => true,
];
}
if (isset($attrs['subtitle']) && $attrs['subtitle'] == 'true') {
$config['subtitle'] = [
'url' => isset($attrs['subtitleurl']) ? $attrs['subtitleurl'] : null,
'type' => isset($attrs['subtitletype']) ? $attrs['subtitletype'] : 'webvtt',
'fontSize' => isset($attrs['subtitlefontsize']) ? $attrs['subtitlefontsize'] : '25px',
'bottom' => isset($attrs['subtitlebottom']) ? $attrs['subtitlebottom'] : '10%',
'color' => isset($attrs['subtitlecolor']) ? $attrs['subtitlecolor'] : '#b7daff',
];
}
$json = json_encode($config);
return "<div class=\"dplayer\" data-config='{$json}'></div>";
}
public static function addEditorButton()
{
$dir = Helper::options()->pluginUrl . '/DPlayer/assets/editor.js';
echo "<script type=\"text/javascript\" src=\"{$dir}\"></script>";
}
public static function config(Typecho_Widget_Helper_Form $form)
{
$theme = new Typecho_Widget_Helper_Form_Element_Text(
'theme', null, '#FADFA3',
_t('默认主题颜色'), _t('播放器默认的主题颜色,例如 #372e21、#75c、red、blue,该设定会被[dplayer]标签中的theme属性覆盖,默认为 #FADFA3'));
$api = new Typecho_Widget_Helper_Form_Element_Text(
'api', null, '',
_t('弹幕服务器地址'), _t('用于保存视频弹幕,例如 https://api.prprpr.me/dplayer/v3/'));
$hls = new Typecho_Widget_Helper_Form_Element_Radio('hls', array('0' => _t('不开启HLS支持'), '1' => _t('开启HLS支持')), '0', _t('HLS支持'), _t("开启后可解析 m3u8 格式视频"));
$flv = new Typecho_Widget_Helper_Form_Element_Radio('flv', array('0' => _t('不开启FLV支持'), '1' => _t('开启FLV支持')), '0', _t('FLV支持'), _t("开启后可解析 flv 格式视频"));
$form->addInput($theme);
$form->addInput($api);
$form->addInput($hls);
$form->addInput($flv);
}
public static function personalConfig(Typecho_Widget_Helper_Form $form)
{
}
/**
* Retrieve all attributes from the shortcodes tag.
*
* The attributes list has the attribute name as the key and the value of the
* attribute as the value in the key/value pair. This allows for easier
* retrieval of the attributes, since all attributes have to be known.
*
* @link https://github.com/WordPress/WordPress/blob/master/wp-includes/shortcodes.php
* @since 2.5.0
*
* @param string $text
* @return array|string List of attribute values.
* Returns empty array if trim( $text ) == '""'.
* Returns empty string if trim( $text ) == ''.
* All other matches are checked for not empty().
*/
private static function shortcode_parse_atts($text)
{
$atts = array();
$pattern = '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
$text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text);
if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) {
foreach ($match as $m) {
if (!empty($m[1]))
$atts[strtolower($m[1])] = stripcslashes($m[2]);
elseif (!empty($m[3]))
$atts[strtolower($m[3])] = stripcslashes($m[4]);
elseif (!empty($m[5]))
$atts[strtolower($m[5])] = stripcslashes($m[6]);
elseif (isset($m[7]) && strlen($m[7]))
$atts[] = stripcslashes($m[7]);
elseif (isset($m[8]))
$atts[] = stripcslashes($m[8]);
}
// Reject any unclosed HTML elements
foreach ($atts as &$value) {
if (false !== strpos($value, '<')) {
if (1 !== preg_match('/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value)) {
$value = '';
}
}
}
} else {
$atts = ltrim($text);
}
return $atts;
}
/**
* Retrieve the shortcode regular expression for searching.
*
* The regular expression combines the shortcode tags in the regular expression
* in a regex class.
*
* The regular expression contains 6 different sub matches to help with parsing.
*
* 1 - An extra [ to allow for escaping shortcodes with double [[]]
* 2 - The shortcode name
* 3 - The shortcode argument list
* 4 - The self closing /
* 5 - The content of a shortcode when it wraps some content.
* 6 - An extra ] to allow for escaping shortcodes with double [[]]
*
* @link https://github.com/WordPress/WordPress/blob/master/wp-includes/shortcodes.php
* @since 2.5.0
*
*
* @param array $tagnames List of shortcodes to find. Optional. Defaults to all registered shortcodes.
* @return string The shortcode search regular expression
*/
private static function get_shortcode_regex($tagnames = null)
{
$tagregexp = join('|', array_map('preg_quote', $tagnames));
// WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
// Also, see shortcode_unautop() and shortcode.js.
return
'\\[' // Opening bracket
. '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
. "($tagregexp)" // 2: Shortcode name
. '(?![\\w-])' // Not followed by word character or hyphen
. '(' // 3: Unroll the loop: Inside the opening shortcode tag
. '[^\\]\\/]*' // Not a closing bracket or forward slash
. '(?:'
. '\\/(?!\\])' // A forward slash not followed by a closing bracket
. '[^\\]\\/]*' // Not a closing bracket or forward slash
. ')*?'
. ')'
. '(?:'
. '(\\/)' // 4: Self closing tag ...
. '\\]' // ... and closing bracket
. '|'
. '\\]' // Closing bracket
. '(?:'
. '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
. '[^\\[]*+' // Not an opening bracket
. '(?:'
. '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
. '[^\\[]*+' // Not an opening bracket
. ')*+'
. ')'
. '\\[\\/\\2\\]' // Closing shortcode tag
. ')?'
. ')'
. '(\\]?)'; // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
}
}