[44] | 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 | }
|
---|