1 | <?php
|
---|
2 | /**
|
---|
3 | * Copyright 2006, 2007, 2008, 2009 Eric D. Hough (http://ehough.com)
|
---|
4 | *
|
---|
5 | * This file is part of TubePress (http://tubepress.org)
|
---|
6 | *
|
---|
7 | * TubePress is free software: you can redistribute it and/or modify
|
---|
8 | * it under the terms of the GNU General Public License as published by
|
---|
9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
10 | * (at your option) any later version.
|
---|
11 | *
|
---|
12 | * TubePress is distributed in the hope that it will be useful,
|
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
15 | * GNU General Public License for more details.
|
---|
16 | *
|
---|
17 | * You should have received a copy of the GNU General Public License
|
---|
18 | * along with TubePress. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | *
|
---|
20 | */
|
---|
21 |
|
---|
22 | function_exists('tubepress_load_classes')
|
---|
23 | || require(dirname(__FILE__) . '/../../../../tubepress_classloader.php');
|
---|
24 | tubepress_load_classes(array('org_tubepress_video_factory_VideoFactory',
|
---|
25 | 'org_tubepress_video_Video'));
|
---|
26 |
|
---|
27 | /**
|
---|
28 | * Simple implementation of org_tubepress_video_factory_VideoFactory
|
---|
29 | */
|
---|
30 | class org_tubepress_video_factory_SimpleVideoFactory implements org_tubepress_video_factory_VideoFactory
|
---|
31 | {
|
---|
32 | private $_mediaGroup;
|
---|
33 |
|
---|
34 | /* shorthands for the namespaces */
|
---|
35 | const NS_APP = 'http://www.w3.org/2007/app';
|
---|
36 | const NS_MEDIA = 'http://search.yahoo.com/mrss/';
|
---|
37 | const NS_YT = 'http://gdata.youtube.com/schemas/2007';
|
---|
38 | const NS_GD = 'http://schemas.google.com/g/2005';
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * Main method
|
---|
42 | *
|
---|
43 | * @param DOMDocument $rss The raw XML of what we got from YouTube
|
---|
44 | * @param int $limit The maximum size of the array to return
|
---|
45 | *
|
---|
46 | * @return array An array of TubePressVideos (may be empty)
|
---|
47 | */
|
---|
48 | public function dom2TubePressVideoArray(DOMDocument $rss, $limit)
|
---|
49 | {
|
---|
50 | $results = array();
|
---|
51 | $entries = $rss->getElementsByTagName('entry');
|
---|
52 |
|
---|
53 | /* create a org_tubepress_video_Video out of each "entry" node */
|
---|
54 | for ($j = 0; $j < min($limit, $entries->length); $j++) {
|
---|
55 | $results[] = $this->_createVideo($entries->item($j));
|
---|
56 | }
|
---|
57 | return $results;
|
---|
58 | }
|
---|
59 |
|
---|
60 | /**
|
---|
61 | * Creates a video from a single "entry" XML node
|
---|
62 | *
|
---|
63 | * @param DOMNode $entry The "entry" XML node
|
---|
64 | *
|
---|
65 | * @return org_tubepress_video_Video The org_tubepress_video_Video representation of this node
|
---|
66 | */
|
---|
67 | private function _createVideo(DOMNode $entry)
|
---|
68 | {
|
---|
69 | $vid = new org_tubepress_video_Video();
|
---|
70 |
|
---|
71 | /* see if the video is actually available, not just a stub */
|
---|
72 | if ($this->_videoNotAvailable($entry)) {
|
---|
73 | $vid->setDisplayable(false);
|
---|
74 | return $vid;
|
---|
75 | }
|
---|
76 | $vid->setDisplayable(true);
|
---|
77 |
|
---|
78 | $this->_mediaGroup =
|
---|
79 | $entry->getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_MEDIA,
|
---|
80 | 'group')->item(0);
|
---|
81 |
|
---|
82 | /* everyone loves the builder pattern */
|
---|
83 | $vid->setAuthor($this->_getAuthor($entry));
|
---|
84 | $vid->setCategory($this->_getCategory($entry));
|
---|
85 | $vid->setDescription($this->_getDescription($entry));
|
---|
86 | $vid->setId($this->_getId($entry));
|
---|
87 | $vid->setLength($this->_getRuntime($entry));
|
---|
88 | $vid->setRating($this->_getRatingAverage($entry));
|
---|
89 | $vid->setRatings($this->_getRatingCount($entry));
|
---|
90 | $vid->setTags($this->_getTags($entry));
|
---|
91 | $vid->setThumbUrls($this->_getThumbUrls($entry));
|
---|
92 | $vid->setTitle($this->_getTitle($entry));
|
---|
93 | $vid->setUploadTime($this->_getUploadTime($entry));
|
---|
94 | $vid->setViews($this->_getViewCount($entry));
|
---|
95 | $vid->setYouTubeUrl($this->_getURL($entry));
|
---|
96 | return $vid;
|
---|
97 | }
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * Gets the YouTube author from the XML
|
---|
101 | *
|
---|
102 | * @param DOMElement $rss The "entry" XML element
|
---|
103 | *
|
---|
104 | * @return string The YouTube author from the XML
|
---|
105 | */
|
---|
106 | private function _getAuthor(DOMElement $rss)
|
---|
107 | {
|
---|
108 | $authorNode = $rss->getElementsByTagName('author')->item(0);
|
---|
109 | return $authorNode->getElementsByTagName('name')->item(0)->nodeValue;
|
---|
110 | }
|
---|
111 |
|
---|
112 | /**
|
---|
113 | * Gets the YouTube category from the XML
|
---|
114 | *
|
---|
115 | * @param DOMElement $rss The "entry" XML element
|
---|
116 | *
|
---|
117 | * @return string The YouTube category from the XML
|
---|
118 | */
|
---|
119 | private function _getCategory(DOMElement $rss)
|
---|
120 | {
|
---|
121 | return trim($rss->
|
---|
122 | getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_MEDIA,
|
---|
123 | 'category')->item(0)->nodeValue);
|
---|
124 | }
|
---|
125 |
|
---|
126 | /**
|
---|
127 | * Gets the video's description
|
---|
128 | *
|
---|
129 | * @param DOMElement $rss The "entry" XML element
|
---|
130 | *
|
---|
131 | * @return string The video's description
|
---|
132 | */
|
---|
133 | private function _getDescription(DOMElement $rss)
|
---|
134 | {
|
---|
135 | return trim($this->_mediaGroup->
|
---|
136 | getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_MEDIA,
|
---|
137 | 'description')->item(0)->nodeValue);
|
---|
138 | }
|
---|
139 |
|
---|
140 | /**
|
---|
141 | * Gets the video's ID from XML
|
---|
142 | *
|
---|
143 | * @param DOMElement $rss The "entry" XML element
|
---|
144 | *
|
---|
145 | * @return string The video's ID from XML
|
---|
146 | */
|
---|
147 | private function _getId(DOMElement $rss)
|
---|
148 | {
|
---|
149 | $thumb =
|
---|
150 | $rss->getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_MEDIA,
|
---|
151 | "thumbnail")->item(0);
|
---|
152 | $id = $thumb->getAttribute("url");
|
---|
153 | $id = substr($id, 0, strrpos($id, "/"));
|
---|
154 | $id = substr($id, strrpos($id, "/") + 1);
|
---|
155 | return $id;
|
---|
156 | }
|
---|
157 |
|
---|
158 | /**
|
---|
159 | * Gets the average rating of the video
|
---|
160 | *
|
---|
161 | * @param DOMElement $rss The "entry" XML element
|
---|
162 | *
|
---|
163 | * @return string The average rating of the video
|
---|
164 | */
|
---|
165 | private function _getRatingAverage(DOMElement $rss)
|
---|
166 | {
|
---|
167 | $count = $rss->getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_GD,
|
---|
168 | 'rating')->item(0);
|
---|
169 | if ($count != null) {
|
---|
170 | return $count->getAttribute('average');
|
---|
171 | }
|
---|
172 | return "N/A";
|
---|
173 | }
|
---|
174 |
|
---|
175 | /**
|
---|
176 | * Gets the number of times this video has been rated
|
---|
177 | *
|
---|
178 | * @param DOMElement $rss The "entry" XML element
|
---|
179 | *
|
---|
180 | * @return string The number of times this video has been rated
|
---|
181 | */
|
---|
182 | private function _getRatingCount(DOMElement $rss)
|
---|
183 | {
|
---|
184 | $count = $rss->getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_GD,
|
---|
185 | 'rating')->item(0);
|
---|
186 | if ($count != null) {
|
---|
187 | return number_format($count->getAttribute('numRaters'));
|
---|
188 | }
|
---|
189 | return "0";
|
---|
190 | }
|
---|
191 |
|
---|
192 | /**
|
---|
193 | * Gets the runtime of this video
|
---|
194 | *
|
---|
195 | * @param DOMElement $rss The "entry" XML element
|
---|
196 | *
|
---|
197 | * @return string The runtime of this video
|
---|
198 | */
|
---|
199 | private function _getRuntime(DOMElement $rss)
|
---|
200 | {
|
---|
201 | $duration =
|
---|
202 | $this->_mediaGroup->
|
---|
203 | getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_YT,
|
---|
204 | 'duration')->item(0);
|
---|
205 | return
|
---|
206 | org_tubepress_video_factory_SimpleVideoFactory::
|
---|
207 | _seconds2HumanTime($duration->getAttribute('seconds'));
|
---|
208 | }
|
---|
209 |
|
---|
210 | /**
|
---|
211 | * Gets the tags of this video (space separated)
|
---|
212 | *
|
---|
213 | * @param DOMElement $rss The "entry" XML element
|
---|
214 | *
|
---|
215 | * @return string The tags of this video (space separated)
|
---|
216 | */
|
---|
217 | private function _getTags(DOMElement $rss)
|
---|
218 | {
|
---|
219 | $rawKeywords =
|
---|
220 | $this->_mediaGroup->
|
---|
221 | getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_MEDIA,
|
---|
222 | 'keywords')->item(0);
|
---|
223 | return split(", ", trim($rawKeywords->nodeValue));
|
---|
224 | }
|
---|
225 |
|
---|
226 | /**
|
---|
227 | * Gets this video's thumbnail URLs
|
---|
228 | *
|
---|
229 | * @param DOMElement $rss The "entry" XML element
|
---|
230 | *
|
---|
231 | * @return array An array of this video's thumbnail URLs
|
---|
232 | */
|
---|
233 | private function _getThumbUrls(DOMElement $rss)
|
---|
234 | {
|
---|
235 | $results = array();
|
---|
236 | $thumbs =
|
---|
237 | $this->_mediaGroup->
|
---|
238 | getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_MEDIA,
|
---|
239 | 'thumbnail');
|
---|
240 | for ($x = 0; $x < $thumbs->length; $x++) {
|
---|
241 | array_push($results, $thumbs->item($x)->getAttribute('url'));
|
---|
242 | }
|
---|
243 | return $results;
|
---|
244 | }
|
---|
245 |
|
---|
246 | /**
|
---|
247 | * Gets this video's title
|
---|
248 | *
|
---|
249 | * @param DOMElement $rss The "entry" XML element
|
---|
250 | *
|
---|
251 | * @return string Get this video's title
|
---|
252 | */
|
---|
253 | private function _getTitle(DOMElement $rss)
|
---|
254 | {
|
---|
255 | $title =
|
---|
256 | $rss->getElementsByTagName('title')->item(0)->nodeValue;
|
---|
257 | return htmlspecialchars($title, ENT_QUOTES);
|
---|
258 | }
|
---|
259 |
|
---|
260 | /**
|
---|
261 | * Get this video's upload timestamp
|
---|
262 | *
|
---|
263 | * @param DOMElement $rss The "entry" XML element
|
---|
264 | *
|
---|
265 | * @return string This video's upload timestamp
|
---|
266 | */
|
---|
267 | private function _getUploadTime(DOMElement $rss)
|
---|
268 | {
|
---|
269 | $publishedNode = $rss->getElementsByTagName('published');
|
---|
270 | if ($publishedNode->length == 0) {
|
---|
271 | return "N/A";
|
---|
272 | }
|
---|
273 | $views = $publishedNode->item(0);
|
---|
274 | return org_tubepress_video_factory_SimpleVideoFactory::_rfc3339toHumanTime($views->nodeValue);
|
---|
275 | }
|
---|
276 |
|
---|
277 | /**
|
---|
278 | * Get this video's YouTube URL
|
---|
279 | *
|
---|
280 | * @param DOMElement $rss The "entry" XML element
|
---|
281 | *
|
---|
282 | * @return string This video's YouTube URL
|
---|
283 | */
|
---|
284 | private function _getURL(DOMElement $rss)
|
---|
285 | {
|
---|
286 | $links = $rss->getElementsByTagName('link');
|
---|
287 | for ($x = 0; $x < $links->length; $x++) {
|
---|
288 | $link = $links->item($x);
|
---|
289 | if ($link->getAttribute('rel') != 'alternate') {
|
---|
290 | continue;
|
---|
291 | }
|
---|
292 | return $link->getAttribute('href');
|
---|
293 | }
|
---|
294 | }
|
---|
295 |
|
---|
296 | /**
|
---|
297 | * Get the number of times this video has been viewed
|
---|
298 | *
|
---|
299 | * @param DOMElement $rss The "entry" XML element
|
---|
300 | *
|
---|
301 | * @return string The number of times this video has been viewed
|
---|
302 | */
|
---|
303 | private function _getViewCount(DOMElement $rss)
|
---|
304 | {
|
---|
305 | $stats = $rss->getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_YT,
|
---|
306 | 'statistics')->item(0);
|
---|
307 | if ($stats != null) {
|
---|
308 | return number_format($stats->getAttribute('viewCount'));
|
---|
309 | } else {
|
---|
310 | return "N/A";
|
---|
311 | }
|
---|
312 | }
|
---|
313 |
|
---|
314 | /**
|
---|
315 | * Converts gdata timestamps to human readable
|
---|
316 | *
|
---|
317 | * @param string $rfc3339 The RFC 3339 format of time
|
---|
318 | *
|
---|
319 | * @return string Human time format
|
---|
320 | */
|
---|
321 | private static function _rfc3339toHumanTime($rfc3339)
|
---|
322 | {
|
---|
323 | $tmp = str_replace("T", " ", $rfc3339);
|
---|
324 | $tmp = ereg_replace("(\.[0-9]{1,})?", "", $tmp);
|
---|
325 |
|
---|
326 | $datetime = substr($tmp, 0, 19);
|
---|
327 | $timezone = str_replace(":", "", substr($tmp, 19, 6));
|
---|
328 | return strtotime($datetime . " " . $timezone);
|
---|
329 | }
|
---|
330 |
|
---|
331 | /**
|
---|
332 | * Converts seconds to minutes and seconds
|
---|
333 | *
|
---|
334 | * @param string $length_seconds The runtime of a video, in seconds
|
---|
335 | *
|
---|
336 | * @return string Human time format
|
---|
337 | */
|
---|
338 | private static function _seconds2HumanTime($length_seconds)
|
---|
339 | {
|
---|
340 | $seconds = $length_seconds;
|
---|
341 | $length = intval($seconds / 60);
|
---|
342 | $leftOverSeconds = $seconds % 60;
|
---|
343 | if ($leftOverSeconds < 10) {
|
---|
344 | $leftOverSeconds = "0" . $leftOverSeconds;
|
---|
345 | }
|
---|
346 | $length .= ":" . $leftOverSeconds;
|
---|
347 | return $length;
|
---|
348 | }
|
---|
349 |
|
---|
350 | private function _videoNotAvailable(DOMNode $entry)
|
---|
351 | {
|
---|
352 | $control = $entry->getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_APP, 'control');
|
---|
353 | if ($control->length > 0) {
|
---|
354 | $state = $control->item(0)->getElementsByTagNameNS(org_tubepress_video_factory_SimpleVideoFactory::NS_YT, 'state');
|
---|
355 | if ($state->length > 0) {
|
---|
356 | return true;
|
---|
357 | }
|
---|
358 | }
|
---|
359 | return false;
|
---|
360 | }
|
---|
361 | }
|
---|