1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Sonata Project package. |
5
|
|
|
* |
6
|
|
|
* (c) Thomas Rabaix <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Sonata\MediaBundle\Provider; |
13
|
|
|
|
14
|
|
|
use Buzz\Browser; |
15
|
|
|
use Gaufrette\Filesystem; |
16
|
|
|
use Sonata\CoreBundle\Model\Metadata; |
17
|
|
|
use Sonata\MediaBundle\CDN\CDNInterface; |
18
|
|
|
use Sonata\MediaBundle\Generator\GeneratorInterface; |
19
|
|
|
use Sonata\MediaBundle\Metadata\MetadataBuilderInterface; |
20
|
|
|
use Sonata\MediaBundle\Model\MediaInterface; |
21
|
|
|
use Sonata\MediaBundle\Thumbnail\ThumbnailInterface; |
22
|
|
|
use Symfony\Component\HttpFoundation\RedirectResponse; |
23
|
|
|
|
24
|
|
|
class YouTubeProvider extends BaseVideoProvider |
25
|
|
|
{ |
26
|
|
|
/** |
27
|
|
|
* @var bool |
28
|
|
|
*/ |
29
|
|
|
protected $html5; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @param string $name |
33
|
|
|
* @param Filesystem $filesystem |
34
|
|
|
* @param CDNInterface $cdn |
35
|
|
|
* @param GeneratorInterface $pathGenerator |
36
|
|
|
* @param ThumbnailInterface $thumbnail |
37
|
|
|
* @param Browser $browser |
38
|
|
|
* @param MetadataBuilderInterface $metadata |
39
|
|
|
* @param bool $html5 |
40
|
|
|
*/ |
41
|
|
|
public function __construct($name, Filesystem $filesystem, CDNInterface $cdn, GeneratorInterface $pathGenerator, ThumbnailInterface $thumbnail, Browser $browser, MetadataBuilderInterface $metadata = null, $html5 = false) |
42
|
|
|
{ |
43
|
|
|
parent::__construct($name, $filesystem, $cdn, $pathGenerator, $thumbnail, $browser, $metadata); |
44
|
|
|
$this->html5 = $html5; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* {@inheritdoc} |
49
|
|
|
*/ |
50
|
|
|
public function getProviderMetadata() |
51
|
|
|
{ |
52
|
|
|
return new Metadata($this->getName(), $this->getName().'.description', false, 'SonataMediaBundle', array('class' => 'fa fa-youtube')); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* {@inheritdoc} |
57
|
|
|
*/ |
58
|
|
|
public function getHelperProperties(MediaInterface $media, $format, $options = array()) |
59
|
|
|
{ |
60
|
|
|
// Override html5 value if $options['html5'] is a boolean |
61
|
|
|
if (!isset($options['html5'])) { |
62
|
|
|
$options['html5'] = $this->html5; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
// documentation : http://code.google.com/apis/youtube/player_parameters.html |
66
|
|
|
|
67
|
|
|
$default_player_url_parameters = array( |
68
|
|
|
//Values: 0 or 1. Default is 1. Sets whether the player should load related |
69
|
|
|
// videos once playback of the initial video starts. Related videos are |
70
|
|
|
// displayed in the "genie menu" when the menu button is pressed. The player |
71
|
|
|
// search functionality will be disabled if rel is set to 0. |
72
|
|
|
'rel' => 0, |
73
|
|
|
|
74
|
|
|
// Values: 0 or 1. Default is 0. Sets whether or not the initial video will autoplay |
75
|
|
|
// when the player loads. |
76
|
|
|
'autoplay' => 0, |
77
|
|
|
|
78
|
|
|
// Values: 0 or 1. Default is 0. In the case of a single video player, a setting of 1 |
79
|
|
|
// will cause the player to play the initial video again and again. In the case of a |
80
|
|
|
// playlist player (or custom player), the player will play the entire playlist and |
81
|
|
|
// then start again at the first video. |
82
|
|
|
'loop' => 0, |
83
|
|
|
|
84
|
|
|
// Values: 0 or 1. Default is 0. Setting this to 1 will enable the Javascript API. |
85
|
|
|
// For more information on the Javascript API and how to use it, see the JavaScript |
86
|
|
|
// API documentation. |
87
|
|
|
'enablejsapi' => 0, |
88
|
|
|
|
89
|
|
|
// Value can be any alphanumeric string. This setting is used in conjunction with the |
90
|
|
|
// JavaScript API. See the JavaScript API documentation for details. |
91
|
|
|
'playerapiid' => null, |
92
|
|
|
|
93
|
|
|
// Values: 0 or 1. Default is 0. Setting to 1 will disable the player keyboard controls. |
94
|
|
|
// Keyboard controls are as follows: |
95
|
|
|
// Spacebar: Play / Pause |
96
|
|
|
// Arrow Left: Jump back 10% in the current video |
97
|
|
|
// Arrow Right: Jump ahead 10% in the current video |
98
|
|
|
// Arrow Up: Volume up |
99
|
|
|
// Arrow Down: Volume Down |
100
|
|
|
'disablekb' => 0, |
101
|
|
|
|
102
|
|
|
// Values: 0 or 1. Default is 0. Setting to 1 enables the "Enhanced Genie Menu". This |
103
|
|
|
// behavior causes the genie menu (if present) to appear when the user's mouse enters |
104
|
|
|
// the video display area, as opposed to only appearing when the menu button is pressed. |
105
|
|
|
'egm' => 0, |
106
|
|
|
|
107
|
|
|
// Values: 0 or 1. Default is 0. Setting to 1 enables a border around the entire video |
108
|
|
|
// player. The border's primary color can be set via the color1 parameter, and a |
109
|
|
|
// secondary color can be set by the color2 parameter. |
110
|
|
|
'border' => 0, |
111
|
|
|
|
112
|
|
|
// Values: Any RGB value in hexadecimal format. color1 is the primary border color, and |
113
|
|
|
// color2 is the video control bar background color and secondary border color. |
114
|
|
|
'color1' => null, |
115
|
|
|
'color2' => null, |
116
|
|
|
|
117
|
|
|
// Values: 0 or 1. Default is 0. Setting to 1 enables the fullscreen button. This has no |
118
|
|
|
// effect on the Chromeless Player. Note that you must include some extra arguments to |
119
|
|
|
// your embed code for this to work. |
120
|
|
|
'fs' => 1, |
121
|
|
|
|
122
|
|
|
// Values: A positive integer. This parameter causes the player to begin playing the video |
123
|
|
|
// at the given number of seconds from the start of the video. Note that similar to the |
124
|
|
|
// seekTo function, the player will look for the closest keyframe to the time you specify. |
125
|
|
|
// This means sometimes the play head may seek to just before the requested time, usually |
126
|
|
|
// no more than ~2 seconds |
127
|
|
|
'start' => 0, |
128
|
|
|
|
129
|
|
|
// Values: 0 or 1. Default is 0. Setting to 1 enables HD playback by default. This has no |
130
|
|
|
// effect on the Chromeless Player. This also has no effect if an HD version of the video |
131
|
|
|
// is not available. If you enable this option, keep in mind that users with a slower |
132
|
|
|
// connection may have an sub-optimal experience unless they turn off HD. You should ensure |
133
|
|
|
// your player is large enough to display the video in its native resolution. |
134
|
|
|
'hd' => 1, |
135
|
|
|
|
136
|
|
|
// Values: 0 or 1. Default is 1. Setting to 0 disables the search box from displaying when |
137
|
|
|
// the video is minimized. Note that if the rel parameter is set to 0 then the search box |
138
|
|
|
// will also be disabled, regardless of the value of showsearch. |
139
|
|
|
'showsearch' => 0, |
140
|
|
|
|
141
|
|
|
// Values: 0 or 1. Default is 1. Setting to 0 causes the player to not display information |
142
|
|
|
// like the video title and rating before the video starts playing. |
143
|
|
|
'showinfo' => 0, |
144
|
|
|
|
145
|
|
|
// Values: 1 or 3. Default is 1. Setting to 1 will cause video annotations to be shown by |
146
|
|
|
// default, whereas setting to 3 will cause video annotation to not be shown by default. |
147
|
|
|
'iv_load_policy' => 1, |
148
|
|
|
|
149
|
|
|
// Values: 1. Default is based on user preference. Setting to 1 will cause closed captions |
150
|
|
|
// to be shown by default, even if the user has turned captions off. |
151
|
|
|
'cc_load_policy' => 1, |
152
|
|
|
|
153
|
|
|
// Values: 'window' or 'opaque' or 'transparent'. |
154
|
|
|
// When wmode=window, the Flash movie is not rendered in the page. |
155
|
|
|
// When wmode=opaque, the Flash movie is rendered as part of the page. |
156
|
|
|
// When wmode=transparent, the Flash movie is rendered as part of the page. |
157
|
|
|
'wmode' => 'window', |
158
|
|
|
); |
159
|
|
|
|
160
|
|
|
$default_player_parameters = array( |
161
|
|
|
// Values: 0 or 1. Default is 0. Setting to 1 enables a border around the entire video |
162
|
|
|
// player. The border's primary color can be set via the color1 parameter, and a |
163
|
|
|
// secondary color can be set by the color2 parameter. |
164
|
|
|
'border' => $default_player_url_parameters['border'], |
165
|
|
|
|
166
|
|
|
// Values: 'allowfullscreen' or empty. Default is 'allowfullscreen'. Setting to empty value disables |
167
|
|
|
// the fullscreen button. |
168
|
|
|
'allowFullScreen' => $default_player_url_parameters['fs'] == '1' ? true : false, |
169
|
|
|
|
170
|
|
|
// The allowScriptAccess parameter in the code is needed to allow the player SWF to call |
171
|
|
|
// functions on the containing HTML page, since the player is hosted on a different domain |
172
|
|
|
// from the HTML page. |
173
|
|
|
'allowScriptAccess' => isset($options['allowScriptAccess']) ? $options['allowScriptAccess'] : 'always', |
174
|
|
|
|
175
|
|
|
// Values: 'window' or 'opaque' or 'transparent'. |
176
|
|
|
// When wmode=window, the Flash movie is not rendered in the page. |
177
|
|
|
// When wmode=opaque, the Flash movie is rendered as part of the page. |
178
|
|
|
// When wmode=transparent, the Flash movie is rendered as part of the page. |
179
|
|
|
'wmode' => $default_player_url_parameters['wmode'], |
180
|
|
|
); |
181
|
|
|
|
182
|
|
|
$player_url_parameters = array_merge($default_player_url_parameters, isset($options['player_url_parameters']) ? $options['player_url_parameters'] : array()); |
183
|
|
|
|
184
|
|
|
$box = $this->getBoxHelperProperties($media, $format, $options); |
185
|
|
|
|
186
|
|
|
$player_parameters = array_merge($default_player_parameters, isset($options['player_parameters']) ? $options['player_parameters'] : array(), array( |
187
|
|
|
'width' => $box->getWidth(), |
188
|
|
|
'height' => $box->getHeight(), |
189
|
|
|
)); |
190
|
|
|
|
191
|
|
|
$params = array( |
192
|
|
|
'html5' => $options['html5'], |
193
|
|
|
'player_url_parameters' => http_build_query($player_url_parameters), |
194
|
|
|
'player_parameters' => $player_parameters, |
195
|
|
|
); |
196
|
|
|
|
197
|
|
|
return $params; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* {@inheritdoc} |
202
|
|
|
*/ |
203
|
|
|
public function updateMetadata(MediaInterface $media, $force = false) |
204
|
|
|
{ |
205
|
|
|
$url = sprintf('http://www.youtube.com/oembed?url=%s&format=json', $this->getReferenceUrl($media)); |
206
|
|
|
|
207
|
|
|
try { |
208
|
|
|
$metadata = $this->getMetadata($media, $url); |
209
|
|
|
} catch (\RuntimeException $e) { |
210
|
|
|
$media->setEnabled(false); |
211
|
|
|
$media->setProviderStatus(MediaInterface::STATUS_ERROR); |
212
|
|
|
|
213
|
|
|
return; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
$media->setProviderMetadata($metadata); |
217
|
|
|
|
218
|
|
|
if ($force) { |
219
|
|
|
$media->setName($metadata['title']); |
220
|
|
|
$media->setAuthorName($metadata['author_name']); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
$media->setHeight($metadata['height']); |
224
|
|
|
$media->setWidth($metadata['width']); |
225
|
|
|
$media->setContentType('video/x-flv'); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* {@inheritdoc} |
230
|
|
|
*/ |
231
|
|
|
public function getDownloadResponse(MediaInterface $media, $format, $mode, array $headers = array()) |
232
|
|
|
{ |
233
|
|
|
return new RedirectResponse($this->getReferenceUrl($media), 302, $headers); |
|
|
|
|
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* Get provider reference url. |
238
|
|
|
* |
239
|
|
|
* @param MediaInterface $media |
240
|
|
|
* |
241
|
|
|
* @return string |
242
|
|
|
*/ |
243
|
|
|
public function getReferenceUrl(MediaInterface $media) |
244
|
|
|
{ |
245
|
|
|
return sprintf('http://www.youtube.com/watch?v=%s', $media->getProviderReference()); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* @param MediaInterface $media |
250
|
|
|
*/ |
251
|
|
|
protected function fixBinaryContent(MediaInterface $media) |
252
|
|
|
{ |
253
|
|
|
if (!$media->getBinaryContent()) { |
254
|
|
|
return; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
if (strlen($media->getBinaryContent()) === 11) { |
258
|
|
|
return; |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
if (preg_match("/^(?:http(?:s)?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^\#\?&\"'>]+)/", $media->getBinaryContent(), $matches)) { |
262
|
|
|
$media->setBinaryContent($matches[1]); |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* {@inheritdoc} |
268
|
|
|
*/ |
269
|
|
|
protected function doTransform(MediaInterface $media) |
270
|
|
|
{ |
271
|
|
|
$this->fixBinaryContent($media); |
272
|
|
|
|
273
|
|
|
if (!$media->getBinaryContent()) { |
274
|
|
|
return; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
$media->setProviderName($this->name); |
278
|
|
|
$media->setProviderStatus(MediaInterface::STATUS_OK); |
279
|
|
|
$media->setProviderReference($media->getBinaryContent()); |
280
|
|
|
|
281
|
|
|
$this->updateMetadata($media, true); |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.