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