2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
20 * @package block_tag_youtube
21 * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 define('DEFAULT_NUMBER_OF_VIDEOS', 5);
27 class block_tag_youtube
extends block_base
{
30 * @var Google_Service_Youtube
32 protected $service = null;
35 $this->title
= get_string('pluginname','block_tag_youtube');
36 $this->config
= new stdClass();
39 function applicable_formats() {
40 return array('tag' => true);
44 * It can be configured.
48 public function has_config() {
52 function specialization() {
53 $this->title
= !empty($this->config
->title
) ?
$this->config
->title
: get_string('pluginname', 'block_tag_youtube');
54 // Convert numeric categories (old YouTube API) to
55 // textual ones (new Google Data API)
56 $this->config
->category
= !empty($this->config
->category
) ?
$this->category_map_old2new($this->config
->category
) : '0';
59 function instance_allow_multiple() {
63 function get_content() {
66 //note: do NOT include files at the top of this file
67 require_once($CFG->libdir
. '/filelib.php');
69 if ($this->content
!== NULL) {
70 return $this->content
;
73 $this->content
= new stdClass();
74 $this->content
->footer
= '';
76 if (!$this->get_service()) {
77 $this->content
->text
= $this->get_error_message();
78 return $this->content
;
82 if(!empty($this->config
->playlist
)){
83 //videos from a playlist
84 $text = $this->get_videos_by_playlist();
87 if(!empty($this->config
->category
)){
88 //videos from category with tag
89 $text = $this->get_videos_by_tag_and_category();
93 $text = $this->get_videos_by_tag();
97 $this->content
->text
= $text;
99 return $this->content
;
102 function get_videos_by_playlist(){
104 if (!$service = $this->get_service()) {
105 return $this->get_error_message();
108 $numberofvideos = DEFAULT_NUMBER_OF_VIDEOS
;
109 if( !empty($this->config
->numberofvideos
)) {
110 $numberofvideos = $this->config
->numberofvideos
;
114 $response = $service->playlistItems
->listPlaylistItems('id,snippet', array(
115 'playlistId' => $this->config
->playlist
,
116 'maxResults' => $numberofvideos
118 } catch (Google_Service_Exception
$e) {
119 debugging('Google service exception: ' . $e->getMessage(), DEBUG_DEVELOPER
);
120 return $this->get_error_message(get_string('requesterror', 'block_tag_youtube'));
123 return $this->render_items($response);
126 function get_videos_by_tag(){
128 if (!$service = $this->get_service()) {
129 return $this->get_error_message();
132 $tagid = optional_param('id', 0, PARAM_INT
); // tag id - for backware compatibility
133 $tag = optional_param('tag', '', PARAM_TAG
); // tag
134 $tc = optional_param('tc', 0, PARAM_INT
); // Tag collection id.
137 $tagobject = core_tag_tag
::get($tagid);
139 $tagobject = core_tag_tag
::get_by_name($tc, $tag);
142 if (empty($tagobject)) {
146 $querytag = urlencode($tagobject->name
);
148 $numberofvideos = DEFAULT_NUMBER_OF_VIDEOS
;
149 if ( !empty($this->config
->numberofvideos
) ) {
150 $numberofvideos = $this->config
->numberofvideos
;
154 $response = $service->search
->listSearch('id,snippet', array(
157 'maxResults' => $numberofvideos
159 } catch (Google_Service_Exception
$e) {
160 debugging('Google service exception: ' . $e->getMessage(), DEBUG_DEVELOPER
);
161 return $this->get_error_message(get_string('requesterror', 'block_tag_youtube'));
164 return $this->render_items($response);
167 function get_videos_by_tag_and_category(){
169 if (!$service = $this->get_service()) {
170 return $this->get_error_message();
173 $tagid = optional_param('id', 0, PARAM_INT
); // tag id - for backware compatibility
174 $tag = optional_param('tag', '', PARAM_TAG
); // tag
175 $tc = optional_param('tc', 0, PARAM_INT
); // Tag collection id.
178 $tagobject = core_tag_tag
::get($tagid);
180 $tagobject = core_tag_tag
::get_by_name($tc, $tag);
183 if (empty($tagobject)) {
187 $querytag = urlencode($tagobject->name
);
189 $numberofvideos = DEFAULT_NUMBER_OF_VIDEOS
;
190 if( !empty($this->config
->numberofvideos
)) {
191 $numberofvideos = $this->config
->numberofvideos
;
195 $response = $service->search
->listSearch('id,snippet', array(
198 'maxResults' => $numberofvideos,
199 'videoCategoryId' => $this->config
->category
201 } catch (Google_Service_Exception
$e) {
202 debugging('Google service exception: ' . $e->getMessage(), DEBUG_DEVELOPER
);
203 return $this->get_error_message(get_string('requesterror', 'block_tag_youtube'));
206 return $this->render_items($response);
210 * Sends a request to fetch data.
212 * @see block_tag_youtube::service
213 * @deprecated since Moodle 2.8.8, 2.9.2 and 3.0 MDL-49085 - please do not use this function any more.
214 * @param string $request
215 * @throws coding_exception
217 public function fetch_request($request) {
218 throw new coding_exception('Sorry, this function has been deprecated in Moodle 2.8.8, 2.9.2 and 3.0. Use block_tag_youtube::get_service instead.');
220 $c = new curl(array('cache' => true, 'module_cache'=>'tag_youtube'));
221 $c->setopt(array('CURLOPT_TIMEOUT' => 3, 'CURLOPT_CONNECTTIMEOUT' => 3));
223 $response = $c->get($request);
225 $xml = new SimpleXMLElement($response);
226 return $this->render_video_list($xml);
230 * Renders the video list.
232 * @see block_tag_youtube::render_items
233 * @deprecated since Moodle 2.8.8, 2.9.2 and 3.0 MDL-49085 - please do not use this function any more.
234 * @param SimpleXMLElement $xml
235 * @throws coding_exception
237 function render_video_list(SimpleXMLElement
$xml){
238 throw new coding_exception('Sorry, this function has been deprecated in Moodle 2.8.8, 2.9.2 and 3.0. Use block_tag_youtube::render_items instead.');
242 * Returns an error message.
244 * Useful when the block is not properly set or something goes wrong.
246 * @param string $message The message to display.
247 * @return string HTML
249 protected function get_error_message($message = null) {
252 if (empty($message)) {
253 $message = get_string('apierror', 'block_tag_youtube');
255 return $OUTPUT->notification($message);
259 * Gets the youtube service object.
261 * @return Google_Service_YouTube
263 protected function get_service() {
266 if (!$apikey = get_config('block_tag_youtube', 'apikey')) {
270 // Wrapped in an if in case we call different get_videos_* multiple times.
271 if (!isset($this->service
)) {
272 require_once($CFG->libdir
. '/google/lib.php');
273 $client = get_google_client();
274 $client->setDeveloperKey($apikey);
275 $client->setScopes(array(Google_Service_YouTube
::YOUTUBE_READONLY
));
276 $this->service
= new Google_Service_YouTube($client);
279 return $this->service
;
283 * Renders the list of items.
285 * @param array $videosdata
286 * @return string HTML
288 protected function render_items($videosdata) {
290 if (!$videosdata ||
empty($videosdata->items
)) {
291 if (!empty($videosdata->error
)) {
292 debugging('Error fetching data from youtube: ' . $videosdata->error
->message
, DEBUG_DEVELOPER
);
297 // If we reach that point we already know that the API key is set.
298 $service = $this->get_service();
300 $text = html_writer
::start_tag('ul', array('class' => 'yt-video-entry unlist img-text'));
301 foreach ($videosdata->items
as $video) {
303 // Link to the video included in the playlist if listing a playlist.
304 if (!empty($video->snippet
->resourceId
)) {
305 $id = $video->snippet
->resourceId
->videoId
;
306 $playlist = '&list=' . $video->snippet
->playlistId
;
308 $id = $video->id
->videoId
;
312 $thumbnail = $video->snippet
->getThumbnails()->getDefault();
313 $url = 'http://www.youtube.com/watch?v=' . $id . $playlist;
315 $videodetails = $service->videos
->listVideos('id,contentDetails', array('id' => $id));
316 if ($videodetails && !empty($videodetails->items
)) {
318 // We fetch by id so we just use the first one.
319 $details = $videodetails->items
[0];
320 $start = new DateTime('@0');
321 $start->add(new DateInterval($details->contentDetails
->duration
));
322 $seconds = $start->format('U');
325 $text .= html_writer
::start_tag('li');
327 $imgattrs = array('class' => 'youtube-thumb', 'src' => $thumbnail->url
, 'alt' => $video->snippet
->title
);
328 $thumbhtml = html_writer
::empty_tag('img', $imgattrs);
329 $link = html_writer
::tag('a', $thumbhtml, array('href' => $url));
330 $text .= html_writer
::tag('div', $link, array('class' => 'clearfix'));
332 $text .= html_writer
::tag('span', html_writer
::tag('a', $video->snippet
->title
, array('href' => $url)));
334 if (!empty($seconds)) {
335 $text .= html_writer
::tag('div', format_time($seconds));
337 $text .= html_writer
::end_tag('li');
339 $text .= html_writer
::end_tag('ul');
344 function get_categories() {
345 // TODO: Right now using sticky categories from
346 // http://gdata.youtube.com/schemas/2007/categories.cat
347 // This should be performed from time to time by the block insead
348 // and cached somewhere, avoiding deprecated ones and observing regions
350 '0' => get_string('anycategory', 'block_tag_youtube'),
351 'Film' => get_string('filmsanimation', 'block_tag_youtube'),
352 'Autos' => get_string('autosvehicles', 'block_tag_youtube'),
353 'Music' => get_string('music', 'block_tag_youtube'),
354 'Animals'=> get_string('petsanimals', 'block_tag_youtube'),
355 'Sports' => get_string('sports', 'block_tag_youtube'),
356 'Travel' => get_string('travel', 'block_tag_youtube'),
357 'Games' => get_string('gadgetsgames', 'block_tag_youtube'),
358 'Comedy' => get_string('comedy', 'block_tag_youtube'),
359 'People' => get_string('peopleblogs', 'block_tag_youtube'),
360 'News' => get_string('newspolitics', 'block_tag_youtube'),
361 'Entertainment' => get_string('entertainment', 'block_tag_youtube'),
362 'Education' => get_string('education', 'block_tag_youtube'),
363 'Howto' => get_string('howtodiy', 'block_tag_youtube'),
364 'Tech' => get_string('scienceandtech', 'block_tag_youtube')
369 * Provide conversion from old numeric categories available in youtube API
370 * to the new ones available in the Google API
372 * @param int $oldcat old category code
373 * @return mixed new category code or 0 (if no match found)
375 * TODO: Someday this should be applied on upgrade for all the existing
376 * block instances so we won't need the mapping any more. That would imply
377 * to implement restore handling to perform the conversion of old blocks.
379 function category_map_old2new($oldcat) {
380 $oldoptions = array (
385 24 => 'Entertainment',
395 if (array_key_exists($oldcat, $oldoptions)) {
396 return $oldoptions[$oldcat];