-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapiclient.php
356 lines (304 loc) · 9.85 KB
/
apiclient.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
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
<?php
/**
* Team++ media API client
* The client for the media API <http://media.plusp.lu>
*
* @file apiclient.php
*
* @version 1.0.4
* @author Lukas Bestle <http://lu-x.me>
* @link https://github.com/TeamPlusPlus/apiclient
* @copyright Copyright 2013 Lukas Bestle
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
*/
// Set locale (German date formats!)
setlocale(LC_ALL, 'de_DE');
// State definitions
define('STATE_NO', 0);
define('STATE_OVER', 1);
define('STATE_SOON', 2);
define('STATE_LIVE', 3);
define('STATE_RECORDED', 4);
define('STATE_RELIVE', 5);
/**
* Episodes
*
* Episode API client
*/
class Episodes {
// Cache
static $newest = null;
static $next = null;
static $episodes = array();
/**
* Load the data from cache
*/
public static function loadCache() {
// Get the data from the file
$file = @file_get_contents(KIRBY_PROJECT_ROOT_CACHE . '/episodes.ser');
// Did it work (= does the file exist and is it valid)?
if(!($file && $data = @unserialize($file))) {
// No, write it first
static::writeCache();
return;
}
static::$newest = $data[0];
static::$next = $data[1];
static::$episodes = $data[2];
}
/**
* Write API data into cache
*/
public static function writeCache() {
// Get data from API
$data = json_decode(file_get_contents('http://media.plusp.lu/' . site()->subdomain() . '/all'), true);
// Put the episode data into cache
static::$episodes = $data['episodes'];
// Parse newest and next episodes
static::newest();
static::next();
// Shall it write the file?
if(!c::get('cache.episodes', false)) return;
// Write the cache file
file_put_contents(KIRBY_PROJECT_ROOT_CACHE . '/episodes.ser', serialize(array(
static::$newest,
static::$next,
static::$episodes
)));
}
/**
* Next episode
*
* @return Kirby\CMS\Page The page object with custom data
*/
public static function next() {
// Already in cache?
if(static::$next) return static::nextData(static::$next);
// Get the next episode
$result = static::newest()->next();
if(!$result) return static::nextData(null);
return static::nextData(static::$next = static::title($result, 3));
}
/**
* Current episode
*
* @return Kirby\CMS\Page The page object with custom data
*/
public static function newest() {
// Already in cache?
if(static::$newest) return site()->pages()->find('episodes/' . static::$newest);
// Iterate through all episodes beginning with the latest
$pages = site()->pages()->find('episodes')->children()->flip();
foreach($pages as $page) {
// Analyze the page
$data = static::infos($page, true);
// Check if it has all valid information to be published
if(!is_array($data) || !isset($data['files']['media']['mp3']) || !isset($data['files']['cover']['png']) || !$page->text() || !$page->title() || !$page->shownotes()) continue;
// It is published -> Return the page
return site()->pages()->find('episodes/' . static::$newest = static::title($page, 3));
}
}
/**
* Get the title of an episode
*
* @param Kirby\CMS\Page $episode The episode to get the title from
* @param int $type What type of title?
*
* @return mixed The title formatted like $type
*/
public static function title($episode, $type=0) {
// Titles for invalid pages
if(!is_object($episode) || $episode == new StdClass()) return '';
// Analyze URI
$episodeComponents = explode('/', $episode->uri());
// Is it an episode?
if(!isset($episodeComponents[1])) {
return (string)$episode->title();
}
// The episode name is the second element of the URI (`episodes/$episode`)
$episodeString = $episodeComponents[1];
$episodeID = (int)$episodeString;
// Return the appropriate type
switch($type) {
case 0:
return "#$episodeID ({$episode->title()})";
case 1:
return "#$episodeID <br>({$episode->title()})";
case 2:
return $episodeID;
case 3:
return $episodeString;
case 4:
return site()->title() . " #$episodeID ({$episode->title()})";
}
}
/**
* Parse information for an episode and add it to the Kirby\CMS\Page object
*
* @param Kirby\CMS\Page $episode The episode to parse
* @param boolean $raw Raw data or Kirby\CMS\Page object?
*
* @return mixed The page object with custom data or just an array with information
*/
public static function infos($episode, $raw=false) {
// Get the episode ID
$episodeID = static::title($episode, 2);
if(!isset(static::$episodes[$episodeID])) return ($raw)? array() : static::objectify();
// Get the data from the API cache array
$episodeData = static::$episodes[$episodeID];
// Either parse it and return the object or just return the array
return ($raw)? $episodeData : static::objectify($episodeData);
}
/**
* Parse shownotes and add timestamps
*
* @param string $shownotes The parsed HTML for the shownotes
* @param Kirby\CMS\Page $episode The episode to get the timestamps from
*
* @return string The parsed shownotes HTML including timestamps
*/
public static function shownotes($shownotes, $episode) {
// Get the chapters
$infos = static::infos($episode, true);
// Is there any information?
if(!$infos) return $shownotes;
$chapters = $infos['chapters'];
// Sort them by name
$chaptersAnalyzed = array();
foreach($chapters as $chapter) {
// Re-parse the time
$timeParts = explode('.', $chapter['start']);
// Add to re-indexed array
$chaptersAnalyzed[$chapter['title']] = $timeParts[0];
}
// Get all headings (separating the chapters)
$shownotes = preg_replace_callback('{(?<=<h3>).*?(?=</h3>)}', function($matches) use($chaptersAnalyzed) {
if(!isset($chaptersAnalyzed[$matches[0]])) {
// The chapter time is not defined
return $matches[0];
}
// Add the timestamp
return '[' . $chaptersAnalyzed[$matches[0]] . '] ' . $matches[0];
}, $shownotes);
return $shownotes;
}
/**
* Get the current state of the next episode
*
* @param string $id The episode ID
*
* @return Kirby\CMS\Page The page object with custom data
*/
private static function nextData($id) {
$state = STATE_NO;
$live = '';
$url = '';
$page = new StdClass();
// Is it a valid episode ID?
if(is_string($id)) {
// Get the time string
$page = site()->pages()->find("episodes/$id");
// Parse as time stamp
$timestamp = @strtotime($page->live());
// Ask the API if the episode is live
$results = json_decode(file_get_contents('http://media.plusp.lu/live/' . site()->subdomain()), true);
if($results['live'] == true) {
$state = STATE_LIVE;
$url = $results['url'];
} else if($timestamp == false) {
// No valid time stamp
if($page) {
// The page does exist and is ready but the media files are not ready
$state = STATE_RECORDED;
}
} else if($timestamp + 1800 <= time()) {
// 1.5h after the live date -> Episode is already over
$state = STATE_RECORDED;
} else {
// On air soon
$state = STATE_SOON;
// Dates
$ymdLive = date('Ymd', $timestamp);
$ymdToday = date('Ymd');
if($ymdLive > $ymdToday + 6) {
// More than one week in the future
if($timestamp % 3600) {
// It has minutes
$timestring = '%d. %B %G ~%H:%M Uhr';
} else {
// Only hours
$timestring = '%d. %B %G ~%H Uhr';
}
} else if($ymdToday == $ymdLive) {
// Today
if($timestamp % 3600) {
// It has minutes
$timestring = 'Heute ~%H:%M Uhr';
} else {
// Only hours
$timestring = 'Heute ~%H Uhr';
}
} else {
// This week
if($timestamp % 3600) {
// It has minutes
$timestring = '%A ~%H:%M Uhr';
} else {
// Only hours
$timestring = '%A ~%H Uhr';
}
}
// Build the correct date format
$live = strftime($timestring, $timestamp);
}
}
// Check if a ReLive is available
if($state == STATE_RECORDED && static::status('http://media.plusp.lu/' . site()->subdomain() . '/' . $id . '.relive') == 'HTTP 200 OK') {
// Yep
$state = STATE_RELIVE;
}
// Add the information to the page
$page->infos = new StdClass();
$page->infos->state = $state;
$page->infos->live = $live;
$page->infos->url = $url;
$page->infos->id = ($id)? (int)$id : static::$newest + 1;
$page->infos->number = '#' . $page->infos->id;
return $page;
}
/**
* Build an object from data
*
* @param array $data Data as array
*
* @return StdClass The objectified data
*/
private static function objectify($data=array()) {
$obj = new StdClass();
// Files
$obj->image = isset($data['files']['cover']['png'])? $data['files']['cover']['png'] : null;
$obj->psc = isset($data['files']['meta']['psc'])? $data['files']['meta']['psc'] : null;
$obj->m4a = isset($data['files']['media']['m4a'])? $data['files']['media']['m4a'] : null;
$obj->mp3 = isset($data['files']['media']['mp3'])? $data['files']['media']['mp3'] : null;
$obj->ogg = isset($data['files']['media']['ogg'])? $data['files']['media']['ogg'] : null;
$obj->opus = isset($data['files']['media']['opus'])? $data['files']['media']['opus'] : null;
// Other information
$obj->infos = isset($data['infos'])? $data['infos'] : array();
$obj->duration = isset($data['duration'])? $data['duration'] : 0;
$obj->chapters = isset($data['chapters'])? $data['chapters'] : array();
return $obj;
}
/**
* Requests HTTP headers and returns the HTTP status
*
* @param string $url URL
* @return int HTTP status code
*/
private static function status($url) {
$headers = @get_headers($url);
$status = (isset($headers[0]))? $headers[0] : 'HTTP 0';
return $status;
}
}
// Load the data when the class loads
Episodes::loadCache();