Skip to content

Commit c82e6a7

Browse files
committed
Merge branch 'release/1.1.0' into v1
2 parents f4ae19e + 1dfc636 commit c82e6a7

File tree

5 files changed

+131
-27
lines changed

5 files changed

+131
-27
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Transcoder Changelog
22

3+
## 1.1.0 - 2018.02.02
4+
### Added
5+
* Transcoder now supports the transcoding of remote video & audio files
6+
* Added the ability to generate a thumbnail for videos in the AdminCP Assets index
7+
8+
### Changed
9+
* Cleaned up the exception handling
10+
311
## 1.0.11 - 2018.02.01
412
### Added
513
* Renamed the composer package name to `craft-transcoder`

README.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ If you have managed hosting, contact your sysadmin to get `ffmpeg` installed.
3232

3333
## Transcoder Overview
3434

35-
The Transcoder allows you to take any locally stored video, and transcode it into any size, bitrate, framerate, and save it out as a web-ready video in a variety of file formats.
35+
The Transcoder plugin allows you to take any video (local or remote), and transcode it into any size, bitrate, framerate, and save it out as a web-ready video in a variety of file formats.
3636

3737
It can also transcode audio files to any bitrate & sample rate, to a variety of file formats. It can even extract audio tracks from video files.
3838

39-
It also allows you to get a thumbnail of a video in any size and at any timecode, and can extract information about audio/video files such.
39+
Transcoder also allows you to get a thumbnail of a video in any size and at any timecode, and can extract information about audio/video files such.
4040

4141
Finally, it lets you download an arbitrary file (such as the transcoded video) via a special download link.
4242

@@ -59,6 +59,15 @@ To generate a transcoded video, do the following:
5959
"height": 480
6060
}) %}
6161

62+
You can also pass in an URL:
63+
64+
{% set transVideoUrl = craft.transcoder.getVideoUrl('http://vjs.zencdn.net/v/oceans.mp4', {
65+
"videoFrameRate": 20,
66+
"videoBitRate": "500k",
67+
"width": 720,
68+
"height": 480
69+
}) %}
70+
6271
You can also pass in an `Asset`:
6372

6473
{% set myAsset = entry.someAsset.first() %}
@@ -122,6 +131,14 @@ To generate a transcoded audio File, do the following:
122131
"audioChannels": 1
123132
}) %}
124133

134+
You can also pass in a URL:
135+
136+
{% set transAudioUrl = craft.transcoder.getAudioUrl('http://www.noiseaddicts.com/samples_1w72b820/2514.mp3', {
137+
"audioBitRate": "64k",
138+
"audioSampleRate": 22050,
139+
"audioChannels": 1
140+
}) %}
141+
125142
You can also pass in an `Asset`:
126143

127144
{% set myAsset = entry.someAsset.first() %}
@@ -197,6 +214,14 @@ To generate a thumbnail from a video, do the following:
197214
"timeInSecs": 20,
198215
}) %}
199216

217+
You can also pass in a URL:
218+
219+
{% set transVideoUrl = craft.transcoder.getVideoUrl('http://vjs.zencdn.net/v/oceans.mp4', {
220+
"width": 300,
221+
"height": 200,
222+
"timeInSecs": 20,
223+
}) %}
224+
200225
You can also pass in an `Asset`:
201226

