1<?php
2/**
3 * Embed a jPlayer
4 *
5 * @author     Szymon Olewniczak <solewniczak@rid.pl>
6 */
7
8// must be run within Dokuwiki
9if(!defined('DOKU_INC')) die();
10
11require_once __DIR__ . '/vendor/autoload.php';
12
13class syntax_plugin_jplayer extends DokuWiki_Syntax_Plugin {
14
15    private $getID3;
16
17    public function __construct() {
18        $this->getID3 = new getID3;
19    }
20
21    /**
22     * What kind of syntax are we?
23     */
24    function getType(){
25        return 'substition';
26    }
27    /**
28     * What about paragraphs?
29     */
30    function getPType(){
31        return 'block';
32    }
33    /**
34     * Where to sort in?
35     */
36    function getSort(){
37        return 301;
38    }
39    /**
40     * Connect pattern to lexer
41     */
42    function connectTo($mode) {
43        $this->Lexer->addSpecialPattern('\{\{jPlayerPlaylist>[^}]*\}\}',$mode,'plugin_jplayer');
44    }
45
46    private function _audio($item) {
47        $full_path = mediaFN($item['id']);
48        $pathinfo = pathinfo($item['file']);
49        $link = ml($item['id'],'',true);
50
51        $audio = array('title' => $pathinfo['filename']);
52        if ($pathinfo['extension'] === 'mp3') {
53            $audio['mp3'] = $link;
54            if ($this->getConf('use_id3_tags') == '1') {
55                $analyze = $this->getID3->analyze($full_path);
56                if(isset($analyze['tags']['id3v2']['title'])) {
57                    $audio['title'] = $analyze['tags']['id3v2']['title'];
58                } elseif(isset($analyze['tags']['id3v1']['title'])) {
59                    $audio['title'] = $analyze['tags']['id3v1']['title'];
60                }
61            }
62        }
63        if ($pathinfo['extension'] === 'ogg') {
64            $audio['oga'] = $link;
65        }
66
67        //https://stackoverflow.com/questions/9066878/jquery-jplayer-enable-download-for-client
68        $audio['free'] = true;
69
70        return $audio;
71    }
72
73
74    /**
75     * Handle the match
76     */
77    function handle($match, $state, $pos, Doku_Handler $handler){
78        global $conf;
79        global $ID;
80        $match = substr($match, strlen('{{jPlayerPlaylist>'), -2); //strip markup from start and end
81        $data = array('unique_id' => $pos);
82        $data['audio'] = array();
83        // extract params
84        $files_and_namespaces = preg_split('/\s+/', $match);
85        //remove empty
86        $files_and_namespaces = array_filter($files_and_namespaces);
87
88        foreach ($files_and_namespaces as $file) {
89            // namespace (including resolving relatives)
90            resolve_mediaid(getNS($ID), $file, $exists);
91            if (!$exists) {
92                msg("jPlayerPlaylist: file \"$file\" doesn't exist", -1);
93                continue;
94            }
95
96            $auth = auth_quickaclcheck($file);
97            if ($auth < AUTH_READ) {
98                msg("jPlayerPlaylist: no read permission to \"$file\"", -1);
99                continue;
100            }
101
102            $dir = utf8_encodeFN(str_replace(':','/',$file));
103            $full_path = $conf['mediadir'] . '/' . $dir;
104            if (is_dir($full_path)) {
105                $sort = 'natural';
106                search($files, $conf['mediadir'], 'search_media',
107                       array('showmsg' => false, 'depth' => 1), $dir, 1, $sort);
108
109                $max = (int) $this->getConf('max_audio_files_per_player');
110                if (is_array($files)) foreach ($files as $item) {
111                    if ($max == 0) {
112                        break;
113                    }
114                    $data['audio'][] = $this->_audio($item);
115                    $max -= 1;
116                }
117            } else {
118                $data['audio'][] = $this->_audio(array(
119                    'file' => $full_path,
120                    'id' => $file
121                ));
122            }
123        }
124
125        return $data;
126    }
127
128    private function render_metadata(Doku_Renderer $R, $data) {
129        $plugin_name = $this->getPluginName();
130        $unique_id = $data['unique_id'];
131
132        if (!isset($R->meta['plugin'][$plugin_name])) $R->meta['plugin'][$plugin_name] = array();
133
134        $ids = array(
135            'JPLAYER' => 'jquery_jplayer__' . $unique_id,
136            'WRAPPER' => 'jp_container__' . $unique_id
137        );
138
139        $options = array(
140            'swfPath' => DOKU_BASE . 'lib/plugins/jplayer/vendor/happyworm/jplayer/dist/jplayer',
141            'supplied' => 'oga, mp3',
142            'wmode' => 'window',
143            'useStateClassSkin' => true,
144            'autoBlur' => false,
145            'smoothPlayBar' => true,
146            'keyEnabled' => true
147        );
148
149        $R->meta['plugin'][$plugin_name][$unique_id] = array(
150            'ids' => $ids,
151            'audio' => $data['audio'],
152            'options' => $options
153        );
154    }
155
156    private function render_xhtml(Doku_Renderer $R, $data) {
157        global $ID;
158
159        $plugin_name = $this->getPluginName();
160        $unique_id = $data['unique_id'];
161
162        $skin = $this->getConf('skin');
163
164        $tpl_path = DOKU_PLUGIN .
165            'jplayer/vendor/happyworm/jplayer/dist/skin/'.$skin.'/mustache/';
166        // use .html instead of .mustache for default template extension
167        $options =  array('extension' => '.html');
168        $mustache = new Mustache_Engine(array(
169                                            'loader' => new Mustache_Loader_FilesystemLoader($tpl_path, $options)
170                                        ));
171        $tpl = $mustache->loadTemplate('jplayer.'.$skin.'.audio.playlist');
172
173        $meta = p_get_metadata($ID, "plugin $plugin_name");
174        $ids = $meta[$unique_id]['ids'];
175        $R->doc .= $tpl->render($ids);
176    }
177
178    /**
179     * Create output
180     */
181    function render($mode, Doku_Renderer $R, $data) {
182        $method = "render_$mode";
183        if (method_exists($this, $method)) {
184            call_user_func(array($this, $method), $R, $data);
185            return true;
186        }
187        return false;
188    }
189}
190