Differences Between: [Versions 311 and 402] [Versions 311 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * This plugin is used to access youtube videos 19 * 20 * @since Moodle 2.0 21 * @package repository_youtube 22 * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 require_once($CFG->dirroot . '/repository/lib.php'); 26 27 /** 28 * repository_youtube class 29 * 30 * @since Moodle 2.0 31 * @package repository_youtube 32 * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org} 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 36 class repository_youtube extends repository { 37 /** @var int maximum number of thumbs per page */ 38 const YOUTUBE_THUMBS_PER_PAGE = 27; 39 40 /** 41 * API key for using the YouTube Data API. 42 * @var mixed 43 */ 44 private $apikey; 45 46 /** 47 * Google Client. 48 * @var Google_Client 49 */ 50 private $client = null; 51 52 /** 53 * YouTube Service. 54 * @var Google_Service_YouTube 55 */ 56 private $service = null; 57 58 /** 59 * Youtube plugin constructor 60 * @param int $repositoryid 61 * @param object $context 62 * @param array $options 63 */ 64 public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) { 65 parent::__construct($repositoryid, $context, $options); 66 67 $this->apikey = $this->get_option('apikey'); 68 69 // Without an API key, don't show this repo to users as its useless without it. 70 if (empty($this->apikey)) { 71 $this->disabled = true; 72 } 73 } 74 75 /** 76 * Init all the youtube client service stuff. 77 * 78 * Instead of instantiating the service in the constructor, we delay 79 * it until really neeed because it's really memory hungry (2MB). That 80 * way the editor or any other artifact requiring repository instantiation 81 * can do it in a cheap way. Sort of lazy loading the plugin. 82 */ 83 private function init_youtube_service() { 84 global $CFG; 85 86 if (!isset($this->service)) { 87 require_once($CFG->libdir . '/google/lib.php'); 88 $this->client = get_google_client(); 89 $this->client->setDeveloperKey($this->apikey); 90 $this->client->setScopes(array(Google_Service_YouTube::YOUTUBE_READONLY)); 91 $this->service = new Google_Service_YouTube($this->client); 92 } 93 } 94 95 /** 96 * Save apikey in config table. 97 * @param array $options 98 * @return boolean 99 */ 100 public function set_option($options = array()) { 101 if (!empty($options['apikey'])) { 102 set_config('apikey', trim($options['apikey']), 'youtube'); 103 } 104 unset($options['apikey']); 105 return parent::set_option($options); 106 } 107 108 /** 109 * Get apikey from config table. 110 * 111 * @param string $config 112 * @return mixed 113 */ 114 public function get_option($config = '') { 115 if ($config === 'apikey') { 116 return trim(get_config('youtube', 'apikey')); 117 } else { 118 $options['apikey'] = trim(get_config('youtube', 'apikey')); 119 } 120 return parent::get_option($config); 121 } 122 123 public function check_login() { 124 return !empty($this->keyword); 125 } 126 127 /** 128 * Return search results 129 * @param string $search_text 130 * @return array 131 */ 132 public function search($search_text, $page = 0) { 133 global $SESSION; 134 $sort = optional_param('youtube_sort', '', PARAM_TEXT); 135 $sess_keyword = 'youtube_'.$this->id.'_keyword'; 136 $sess_sort = 'youtube_'.$this->id.'_sort'; 137 138 // This is the request of another page for the last search, retrieve the cached keyword and sort 139 if ($page && !$search_text && isset($SESSION->{$sess_keyword})) { 140 $search_text = $SESSION->{$sess_keyword}; 141 } 142 if ($page && !$sort && isset($SESSION->{$sess_sort})) { 143 $sort = $SESSION->{$sess_sort}; 144 } 145 if (!$sort) { 146 $sort = 'relevance'; // default 147 } 148 149 // Save this search in session 150 $SESSION->{$sess_keyword} = $search_text; 151 $SESSION->{$sess_sort} = $sort; 152 153 $this->keyword = $search_text; 154 $ret = array(); 155 $ret['nologin'] = true; 156 $ret['page'] = (int)$page; 157 if ($ret['page'] < 1) { 158 $ret['page'] = 1; 159 } 160 $start = ($ret['page'] - 1) * self::YOUTUBE_THUMBS_PER_PAGE + 1; 161 $max = self::YOUTUBE_THUMBS_PER_PAGE; 162 $ret['list'] = $this->_get_collection($search_text, $start, $max, $sort); 163 $ret['norefresh'] = true; 164 $ret['nosearch'] = true; 165 // If the number of results is smaller than $max, it means we reached the last page. 166 $ret['pages'] = (count($ret['list']) < $max) ? $ret['page'] : -1; 167 return $ret; 168 } 169 170 /** 171 * Private method to get youtube search results 172 * @param string $keyword 173 * @param int $start 174 * @param int $max max results 175 * @param string $sort 176 * @throws moodle_exception If the google API returns an error. 177 * @return array 178 */ 179 private function _get_collection($keyword, $start, $max, $sort) { 180 global $SESSION; 181 182 // The new API doesn't use "page" numbers for browsing through results. 183 // It uses a prev and next token in each set that you need to use to 184 // request the next page of results. 185 $sesspagetoken = 'youtube_'.$this->id.'_nextpagetoken'; 186 $pagetoken = ''; 187 if ($start > 1 && isset($SESSION->{$sesspagetoken})) { 188 $pagetoken = $SESSION->{$sesspagetoken}; 189 } 190 191 $list = array(); 192 $error = null; 193 try { 194 $this->init_youtube_service(); // About to use the service, ensure it's loaded. 195 $response = $this->service->search->listSearch('id,snippet', array( 196 'q' => $keyword, 197 'maxResults' => $max, 198 'order' => $sort, 199 'pageToken' => $pagetoken, 200 'type' => 'video', 201 'videoEmbeddable' => 'true', 202 )); 203 204 // Track the next page token for the next request (when a user 205 // scrolls down in the file picker for more videos). 206 $SESSION->{$sesspagetoken} = $response['nextPageToken']; 207 208 foreach ($response['items'] as $result) { 209 $title = $result->snippet->title; 210 $source = 'http://www.youtube.com/v/' . $result->id->videoId . '#' . $title; 211 $thumb = $result->snippet->getThumbnails()->getDefault(); 212 213 $list[] = array( 214 'shorttitle' => $title, 215 'thumbnail_title' => $result->snippet->description, 216 'title' => $title.'.avi', // This is a hack so we accept this file by extension. 217 'thumbnail' => $thumb->url, 218 'thumbnail_width' => (int)$thumb->width, 219 'thumbnail_height' => (int)$thumb->height, 220 'size' => '', 221 'date' => '', 222 'source' => $source, 223 ); 224 } 225 } catch (Google_Service_Exception $e) { 226 // If we throw the google exception as-is, we may expose the apikey 227 // to end users. The full message in the google exception includes 228 // the apikey param, so we take just the part pertaining to the 229 // actual error. 230 $error = $e->getErrors()[0]['message']; 231 throw new moodle_exception('apierror', 'repository_youtube', '', $error); 232 } 233 234 return $list; 235 } 236 237 /** 238 * Youtube plugin doesn't support global search 239 */ 240 public function global_search() { 241 return false; 242 } 243 244 public function get_listing($path='', $page = '') { 245 return array(); 246 } 247 248 /** 249 * Generate search form 250 */ 251 public function print_login($ajax = true) { 252 $ret = array(); 253 $search = new stdClass(); 254 $search->type = 'text'; 255 $search->id = 'youtube_search'; 256 $search->name = 's'; 257 $search->label = get_string('search', 'repository_youtube').': '; 258 $sort = new stdClass(); 259 $sort->type = 'select'; 260 $sort->options = array( 261 (object)array( 262 'value' => 'relevance', 263 'label' => get_string('sortrelevance', 'repository_youtube') 264 ), 265 (object)array( 266 'value' => 'date', 267 'label' => get_string('sortpublished', 'repository_youtube') 268 ), 269 (object)array( 270 'value' => 'rating', 271 'label' => get_string('sortrating', 'repository_youtube') 272 ), 273 (object)array( 274 'value' => 'viewCount', 275 'label' => get_string('sortviewcount', 'repository_youtube') 276 ) 277 ); 278 $sort->id = 'youtube_sort'; 279 $sort->name = 'youtube_sort'; 280 $sort->label = get_string('sortby', 'repository_youtube').': '; 281 $ret['login'] = array($search, $sort); 282 $ret['login_btn_label'] = get_string('search'); 283 $ret['login_btn_action'] = 'search'; 284 $ret['allowcaching'] = true; // indicates that login form can be cached in filepicker.js 285 return $ret; 286 } 287 288 /** 289 * file types supported by youtube plugin 290 * @return array 291 */ 292 public function supported_filetypes() { 293 return array('video'); 294 } 295 296 /** 297 * Youtube plugin only return external links 298 * @return int 299 */ 300 public function supported_returntypes() { 301 return FILE_EXTERNAL; 302 } 303 304 /** 305 * Is this repository accessing private data? 306 * 307 * @return bool 308 */ 309 public function contains_private_data() { 310 return false; 311 } 312 313 /** 314 * Add plugin settings input to Moodle form. 315 * @param object $mform 316 * @param string $classname 317 */ 318 public static function type_config_form($mform, $classname = 'repository') { 319 parent::type_config_form($mform, $classname); 320 $apikey = get_config('youtube', 'apikey'); 321 if (empty($apikey)) { 322 $apikey = ''; 323 } 324 325 $mform->addElement('text', 'apikey', get_string('apikey', 'repository_youtube'), array('value' => $apikey, 'size' => '40')); 326 $mform->setType('apikey', PARAM_RAW_TRIMMED); 327 $mform->addRule('apikey', get_string('required'), 'required', null, 'client'); 328 329 $mform->addElement('static', null, '', get_string('information', 'repository_youtube')); 330 } 331 332 /** 333 * Names of the plugin settings 334 * @return array 335 */ 336 public static function get_type_option_names() { 337 return array('apikey', 'pluginname'); 338 } 339 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body