Skip to content
This repository has been archived by the owner on Sep 9, 2022. It is now read-only.

Commit

Permalink
Merge pull request #18 from edlinklater/feature/keyless
Browse files Browse the repository at this point in the history
Show a cut-down version of the infobox without needing YouTube API key
  • Loading branch information
Cheddam authored Nov 20, 2017
2 parents a205b94 + 09a721a commit 39c5afc
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 43 deletions.
49 changes: 30 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<?php

class Page extends SiteTree
{

private static $db = array(
'VideoID' => '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);
```
48 changes: 36 additions & 12 deletions code/YouTubeField.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

class YouTubeField extends TextField {
class YouTubeField extends TextField
{

/**
* @var string
Expand All @@ -10,17 +11,37 @@ class YouTubeField extends TextField {
*/
private static $api_key;

public function Field($properties = array()) {
if($api_key = $this->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);
}

Expand All @@ -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';
}

Expand All @@ -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)) {
Expand All @@ -57,12 +81,12 @@ 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;
}
}

return false;
}

}
}
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
}
24 changes: 15 additions & 9 deletions javascript/YouTubeField.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
(function($) {
$.entwine(function($) {

$('input.youtube').entwine({
onmatch: function() {
if (this.val().length > 0) {
Expand All @@ -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);
Expand Down Expand Up @@ -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([
'<strong>' + yt.snippet.channelTitle + '</strong>',
'Duration: ' + parseYouTubeDuration(yt.contentDetails.duration),
'Views: ' + parseInt(yt.statistics.viewCount).toLocaleString()
].join(' &middot; '));
var more = ['<strong>' + yt.snippet.channelTitle + '</strong>'];
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(' &middot; '));
infobox.find('.youtube-info-thumb').attr('src', yt.snippet.thumbnails.default.url);

return true;
Expand Down

0 comments on commit 39c5afc

Please sign in to comment.