202227
{% set myAsset = entry.someAsset.first() %}
@@ -252,6 +277,10 @@ To get information about an existing video/audio file, you can use `craft.transc
252277

253278
{% set fileInfo = craft.transcoder.getFileInfo('/home/vagrant/sites/nystudio107/public/oceans.mp4', true) %}
254279

280+
You can also pass in a URL:
281+
282+
{% set fileInfo = craft.transcoder.getFileInfo('http://vjs.zencdn.net/v/oceans.mp4', true) %}
283+
255284
You can also pass in an `Asset`:
256285

257286
{% set myAsset = entry.someAsset.first() %}

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "nystudio107/craft-transcoder",
33
"description": "Transcode video & audio files to various formats, and provide video thumbnails",
44
"type": "craft-plugin",
5-
"version": "1.0.11",
5+
"version": "1.1.0",
66
"keywords": [
77
"craft",
88
"cms",

src/Transcoder.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
use Craft;
1818
use craft\base\Plugin;
1919
use craft\console\Application as ConsoleApplication;
20+
use craft\elements\Asset;
2021
use craft\events\RegisterCacheOptionsEvent;
22+
use craft\events\GetAssetThumbUrlEvent;
23+
use craft\helpers\Assets as AssetsHelper;
24+
use craft\services\Assets;
2125
use craft\utilities\ClearCaches;
2226
use craft\web\twig\variables\CraftVariable;
2327

@@ -64,6 +68,23 @@ function (Event $event) {
6468
}
6569
);
6670

71+
// Handler: Elements::EVENT_AFTER_SAVE_ELEMENT
72+
Event::on(
73+
Assets::class,
74+
Assets::EVENT_GET_ASSET_THUMB_URL,
75+
function (GetAssetThumbUrlEvent $event) {
76+
Craft::trace(
77+
'Assets::EVENT_GET_ASSET_THUMB_URL',
78+
__METHOD__
79+
);
80+
/** @var Asset $asset */
81+
$asset = $event->asset;
82+
if (AssetsHelper::getFileKindByExtension($asset->filename) == Asset::KIND_VIDEO) {
83+
$event->url = Transcoder::$plugin->transcode->handleGetAssetThumbUrl($event);
84+
}
85+
}
86+
);
87+
6788
// Handle console commands
6889
if (Craft::$app instanceof ConsoleApplication) {
6990
$this->controllerNamespace = 'nystudio107\transcoder\console\controllers';

src/services/Transcode.php

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
use Craft;
1616
use craft\base\Component;
1717
use craft\elements\Asset;
18+
use craft\events\GetAssetThumbUrlEvent;
1819
use craft\volumes\Local;
1920

2021
use yii\base\Exception;
22+
use yii\validators\UrlValidator;
2123

2224
use mikehaertl\shellcommand\Command as ShellCommand;
25+
use yii\base\InvalidConfigException;
2326

2427
/**
2528
* @author nystudio107
@@ -83,7 +86,6 @@ class Transcode extends Component
8386
* @param $videoOptions array of options for the video
8487
*
8588
* @return string URL of the transcoded video or ""
86-
* @throws Exception
8789
*/
8890
public function getVideoUrl($filePath, $videoOptions): string
8991
{
@@ -92,7 +94,7 @@ public function getVideoUrl($filePath, $videoOptions): string
9294
$settings = Transcoder::$plugin->getSettings();
9395
$filePath = $this->getAssetPath($filePath);
9496

95-
if (file_exists($filePath)) {
97+
if (!empty($filePath)) {
9698
$destVideoPath = Craft::getAlias($settings['transcoderPath']);
9799

98100
$videoOptions = $this->coalesceOptions("defaultVideoOptions", $videoOptions);
@@ -202,7 +204,6 @@ public function getVideoUrl($filePath, $videoOptions): string
202204
* @param $thumbnailOptions array of options for the thumbnail
203205
*
204206
* @return string URL of the video thumbnail
205-
* @throws Exception
206207
*/
207208
public function getVideoThumbnailUrl($filePath, $thumbnailOptions): string
208209
{
@@ -211,7 +212,7 @@ public function getVideoThumbnailUrl($filePath, $thumbnailOptions): string
211212
$settings = Transcoder::$plugin->getSettings();
212213
$filePath = $this->getAssetPath($filePath);
213214

214-
if (file_exists($filePath)) {
215+
if (!empty($filePath)) {
215216
$destThumbnailPath = Craft::getAlias($settings['transcoderPath']);
216217

217218
$thumbnailOptions = $this->coalesceOptions("defaultThumbnailOptions", $thumbnailOptions);
@@ -264,7 +265,6 @@ public function getVideoThumbnailUrl($filePath, $thumbnailOptions): string
264265
* @param $audioOptions array of options for the audio file
265266
*
266267
* @return string URL of the transcoded audio file or ""
267-
* @throws Exception
268268
*/
269269
public function getAudioUrl($filePath, $audioOptions): string
270270
{
@@ -273,7 +273,7 @@ public function getAudioUrl($filePath, $audioOptions): string
273273
$settings = Transcoder::$plugin->getSettings();
274274
$filePath = $this->getAssetPath($filePath);
275275

276-
if (file_exists($filePath)) {
276+
if (!empty($filePath)) {
277277
$destAudioPath = Craft::getAlias($settings['transcoderPath']);
278278

279279
$audioOptions = $this->coalesceOptions("defaultAudioOptions", $audioOptions);
@@ -360,7 +360,6 @@ public function getAudioUrl($filePath, $audioOptions): string
360360
* @param bool $summary
361361
*
362362
* @return array
363-
* @throws Exception
364363
*/
365364
public function getFileInfo($filePath, $summary = false): array
366365
{
@@ -369,7 +368,7 @@ public function getFileInfo($filePath, $summary = false): array
369368
$settings = Transcoder::$plugin->getSettings();
370369
$filePath = $this->getAssetPath($filePath);
371370

372-
if (file_exists($filePath)) {
371+
if (!empty($filePath)) {
373372
// Build the basic command for ffprobe
374373
$ffprobeOptions = $settings['ffprobeOptions'];
375374
$ffprobeCmd = $settings['ffprobePath']
@@ -431,7 +430,6 @@ public function getFileInfo($filePath, $summary = false): array
431430
* @param $videoOptions
432431
*
433432
* @return string
434-
* @throws Exception
435433
*/
436434
public function getVideoFilename($filePath, $videoOptions): string
437435
{
@@ -456,7 +454,6 @@ public function getVideoFilename($filePath, $videoOptions): string
456454
* @param $audioOptions
457455
*
458456
* @return string
459-
* @throws Exception
460457
*/
461458
public function getAudioFilename($filePath, $audioOptions): string
462459
{
@@ -474,6 +471,24 @@ public function getAudioFilename($filePath, $audioOptions): string
474471
return $result;
475472
}
476473

474+
/**
475+
* Handle generated a thumbnail for the AdminCP
476+
*
477+
* @param GetAssetThumbUrlEvent $event
478+
*
479+
* @return null|string
480+
*/
481+
public function handleGetAssetThumbUrl(GetAssetThumbUrlEvent $event)
482+
{
483+
$options = [
484+
"width" => $event->width,
485+
"height" => $event->height,
486+
];
487+
$thumbUrl = $this->getVideoThumbnailUrl($event->asset, $options);
488+
489+
return empty($thumbUrl) ? null : $thumbUrl;
490+
}
491+
477492
// Protected Methods
478493
// =========================================================================
479494

@@ -484,13 +499,20 @@ public function getAudioFilename($filePath, $audioOptions): string
484499
* @param $options
485500
*
486501
* @return string
487-
* @throws Exception
488502
*/
489503
protected function getFilename($filePath, $options)
490504
{
491505
$settings = Transcoder::$plugin->getSettings();
492506
$filePath = $this->getAssetPath($filePath);
493-
$pathParts = pathinfo($filePath);
507+
508+
$validator = new UrlValidator();
509+
$error = '';
510+
if ($validator->validate($filePath, $error)) {
511+
$urlParts = parse_url($filePath);
512+
$pathParts = pathinfo($urlParts['path']);
513+
} else {
514+
$pathParts = pathinfo($filePath);
515+
}
494516
$fileName = $pathParts['filename'];
495517

496518
// Add our options to the file name
@@ -523,30 +545,54 @@ protected function getFilename($filePath, $options)
523545
* @param $filePath
524546
*
525547
* @return string
526-
* @throws Exception
527548
*/
528549
protected function getAssetPath($filePath): string
529550
{
530551
// If we're passed an Asset, extract the path from it
531552
if (is_object($filePath) && ($filePath instanceof Asset)) {
553+
/** @var Asset $asset */
532554
$asset = $filePath;
533-
$assetVolume = $asset->getVolume();
555+
$assetVolume = null;
556+
try {
557+
$assetVolume = $asset->getVolume();
558+
} catch (InvalidConfigException $e) {
559+
Craft::error($e->getMessage(), __METHOD__);
560+
}
561+
562+
if ($assetVolume) {
563+
// If it's local, get a path to the file
564+
if ($assetVolume instanceof Local) {
565+
$sourcePath = rtrim($assetVolume->path, DIRECTORY_SEPARATOR);
566+
$sourcePath .= strlen($sourcePath) ? DIRECTORY_SEPARATOR : '';
567+
$folderPath = '';
568+
try {
569+
$folderPath = rtrim($asset->getFolder()->path, DIRECTORY_SEPARATOR);
570+
} catch (InvalidConfigException $e) {
571+
Craft::error($e->getMessage(), __METHOD__);
572+
}
573+
$folderPath .= strlen($folderPath) ? DIRECTORY_SEPARATOR : '';
534574

535-
if (!(($assetVolume instanceof Local) || is_subclass_of($assetVolume, Local::class))) {
536-
throw new Exception(
537-
Craft::t('transcoder', 'Paths not available for non-local asset sources')
538-
);
575+
$filePath = $sourcePath . $folderPath . $asset->filename;
576+
} else {
577+
// Otherwise, get a URL
578+
$filePath = $asset->getUrl();
579+
}
539580
}
581+
}
540582

541-
$sourcePath = rtrim($assetVolume->path, DIRECTORY_SEPARATOR);
542-
$sourcePath .= strlen($sourcePath) ? DIRECTORY_SEPARATOR : '';
543-
$folderPath = rtrim($asset->getFolder()->path, DIRECTORY_SEPARATOR);
544-
$folderPath .= strlen($folderPath) ? DIRECTORY_SEPARATOR : '';
583+
$filePath = Craft::getAlias($filePath);
545584

546-
$filePath = $sourcePath . $folderPath . $asset->filename;
585+
// Make sure that $filePath is either an existing file, or a valid URL
586+
if (!file_exists($filePath)) {
587+
$validator = new UrlValidator();
588+
$error = '';
589+
if (!$validator->validate($filePath, $error)) {
590+
Craft::error($error, __METHOD__);
591+
$filePath = '';
592+
}
547593
}
548594

549-
return Craft::getAlias($filePath);
595+
return $filePath;
550596
}
551597

552598
/**

0 commit comments

Comments
 (0)