From 09a721a6381fe2a581444d10463eaccc805f1b95 Mon Sep 17 00:00:00 2001 From: Ed Linklater Date: Mon, 30 Oct 2017 15:09:31 +1300 Subject: [PATCH] Show a cut-down version of the infobox without needing YouTube API key --- README.md | 49 +++++++++++++++++++++++--------------- code/YouTubeField.php | 48 +++++++++++++++++++++++++++---------- composer.json | 7 +++--- javascript/YouTubeField.js | 24 ++++++++++++------- 4 files changed, 85 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 5870076..2ea9ad4 100644 --- a/README.md +++ b/README.md @@ -2,44 +2,55 @@ ## Introduction -This SilverStripe module provides a simple YouTube field, primarily for use in the CMS/ModelAdmin. It accepts input of -various common YouTube URL formats and converts them for storage in database as the 11-character YouTube ID. +This SilverStripe module provides a YouTube field for use in the CMS/ModelAdmin. It accepts input of various common +YouTube URL formats and converts them for storage in database as the 11-character YouTube ID. + +Once a valid ID is saved the field will display the video's thumbnail and title. + +Optionally you can provide a key for the YouTube v3 API, which is used to display additional information (duration and +view count) and provides information immediately (rather than after saving). + +![Screenshot of Video Information](https://cloud.githubusercontent.com/assets/1176635/10863696/39612420-803c-11e5-8940-95e190c06545.png) ## Requirements - * silverstripe/framework 3.0+ for basic field and URL parser - * silverstripe/framework 3.3+ for video information support + * silverstripe/framework 3.3+ ## Basic field +*mysite/code/Page.php* + +```php + 'Varchar(11)', ); - + public function getCMSFields() { $fields = parent::getCMSFields(); $fields->addFieldToTab('Root.Main', new YouTubeField('VideoID', 'YouTube Video')); return $fields; } + +} +``` -## Video Information - -Optionally you can provide a key for the YouTube v3 API, which is used to display video information (title, thumbnail, -length) under the field when a valid ID has been provided. - -![Screenshot of Video Information](https://cloud.githubusercontent.com/assets/1176635/10863696/39612420-803c-11e5-8940-95e190c06545.png) - -*mysite/_config/youtubefield.yml* +*mysite/_config/config.yml* - --- - name: youtubefield - --- - YouTubeField: - api_key: YOUR_API_KEY +```yaml +YouTubeField: + api_key: YOUR_API_KEY +``` ## URL Parser There is a static function which can be called (without using the YouTubeField) to simply retrieve the YouTube ID from a supported URL format. - YouTubeField::url_parser($url); +```php +YouTubeField::url_parser($url); +``` diff --git a/code/YouTubeField.php b/code/YouTubeField.php index b52de37..a3eb774 100644 --- a/code/YouTubeField.php +++ b/code/YouTubeField.php @@ -1,6 +1,7 @@ config()->get('api_key')) { + public function Field($properties = array()) + { + Requirements::javascript(SS_YOUTUBEFIELD_DIRECTORY . '/javascript/YouTubeField.js'); + + if ($api_key = $this->config()->get('api_key')) { $this->setAttribute('data-apikey', $api_key); - Requirements::javascript(SS_YOUTUBEFIELD_DIRECTORY . '/javascript/YouTubeField.js'); Requirements::javascript('https://apis.google.com/js/client.js?onload=googleApiClientReady'); - } + } elseif (!empty($this->value) && self::url_parser($this->value)) { + $client = new GuzzleHttp\Client(); + $res = $client->get('https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=' . $this->value . '&format=json'); + if ($res->getStatusCode() == '200' && $data = json_decode($res->getBody())) { + $api_data = new stdClass(); + $api_data->id = $this->value; + $api_data->snippet = new stdClass(); + $api_data->snippet->title = $data->title; + if (preg_match('/user\/([\w-]+)/', $data->author_url, $author)) { + $api_data->snippet->channelTitle = $author[1]; + } + $api_data->snippet->thumbnails = new stdClass(); + $api_data->snippet->thumbnails->default = new stdClass(); + $api_data->snippet->thumbnails->default->url = $data->thumbnail_url; + + $this->setAttribute('data-apidata', json_encode($api_data)); + } + } return parent::Field($properties); } - public function dataValue() { + public function dataValue() + { return self::url_parser($this->value); } @@ -29,15 +50,17 @@ public function dataValue() { * * @return string Right Title, or an explanatory default if none set */ - public function RightTitle() { - if(!empty($this->rightTitle)) { + public function RightTitle() + { + if (!empty($this->rightTitle)) { return $this->rightTitle; } else { return 'YouTube video URL or ID. Must be a single video, not a playlist or channel.'; } } - public function Type() { + public function Type() + { return 'text youtube'; } @@ -48,7 +71,8 @@ public function Type() { * * @return string|false YouTube Video ID, or false if no ID found */ - public static function url_parser($url) { + public static function url_parser($url) + { $regex = '/(?<=v=|v\/|vi=|vi\/|youtu.be\/|embed\/)([a-zA-Z0-9_-]{11})/'; if (!empty($url)) { @@ -57,7 +81,7 @@ public static function url_parser($url) { if (preg_match($regex, $url, $matches)) { return $matches[1]; } - } elseif(strlen($url) == 11) { + } elseif (strlen($url) == 11) { return $url; } } @@ -65,4 +89,4 @@ public static function url_parser($url) { return false; } -} \ No newline at end of file +} diff --git a/composer.json b/composer.json index 4bd51bf..00769d4 100644 --- a/composer.json +++ b/composer.json @@ -7,13 +7,14 @@ "authors": [ { "name": "Ed Linklater", - "email": "ed@silverstripe.com" + "email": "ed@edgar.industries" } ], "require": { - "silverstripe/framework": "~3.0" + "silverstripe/framework": "~3.3", + "guzzlehttp/guzzle": "~6.0" }, "extra": { "installer-name": "youtubefield" } -} \ No newline at end of file +} diff --git a/javascript/YouTubeField.js b/javascript/YouTubeField.js index b45bf6a..9b2a84c 100644 --- a/javascript/YouTubeField.js +++ b/javascript/YouTubeField.js @@ -1,6 +1,5 @@ (function($) { $.entwine(function($) { - $('input.youtube').entwine({ onmatch: function() { if (this.val().length > 0) { @@ -11,19 +10,23 @@ getYouTubeSnippet(this); } }); - }); }(jQuery)); function getYouTubeSnippet(element) { + var api_data = element.data('apidata'); var api_key = element.data('apikey'); - var youtube_id = element.val().match(/[a-zA-Z0-9_-]{11}/); + var youtube_id = element.val().match(/[a-zA-Z0-9_-]{11}/); - if (!youtube_id) { + if (!youtube_id) { element.parent().removeClass('youtube-active'); return false; } + if (api_data) { + return showYouTubeSnippet(element, api_data); + } + var yt = JSON.parse(localStorage.getItem('youtube-' + youtube_id[0])); if (yt) { return showYouTubeSnippet(element, yt); @@ -51,11 +54,14 @@ function showYouTubeSnippet(element, yt) { element.parent().addClass('youtube-active'); infobox.find('.youtube-info-title a').text(yt.snippet.title); infobox.find('.youtube-info-title a').attr('href', 'https://www.youtube.com/watch?v=' + yt.id); - infobox.find('.youtube-info-more').html([ - '' + yt.snippet.channelTitle + '', - 'Duration: ' + parseYouTubeDuration(yt.contentDetails.duration), - 'Views: ' + parseInt(yt.statistics.viewCount).toLocaleString() - ].join(' · ')); + var more = ['' + yt.snippet.channelTitle + '']; + if (typeof yt.contentDetails !== 'undefined' && typeof yt.contentDetails.duration !== 'undefined') { + more.push('Duration: ' + parseYouTubeDuration(yt.contentDetails.duration)); + } + if (typeof yt.statistics !== 'undefined' && typeof yt.statistics.viewCount !== 'undefined') { + more.push('Views: ' + parseInt(yt.statistics.viewCount).toLocaleString()); + } + infobox.find('.youtube-info-more').html(more.join(' · ')); infobox.find('.youtube-info-thumb').attr('src', yt.snippet.thumbnails.default.url); return true;