diff --git a/.gitignore b/.gitignore
index 4ebb78c..af58555 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
.DS_Store
vendor
.idea
-composer.lock
\ No newline at end of file
+.phpunit.cache
+coverage.xml
+composer.lock
diff --git a/docs/README.md b/docs/README.md
index 7aa0101..879414f 100755
--- a/docs/README.md
+++ b/docs/README.md
@@ -32,6 +32,7 @@ Moreover, Larupload can calculate the dominant colors of videos and images, as w
* Extract the width and height of the image
* Extract width, height, and duration of the video
* Extract the duration of the audio
+* Convert audio file formats
* Extract dominant color from the image and video
* Automatically create a cover image for video files
* Possibility to upload a cover for every file
diff --git a/docs/advanced-usage/attachment/complete-example.md b/docs/advanced-usage/attachment/complete-example.md
index 8222aab..698fcda 100644
--- a/docs/advanced-usage/attachment/complete-example.md
+++ b/docs/advanced-usage/attachment/complete-example.md
@@ -41,6 +41,13 @@ class Media extends Model
->image('thumbnail', 250, 250, LaruploadMediaStyle::AUTO)
->image('crop_mode', 1100, 1100, LaruploadMediaStyle::CROP)
->image('portrait_mode', 1000, 1000, LaruploadMediaStyle::SCALE_WIDTH)
+ ->audio('audio_wav', new Wav())
+ ->audio('audio_flac', new Flac())
+ ->audio('audio_aac', new Aac())
+ ->audio(
+ name: 'audio_mp3',
+ format: (new Mp3())->setAudioKiloBitrate(192)->setAudioChannels(2)
+ )
->video('thumbnail', 250, 250, LaruploadMediaStyle::AUTO)
->video('crop_mode', 1100, 1100, LaruploadMediaStyle::CROP)
->video('portrait_mode', 1000, 1000, LaruploadMediaStyle::SCALE_WIDTH)
diff --git a/docs/advanced-usage/attachment/media-styles.md b/docs/advanced-usage/attachment/media-styles.md
index 4ffaf26..b3b5392 100644
--- a/docs/advanced-usage/attachment/media-styles.md
+++ b/docs/advanced-usage/attachment/media-styles.md
@@ -45,6 +45,43 @@ class Media extends Model
+
+
+### Audio Style
+
+
Index | Name | Type | Required | Default | Description |
---|
1 | name | string | true | – | style name. examples: hq, lq, ... |
2 | format | Mp3|Aac|Wav|Flac | false | Mp3 | the format of the converted audio file |
+
+```php
+audio('hq', new Wav())
+ ];
+ }
+}
+```
+
+
+
+
+
+
+
### Video Style
Index | Name | Type | Required | Default | Description |
---|
1 | name | string | true | – | style name. examples: thumbnail, small, ... |
2 | width | ?int | false | null | width of the manipulated video |
3 | height | ?int | false | null | height of the manipulated video |
4 | mode | LaruploadMediaStyle | false | SCALE_HEIGHT | this argument specifies how Larupload should manipulate the uploaded video and can take on any of the following values: FIT , AUTO , SCALE_WIDTH , SCALE_HEIGHT , CROP |
5 | format | X264 | false | new X264 | by default, the encoding format for video is X264 . However, users can specify additional options for this format, including adjusting the kilobitrate for both audio and video . This allows for more precise configuration and optimization of the user's encoding preferences. |
6 | padding | bool | false | false | If set to true , padding will be applied to the video using a black color in order to fit the given dimensions. |
diff --git a/docs/cover/upload-cover.md b/docs/cover/upload-cover.md
index 0944399..6854974 100644
--- a/docs/cover/upload-cover.md
+++ b/docs/cover/upload-cover.md
@@ -2,20 +2,17 @@
In Larupload, covers are associated with the original files and must be uploaded using the `attach()` function. When uploading a file, you can also include a cover as the second argument. If a cover is provided, it will be assigned to the uploaded file and the [automatic cover creation](#user-content-fn-1)[^1] by the package will be prevented.
-$file = $request->file('file');
+```php
+$file = $request->file('file');
$cover = $request->file('cover');
+# or
+$upload->attachment('file')->attach($file, $cover);
-$upload->attachment('file')->attach($file, $cover);
$upload->save();
-
+```
[^1]: it's only available for image and videos
-
-[^2]: ```php
- # or
- $upload->file->attach($file, $cover);
- ```
diff --git a/docs/standalone-uploader/customization.md b/docs/standalone-uploader/customization.md
index 81eafff..13e4608 100644
--- a/docs/standalone-uploader/customization.md
+++ b/docs/standalone-uploader/customization.md
@@ -21,6 +21,7 @@ $upload = Larupload::init('path')
->namingMethod(LaruploadNamingMethod::HASH_FILE)
->image('thumbnail', 1000, 750, LaruploadMediaStyle::CROP)
->video('thumbnail', 1000, 750, LaruploadMediaStyle::CROP)
+ ->audio('wav', new Wav())
->stream(
name: '480p',
width: 640,
diff --git a/src/Actions/Cover/GenerateCoverFromFileAction.php b/src/Actions/Cover/GenerateCoverFromFileAction.php
index 0190865..fbe4ec6 100644
--- a/src/Actions/Cover/GenerateCoverFromFileAction.php
+++ b/src/Actions/Cover/GenerateCoverFromFileAction.php
@@ -14,6 +14,10 @@ class GenerateCoverFromFileAction
private readonly string $fileName;
private readonly mixed $ffmpegCaptureFrame;
private array $output;
+ private array $availableStyles = [
+ LaruploadFileType::VIDEO, LaruploadFileType::IMAGE
+ ];
+
public function __construct(private readonly UploadedFile $file, private readonly CoverActionData $data)
{
@@ -29,6 +33,10 @@ public static function make(UploadedFile $file, CoverActionData $data): static
public function run(string $path): array
{
+ if (!in_array($this->data->type, $this->availableStyles)) {
+ return $this->output;
+ }
+
Storage::disk($this->data->disk)->makeDirectory($path);
$format = $this->fileFormat();
diff --git a/src/Actions/FixExceptionNamesAction.php b/src/Actions/FixExceptionNamesAction.php
index 3bee0fc..ed648fc 100644
--- a/src/Actions/FixExceptionNamesAction.php
+++ b/src/Actions/FixExceptionNamesAction.php
@@ -3,6 +3,7 @@
namespace Mostafaznv\Larupload\Actions;
use Illuminate\Support\Str;
+use Mostafaznv\Larupload\DTOs\Style\Style;
use Mostafaznv\Larupload\Larupload;
/**
@@ -15,23 +16,30 @@ class FixExceptionNamesAction
{
public function __construct(
private readonly string $name,
- private readonly string $style
+ private readonly string $styleName,
+ private readonly ?Style $style = null,
) {}
- public static function make(string $name, string $style): self
+ public static function make(string $name, string $styleName, ?Style $style = null): self
{
- return new self($name, $style);
+ return new self($name, $styleName, $style);
}
public function run(): string
{
- if (!in_array($this->style, [Larupload::ORIGINAL_FOLDER, Larupload::COVER_FOLDER])) {
- if (Str::endsWith($this->name, 'svg')) {
- return str_replace('svg', 'jpg', $this->name);
+ $name = $this->name;
+
+ if ($this->style) {
+ $name = larupload_style_path($name, $this->style->extension());
+ }
+
+ if (!in_array($this->styleName, [Larupload::ORIGINAL_FOLDER, Larupload::COVER_FOLDER])) {
+ if (Str::endsWith($name, 'svg')) {
+ return str_replace('svg', 'jpg', $name);
}
}
- return $this->name;
+ return $name;
}
}
diff --git a/src/Concerns/Storage/Attachment/QueueAttachment.php b/src/Concerns/Storage/Attachment/QueueAttachment.php
index 9fa41fb..74e07e5 100755
--- a/src/Concerns/Storage/Attachment/QueueAttachment.php
+++ b/src/Concerns/Storage/Attachment/QueueAttachment.php
@@ -2,16 +2,17 @@
namespace Mostafaznv\Larupload\Concerns\Storage\Attachment;
-
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Mostafaznv\Larupload\Actions\GuessLaruploadFileTypeAction;
+use Mostafaznv\Larupload\Enums\LaruploadFileType;
use Mostafaznv\Larupload\Jobs\ProcessFFMpeg;
use Mostafaznv\Larupload\Larupload;
+
trait QueueAttachment
{
/**
@@ -22,7 +23,12 @@ public function handleFFMpegQueue(bool $isLastOne = false, bool $standalone = fa
$this->file = $this->prepareFileForFFMpegProcess();
$this->type = GuessLaruploadFileTypeAction::make($this->file)->calc();
- $this->handleVideoStyles($this->id);
+ if ($this->type == LaruploadFileType::VIDEO) {
+ $this->handleVideoStyles($this->id);
+ }
+ else if ($this->type == LaruploadFileType::AUDIO) {
+ $this->handleAudioStyles($this->id);
+ }
if ($this->driverIsNotLocal() and $isLastOne) {
Storage::disk($this->localDisk)->deleteDirectory(
diff --git a/src/Concerns/Storage/Attachment/RetrieveAttachment.php b/src/Concerns/Storage/Attachment/RetrieveAttachment.php
index 802fe5d..40ca310 100755
--- a/src/Concerns/Storage/Attachment/RetrieveAttachment.php
+++ b/src/Concerns/Storage/Attachment/RetrieveAttachment.php
@@ -43,7 +43,8 @@ public function urls(): object
$allStyles = array_merge(
$staticStyles,
array_keys($this->imageStyles),
- array_keys($this->videoStyles)
+ array_keys($this->videoStyles),
+ array_keys($this->audioStyles)
);
foreach ($allStyles as $style) {
diff --git a/src/Concerns/Storage/Attachment/StyleAttachment.php b/src/Concerns/Storage/Attachment/StyleAttachment.php
index 2188d66..e60b55f 100755
--- a/src/Concerns/Storage/Attachment/StyleAttachment.php
+++ b/src/Concerns/Storage/Attachment/StyleAttachment.php
@@ -53,6 +53,29 @@ protected function handleStyles(string $id, Model|string $model, bool $standalon
$this->handleVideoStyles($id);
}
+ break;
+
+ case LaruploadFileType::AUDIO:
+ if ($this->ffmpegQueue) {
+ if ($this->driverIsNotLocal()) {
+ $this->uploadOriginalFile($id, $this->localDisk);
+ }
+
+ if ($model instanceof Model) {
+ $this->initializeFFMpegQueue(
+ $model->id, $model->getMorphClass(), $standalone
+ );
+ }
+ else {
+ $this->initializeFFMpegQueue(
+ $id, $model, $standalone
+ );
+ }
+ }
+ else {
+ $this->handleAudioStyles($id);
+ }
+
break;
}
}
@@ -82,6 +105,22 @@ protected function handleVideoStyles($id): void
}
}
+ /**
+ * Handle styles for audios
+ *
+ * @param $id
+ */
+ protected function handleAudioStyles($id): void
+ {
+ foreach ($this->audioStyles as $name => $style) {
+ $path = $this->getBasePath($id, $name);
+ Storage::disk($this->disk)->makeDirectory($path);
+ $saveTo = "$path/{$this->output['name']}";
+
+ $this->ffmpeg()->audio($style, $saveTo);
+ }
+ }
+
/**
* Prepare style path
* this function will use to prepare full path of given style to generate url/download response
@@ -97,7 +136,7 @@ protected function prepareStylePath(string $style): ?string
Larupload::STREAM_FOLDER
];
- if (isset($this->id) and (in_array($style, $staticStyles) or array_key_exists($style, $this->imageStyles) or array_key_exists($style, $this->videoStyles))) {
+ if (isset($this->id) and (in_array($style, $staticStyles) or array_key_exists($style, $this->imageStyles) or array_key_exists($style, $this->videoStyles) or array_key_exists($style, $this->audioStyles))) {
$name = $style == Larupload::COVER_FOLDER
? $this->output['cover']
: $this->output['name'];
@@ -117,7 +156,8 @@ protected function prepareStylePath(string $style): ?string
return null;
}
else if ($name and $this->styleHasFile($style)) {
- $name = FixExceptionNamesAction::make($name, $style)->run();
+
+ $name = FixExceptionNamesAction::make($name, $style, $this->getStyle($style))->run();
$path = $this->getBasePath($this->id, $style);
return "$path/$name";
diff --git a/src/Concerns/Storage/UploadEntity/UploadEntityStyle.php b/src/Concerns/Storage/UploadEntity/UploadEntityStyle.php
index 4d577f8..fb58008 100755
--- a/src/Concerns/Storage/UploadEntity/UploadEntityStyle.php
+++ b/src/Concerns/Storage/UploadEntity/UploadEntityStyle.php
@@ -3,9 +3,15 @@
namespace Mostafaznv\Larupload\Concerns\Storage\UploadEntity;
+use FFMpeg\Format\Audio\Aac;
+use FFMpeg\Format\Audio\Flac;
+use FFMpeg\Format\Audio\Mp3;
+use FFMpeg\Format\Audio\Wav;
use FFMpeg\Format\Video\X264;
+use Mostafaznv\Larupload\DTOs\Style\AudioStyle;
use Mostafaznv\Larupload\DTOs\Style\StreamStyle;
use Mostafaznv\Larupload\DTOs\Style\ImageStyle;
+use Mostafaznv\Larupload\DTOs\Style\Style;
use Mostafaznv\Larupload\DTOs\Style\VideoStyle;
use Mostafaznv\Larupload\Enums\LaruploadFileType;
use Mostafaznv\Larupload\Enums\LaruploadMediaStyle;
@@ -28,6 +34,13 @@ trait UploadEntityStyle
*/
protected array $videoStyles = [];
+ /**
+ * Styles for audio files
+ *
+ * @var AudioStyle[]
+ */
+ protected array $audioStyles = [];
+
/**
* Stream styles
*
@@ -53,6 +66,11 @@ public function getVideoStyles(): array
return $this->videoStyles;
}
+ public function getAudioStyles(): array
+ {
+ return $this->audioStyles;
+ }
+
public function image(string $name, ?int $width = null, ?int $height = null, LaruploadMediaStyle $mode = LaruploadMediaStyle::AUTO): UploadEntities
{
$this->imageStyles[$name] = ImageStyle::make($name, $width, $height, $mode);
@@ -67,6 +85,13 @@ public function video(string $name, ?int $width = null, ?int $height = null, Lar
return $this;
}
+ public function audio(string $name, Mp3|Aac|Wav|Flac $format = new Mp3): UploadEntities
+ {
+ $this->audioStyles[$name] = AudioStyle::make($name, $format);
+
+ return $this;
+ }
+
public function stream(string $name, int $width, int $height, X264 $format, LaruploadMediaStyle $mode = LaruploadMediaStyle::SCALE_HEIGHT, bool $padding = false): UploadEntities
{
$this->streams[$name] = StreamStyle::make($name, $width, $height, $format, $mode, $padding);
@@ -81,26 +106,36 @@ public function coverStyle(string $name, ?int $width = null, ?int $height = null
return $this;
}
- protected function styleHasFile(string $style): bool
+ protected function getStyle(string $style): ?Style
{
- if (in_array($style, [Larupload::ORIGINAL_FOLDER, Larupload::COVER_FOLDER])) {
- return true;
- }
-
$type = $this->output['type'];
$types = [
LaruploadFileType::VIDEO->name,
+ LaruploadFileType::AUDIO->name,
LaruploadFileType::IMAGE->name
];
if (in_array($type, $types)) {
- $styles = $type === LaruploadFileType::IMAGE->name
- ? $this->imageStyles
- : $this->videoStyles;
+ $styles = match ($type) {
+ LaruploadFileType::VIDEO->name => $this->videoStyles,
+ LaruploadFileType::AUDIO->name => $this->audioStyles,
+ LaruploadFileType::IMAGE->name => $this->imageStyles,
+ };
+
+ if (isset($styles[$style])) {
+ return $styles[$style];
+ }
+ }
- return array_key_exists($style, $styles);
+ return null;
+ }
+
+ protected function styleHasFile(string $style): bool
+ {
+ if (in_array($style, [Larupload::ORIGINAL_FOLDER, Larupload::COVER_FOLDER])) {
+ return true;
}
- return false;
+ return $this->getStyle($style) !== null;
}
}
diff --git a/src/DTOs/Style/AudioStyle.php b/src/DTOs/Style/AudioStyle.php
new file mode 100755
index 0000000..31a9080
--- /dev/null
+++ b/src/DTOs/Style/AudioStyle.php
@@ -0,0 +1,43 @@
+format = $format;
+
+ }
+
+ public static function make(string $name, Mp3|Aac|Wav|Flac $format = new Mp3): self
+ {
+ return new self($name, $format);
+ }
+
+ public function extension(): ?string
+ {
+ if ($this->format instanceof Aac) {
+ return 'aac';
+ }
+ else if ($this->format instanceof Wav) {
+ return 'wav';
+ }
+ else if ($this->format instanceof Flac) {
+ return 'flac';
+ }
+
+ return 'mp3';
+ }
+}
diff --git a/src/DTOs/Style/Style.php b/src/DTOs/Style/Style.php
index 42ccada..739a635 100755
--- a/src/DTOs/Style/Style.php
+++ b/src/DTOs/Style/Style.php
@@ -4,6 +4,7 @@
use Exception;
+
abstract class Style
{
public function __construct(
@@ -16,6 +17,11 @@ public function __construct(
}
+ public function extension(): ?string
+ {
+ return null;
+ }
+
private function validate(): void
{
$this->validateName();
diff --git a/src/Helpers/Utils.php b/src/Helpers/Utils.php
index 0942b16..2d6f93c 100755
--- a/src/Helpers/Utils.php
+++ b/src/Helpers/Utils.php
@@ -72,10 +72,12 @@ function split_larupload_path(string $dir): array
*
* @param string $disk
* @param string $saveTo
+ * @param string|null $extension
* @return array
*/
- function get_larupload_save_path(string $disk, string $saveTo): array
+ function get_larupload_save_path(string $disk, string $saveTo, ?string $extension = null): array
{
+ $saveTo = larupload_style_path($saveTo, $extension);
$permanent = \Illuminate\Support\Facades\Storage::disk($disk)->path($saveTo);
list($path, $name) = split_larupload_path($saveTo);
@@ -187,4 +189,24 @@ function file_is_valid(mixed $file, string $name, string $type): bool
}
}
+if (!function_exists('larupload_style_path')) {
+ /**
+ * Change path extension
+ *
+ * @param string $path
+ * @param string|null $extension
+ * @return string
+ */
+ function larupload_style_path(string $path, ?string $extension): string
+ {
+ if ($extension) {
+ $info = pathinfo($path);
+
+ return $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] . '.' . $extension;
+ }
+
+ return $path;
+ }
+}
+
diff --git a/src/Storage/FFMpeg/FFMpeg.php b/src/Storage/FFMpeg/FFMpeg.php
index 12783ef..770d6ce 100755
--- a/src/Storage/FFMpeg/FFMpeg.php
+++ b/src/Storage/FFMpeg/FFMpeg.php
@@ -14,6 +14,7 @@
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Log;
use Mostafaznv\Larupload\DTOs\FFMpeg\FFMpegMeta;
+use Mostafaznv\Larupload\DTOs\Style\AudioStyle;
use Mostafaznv\Larupload\DTOs\Style\ImageStyle;
use Mostafaznv\Larupload\DTOs\Style\StreamStyle;
use Mostafaznv\Larupload\DTOs\Style\VideoStyle;
@@ -21,6 +22,7 @@
use Mostafaznv\Larupload\Storage\Image;
use Psr\Log\LoggerInterface;
+
class FFMpeg
{
private readonly UploadedFile $file;
@@ -122,6 +124,15 @@ public function capture(int|float|null $fromSeconds, ImageStyle $style, string $
return $dominantColor;
}
+ public function audio(AudioStyle $style, string $saveTo): void
+ {
+ $saveTo = get_larupload_save_path($this->disk, $saveTo, $style->extension());
+
+ $this->media->save($style->format, $saveTo['local']);
+
+ larupload_finalize_save($this->disk, $saveTo);
+ }
+
public function manipulate(VideoStyle $style, string $saveTo): void
{
$saveTo = get_larupload_save_path($this->disk, $saveTo);
diff --git a/tests/Feature/AudioStyleTest.php b/tests/Feature/AudioStyleTest.php
new file mode 100644
index 0000000..510b132
--- /dev/null
+++ b/tests/Feature/AudioStyleTest.php
@@ -0,0 +1,138 @@
+withAllAudios();
+ $model = save($model, mp3());
+
+ $attachment = $model->attachment('main_file');
+ $mp3 = urlToAudio($attachment->url('audio_mp3'));
+ $wav = urlToAudio($attachment->url('audio_wav'));
+ $flac = urlToAudio($attachment->url('audio_flac'));
+
+ expect($attachment->url('cover'))
+ ->toBeNull()
+ // mp3
+ ->and($attachment->url('audio_mp3'))
+ ->toBeTruthy()
+ ->toBeString()
+ ->toBeExists()
+ ->and($mp3->width)
+ ->toBeNull()
+ ->and($mp3->height)
+ ->toBeNull()
+ ->and($mp3->duration)
+ ->toBe(67)
+ // wav
+ ->and($attachment->url('audio_wav'))
+ ->toBeTruthy()
+ ->toBeString()
+ ->toBeExists()
+ ->and($wav->width)
+ ->toBeNull()
+ ->and($wav->height)
+ ->toBeNull()
+ ->and($wav->duration)
+ ->toBe(67)
+ // flac
+ ->and($attachment->url('audio_flac'))
+ ->toBeTruthy()
+ ->toBeString()
+ ->toBeExists()
+ ->and($flac->width)
+ ->toBeNull()
+ ->and($flac->height)
+ ->toBeNull()
+ ->and($flac->duration)
+ ->toBe(67);
+
+})->with('models');
+
+it('will generate audio styles in standalone mode correctly', function() {
+ $upload = Larupload::init('uploader')
+ ->audio('audio_mp3', new Mp3())
+ ->audio('audio_wav', new Wav())
+ ->audio('audio_flac', new Flac())
+ ->upload(mp3());
+
+ $mp3 = urlToVideo($upload->audio_mp3);
+ $wav = urlToVideo($upload->audio_wav);
+ $flac = urlToVideo($upload->audio_flac);
+
+ expect($upload->cover)
+ ->toBeNull()
+ // mp3
+ ->and($upload->audio_mp3)
+ ->toBeTruthy()
+ ->toBeString()
+ ->toBeExists()
+ ->and($mp3->width)
+ ->toBeNull()
+ ->and($mp3->height)
+ ->toBeNull()
+ ->and($mp3->duration)
+ ->toBe(67)
+ // wav
+ ->and($upload->audio_wav)
+ ->toBeTruthy()
+ ->toBeString()
+ ->toBeExists()
+ ->and($wav->width)
+ ->toBeNull()
+ ->and($wav->height)
+ ->toBeNull()
+ ->and($wav->duration)
+ ->toBe(67)
+ // flac
+ ->and($upload->audio_flac)
+ ->toBeTruthy()
+ ->toBeString()
+ ->toBeExists()
+ ->and($flac->width)
+ ->toBeNull()
+ ->and($flac->height)
+ ->toBeNull()
+ ->and($flac->duration)
+ ->toBe(67);
+});
+
+it('will generate audio styles correctly when secure-ids is enabled', function(LaruploadHeavyTestModel|LaruploadLightTestModel $model) {
+ config()->set('larupload.secure-ids', LaruploadSecureIdsMethod::ULID);
+
+ $model = new ($model::class);
+ $model->setAttachments(
+ TestAttachmentBuilder::make($model->mode)->withWavAudio()->toArray()
+ );
+ $model = save($model, mp3());
+
+ $attachment = $model->attachment('main_file');
+ $id = $attachment->meta('id');
+ $wav = urlToVideo($attachment->url('audio_wav'));
+
+ expect(Str::isUlid($id))->toBeTrue()
+ // cover
+ ->and($attachment->url('cover'))
+ ->toBeNull()
+ // wav
+ ->and($attachment->url('audio_wav'))
+ ->toBeTruthy()
+ ->toBeString()
+ ->toBeExists()
+ ->and($wav->width)
+ ->toBeNull()
+ ->and($wav->height)
+ ->toBeNull()
+ ->and($wav->duration)
+ ->toBe(67);
+
+})->with('models');
diff --git a/tests/Feature/DownloadTest.php b/tests/Feature/DownloadTest.php
index 6c03f48..e1e6fb1 100644
--- a/tests/Feature/DownloadTest.php
+++ b/tests/Feature/DownloadTest.php
@@ -62,6 +62,21 @@
})->with('models');
+it('will download custom audio styles', function(LaruploadHeavyTestModel|LaruploadLightTestModel $model) {
+ $model->setAttachments(
+ TestAttachmentBuilder::make($model->mode)->withWavAudio()->toArray()
+ );
+
+ $model = save($model, mp3());
+ $attachment = $model->attachment('main_file');
+
+ expect($attachment->download('audio_wav'))
+ ->toBeInstanceOf(StreamedResponse::class)
+ ->getStatusCode()
+ ->toBe(200);
+
+})->with('models');
+
it('will return null for styles that do not exist', function(LaruploadHeavyTestModel|LaruploadLightTestModel $model) {
$model = save($model, jpg());
$attachment = $model->attachment('main_file');
diff --git a/tests/Feature/FFMpegQueueTest.php b/tests/Feature/FFMpegQueueTest.php
index 5b4b403..dedbcee 100644
--- a/tests/Feature/FFMpegQueueTest.php
+++ b/tests/Feature/FFMpegQueueTest.php
@@ -1,7 +1,9 @@
set('larupload.ffmpeg.queue', true);
});
-it('will process ffmpeg through queue', function() {
- save(LaruploadTestModels::QUEUE->instance(), mp4());
+it('will process ffmpeg through queue', function(UploadedFile $file) {
+ Bus::assertNotDispatched(ProcessFFMpeg::class);
+
+ save(LaruploadTestModels::QUEUE->instance(), $file);
Bus::assertDispatched(ProcessFFMpeg::class);
-});
-it('will process ffmpeg through queue in standalone mode', function() {
+})->with([
+ mp4(),
+ mp3()
+]);
+
+it('will process ffmpeg through queue in standalone mode [video]', function() {
+ Bus::assertNotDispatched(ProcessFFMpeg::class);
+
Larupload::init('uploader')
->video('landscape', 400)
->upload(mp4());
- save(LaruploadTestModels::QUEUE->instance(), mp4());
+ Bus::assertDispatched(ProcessFFMpeg::class);
+});
+
+it('will process ffmpeg through queue in standalone mode [audio]', function() {
+ Bus::assertNotDispatched(ProcessFFMpeg::class);
+
+ Larupload::init('uploader')
+ ->audio('audio_wav', new Wav())
+ ->upload(mp3());
Bus::assertDispatched(ProcessFFMpeg::class);
});
@@ -56,6 +75,26 @@
expect($urls->landscape)->toBeExists();
});
+it('will create audio styles through queue process', function() {
+ $model = LaruploadTestModels::QUEUE->instance();
+ $model = save($model, mp3());
+
+ $urls = $model->attachment('main_file')->urls();
+
+ expect($urls->original)
+ ->toBeExists()
+ ->and($urls->cover)
+ ->toBeNull()
+ ->and($urls->audio_wav)
+ ->toNotExists();
+
+ $queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
+ $process = new ProcessFFMpeg($queue->id, $model->id, 'main_file', $model::class);
+ $process->handle();
+
+ expect($urls->audio_wav)->toBeExists();
+});
+
it('will create video styles through queue process in standalone mode', function() {
$name = 'uploader';
$standalone = Larupload::init($name)->video('landscape', 400);
@@ -76,6 +115,26 @@
expect($uploader->landscape)->toBeExists();
});
+it('will create audio styles through queue process in standalone mode', function() {
+ $name = 'uploader';
+ $standalone = Larupload::init($name)->audio('audio_wav', new Wav);
+ $uploader = $standalone->upload(mp3());
+
+ expect($uploader->original)
+ ->toBeExists()
+ ->and($uploader->cover)
+ ->toBeNull()
+ ->and($uploader->audio_wav)
+ ->toNotExists();
+
+ $queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
+ $serializedClass = base64_encode(serialize($standalone));
+ $process = new ProcessFFMpeg($queue->id, $uploader->meta->id, $name, Larupload::class, $serializedClass);
+ $process->handle();
+
+ expect($uploader->audio_wav)->toBeExists();
+});
+
it('will create streams through queue process', function() {
$model = LaruploadTestModels::QUEUE->instance();
$model = save($model, mp4());
@@ -121,7 +180,7 @@
});
-it('can queue ffmpeg for remote disks and deletes local files after finishing the process', function() {
+it('can queue ffmpeg for remote disks and deletes local files after finishing the process', function(UploadedFile $file, int $expectedS3Files1, int $expectedS3Files2) {
# init
$disk = 's3';
$localDisk = config()->get('larupload.local-disk');
@@ -129,7 +188,7 @@
# save model
$model = LaruploadTestModels::REMOTE_QUEUE->instance();
- $model = save($model, mp4());
+ $model = save($model, $file);
# prepare for assertions
$queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
@@ -139,7 +198,7 @@
# assertions 1
expect($s3Files)
- ->toHaveCount(2)
+ ->toHaveCount($expectedS3Files1)
->and($localFiles)
->toHaveCount(1)
->and($localFiles[0])
@@ -156,12 +215,15 @@
// assertions 2
expect($s3Files)
- ->toHaveCount(7)
+ ->toHaveCount($expectedS3Files2)
->and($localFiles)
->toHaveCount(0);
-});
+})->with([
+ [mp4(), 2, 7],
+ [mp3(), 1, 2],
+]);
-it('can queue ffmpeg for remote disks and deletes local files after finishing the process in standalone mode', function() {
+it('can queue ffmpeg for remote disks and deletes local files after finishing the process in standalone mode [video]', function() {
# init
$name = 'uploader';
$disk = 's3';
@@ -203,9 +265,58 @@
->toHaveCount(8)
->and($localFiles)
->toHaveCount(0);
+
+ Storage::disk($disk)->deleteDirectory('/');
+});
+
+it('can queue ffmpeg for remote disks and deletes local files after finishing the process in standalone mode [audio]', function() {
+ # init
+ $name = 'uploader';
+ $disk = 's3';
+ $localDisk = config()->get('larupload.local-disk');
+ Storage::fake($disk);
+ $standalone = Larupload::init($name)
+ ->disk($disk)
+ ->audio('audio_wav', new Wav);
+
+ # upload
+ $uploader = $standalone->upload(mp3());
+
+ # prepare for assertions
+ $queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
+ $serializedClass = base64_encode(serialize($standalone));
+ $s3Files = Storage::disk($disk)->allFiles();
+ $localFiles = Storage::disk($localDisk)->allFiles();
+
+
+ # assertions 1
+ expect($s3Files)
+ ->toHaveCount(2)
+ ->and($localFiles)
+ ->toHaveCount(1)
+ ->and($localFiles[0])
+ ->toEndWith($uploader->meta->name);
+
+
+ # run queue
+ $process = new ProcessFFMpeg($queue->id, $uploader->meta->id, $name, Larupload::class, $serializedClass);
+ $process->handle();
+
+ # prepare for assertions
+ $s3Files = Storage::disk($disk)->allFiles();
+ $localFiles = Storage::disk($localDisk)->allFiles();
+
+ // assertions 2
+ expect($s3Files)
+ ->toHaveCount(3)
+ ->and($localFiles)
+ ->toHaveCount(0);
+
+
+ Storage::disk($disk)->deleteDirectory('/');
});
-it('can queue ffmpeg when using secure-ids', function() {
+it('can queue ffmpeg when using secure-ids [video]', function() {
config()->set('larupload.secure-ids', LaruploadSecureIdsMethod::ULID);
$model = LaruploadTestModels::QUEUE->instance();
@@ -227,7 +338,29 @@
expect($urls->landscape)->toBeExists();
});
-it('can queue ffmpeg when using secure-ids in standalone mode', function() {
+it('can queue ffmpeg when using secure-ids [audio]', function() {
+ config()->set('larupload.secure-ids', LaruploadSecureIdsMethod::ULID);
+
+ $model = LaruploadTestModels::QUEUE->instance();
+ $model = save($model, mp3());
+
+ $urls = $model->attachment('main_file')->urls();
+
+ expect($urls->original)
+ ->toBeExists()
+ ->and($urls->cover)
+ ->toBeExists()
+ ->and($urls->audio_wav)
+ ->toNotExists();
+
+ $queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
+ $process = new ProcessFFMpeg($queue->id, $model->id, 'main_file', $model::class);
+ $process->handle();
+
+ expect($urls->audio_wav)->toBeExists();
+});
+
+it('can queue ffmpeg when using secure-ids in standalone mode [video]', function() {
config()->set('larupload.secure-ids', LaruploadSecureIdsMethod::ULID);
$name = 'uploader';
@@ -273,9 +406,55 @@
expect($urls->landscape)->toBeExists();
});
-it('will change queue status after processing queue', function() {
+it('can queue ffmpeg when using secure-ids in standalone mode [audio]', function() {
+ config()->set('larupload.secure-ids', LaruploadSecureIdsMethod::ULID);
+
+ $name = 'uploader';
+ $standalone = Larupload::init($name)->audio('audio_wav', new Wav);
+ $uploader = $standalone->upload(mp3());
+
+ expect($uploader->original)
+ ->toBeExists()
+ ->and($uploader->cover)
+ ->toBeExists()
+ ->and($uploader->audio_wav)
+ ->toNotExists();
+
+ $queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
+ $serializedClass = base64_encode(serialize($standalone));
+ $process = new ProcessFFMpeg($queue->id, $uploader->meta->id, $name, Larupload::class, $serializedClass);
+ $process->handle();
+
+ expect($uploader->audio_wav)->toBeExists();
+
+
+
+
+
+
+
$model = LaruploadTestModels::QUEUE->instance();
- $model = save($model, mp4());
+ $model = save($model, mp3());
+
+ $urls = $model->attachment('main_file')->urls();
+
+ expect($urls->original)
+ ->toBeExists()
+ ->and($urls->cover)
+ ->toBeExists()
+ ->and($urls->audio_wav)
+ ->toNotExists();
+
+ $queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
+ $process = new ProcessFFMpeg($queue->id, $model->id, 'main_file', $model::class);
+ $process->handle();
+
+ expect($urls->audio_wav)->toBeExists();
+});
+
+it('will change queue status after processing queue', function(UploadedFile $file) {
+ $model = LaruploadTestModels::QUEUE->instance();
+ $model = save($model, $file);
$queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
expect($queue)
@@ -294,11 +473,15 @@
->toBeObject()
->and($queue->status)
->toBe(1);
-});
-it('will fire an event when process is finished', function() {
+})->with([
+ mp4(),
+ mp3(),
+]);
+
+it('will fire an event when process is finished', function(UploadedFile $file) {
$model = LaruploadTestModels::QUEUE->instance();
- $model = save($model, mp4());
+ $model = save($model, $file);
$queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
Event::assertNotDispatched(LaruploadFFMpegQueueFinished::class);
@@ -307,11 +490,15 @@
$process->handle();
Event::assertDispatched(LaruploadFFMpegQueueFinished::class);
-});
-it('will update queue record whit error message, when process failed', function() {
+})->with([
+ mp4(),
+ mp3(),
+]);
+
+it('will update queue record whit error message, when process failed', function(UploadedFile $file) {
$model = LaruploadTestModels::QUEUE->instance();
- $model = save($model, mp4());
+ $model = save($model, $file);
$queue = DB::table(Larupload::FFMPEG_QUEUE_TABLE)->first();
expect($queue->message)->toBeNull();
@@ -325,7 +512,10 @@
expect($queue->message)->toBeTruthy();
-})->throws(Exception::class);
+})->throws(Exception::class)->with([
+ mp4(),
+ mp3(),
+]);
it('can load queue relationships of model', function() {
$model = LaruploadTestModels::QUEUE->instance();
@@ -350,7 +540,7 @@
$model = LaruploadTestModels::QUEUE->instance();
save($model, mp4());
- save($model, mp4());
- save($model, mp4());
+ save($model, mp3());
+ save($model, mp3());
})->throws(HttpResponseException::class);
diff --git a/tests/Feature/ResponseTest.php b/tests/Feature/ResponseTest.php
index 35b7126..dfbef4c 100644
--- a/tests/Feature/ResponseTest.php
+++ b/tests/Feature/ResponseTest.php
@@ -9,7 +9,9 @@
use Illuminate\Support\Facades\Storage;
$properties = [
- 'original', 'cover', 'stream', 'small_size', 'small', 'medium', 'landscape', 'portrait', 'exact', 'auto', 'meta'
+ 'original', 'cover', 'stream', 'small_size', 'small', 'medium',
+ 'audio_mp3', 'audio_wav', 'audio_flac',
+ 'landscape', 'portrait', 'exact', 'auto', 'meta'
];
it('will return larupload object in toArray function', function(LaruploadHeavyTestModel|LaruploadLightTestModel $model) use ($properties) {
diff --git a/tests/Feature/SecureIdsTest.php b/tests/Feature/SecureIdsTest.php
index 9a8649a..97a8845 100644
--- a/tests/Feature/SecureIdsTest.php
+++ b/tests/Feature/SecureIdsTest.php
@@ -136,7 +136,7 @@
->toBeExists();
});
-it('will work with ffmpeg class', function () {
+it('will work with ffmpeg class [video]', function () {
config()->set('larupload.secure-ids', LaruploadSecureIdsMethod::ULID);
$model = LaruploadTestModels::HEAVY->instance();
@@ -165,5 +165,30 @@
->and($attachment->url('landscape'))
->toContain($id)
->toBeExists();
+});
+
+it('will work with ffmpeg class [audio]', function () {
+ config()->set('larupload.secure-ids', LaruploadSecureIdsMethod::ULID);
+
+ $model = LaruploadTestModels::HEAVY->instance();
+ $model->setAttachments(
+ TestAttachmentBuilder::make($model->mode)->withWavAudio()->toArray()
+ );
+
+ $model = save($model, mp3());
+
+ $attachment = $model->attachment('main_file');
+ $id = $attachment->meta('id');
+ expect(Str::isUlid($id))->toBeTrue()
+ ->and($attachment->url())
+ ->toContain($id)
+ ->toBeExists()
+ //
+ ->and($attachment->url('cover'))
+ ->toBeNull()
+ //
+ ->and($attachment->url('audio_wav'))
+ ->toContain($id)
+ ->toBeExists();
});
diff --git a/tests/Feature/UploadEntityTest.php b/tests/Feature/UploadEntityTest.php
index 174abaa..aa74f20 100644
--- a/tests/Feature/UploadEntityTest.php
+++ b/tests/Feature/UploadEntityTest.php
@@ -1,5 +1,7 @@
attachment->audio('audio_wav', new Wav);
+ $this->attachment->audio('audio_aac', new Aac());
+
+ $styles = $this->attachment->getAudioStyles();
+
+ expect($styles)
+ ->toBeArray()
+ ->toHaveCount(2)
+ ->and(array_keys($styles))
+ ->toBe([
+ 'audio_wav', 'audio_aac'
+ ]);
+});
+
it('can change dominant-color property', function() {
$this->model->setAttachments([
$this->attachment->dominantColor(false)
diff --git a/tests/Pest.php b/tests/Pest.php
index 70186f7..5782073 100644
--- a/tests/Pest.php
+++ b/tests/Pest.php
@@ -109,6 +109,21 @@ function urlToVideo(string $url): FFMpegMeta
return $ffmpeg->getMeta();
}
+function urlToAudio(string $url): FFMpegMeta
+{
+ $baseUrl = url('/');
+ $url = str_replace($baseUrl, '', $url);
+ $path = public_path($url);
+
+ $fileName = pathinfo($path, PATHINFO_FILENAME);
+ $disk = config('larupload.disk');
+
+ $file = new UploadedFile($path, $fileName, null, null, true);
+ $ffmpeg = new FFMpeg($file, $disk, 10);
+
+ return $ffmpeg->getMeta();
+}
+
function urlsToPath(AttachmentProxy $attachment, array $exclude = []): array
{
$paths = [];
diff --git a/tests/Support/Models/LaruploadQueueTestModel.php b/tests/Support/Models/LaruploadQueueTestModel.php
index 11ff1d9..43184e0 100755
--- a/tests/Support/Models/LaruploadQueueTestModel.php
+++ b/tests/Support/Models/LaruploadQueueTestModel.php
@@ -24,6 +24,7 @@ public function attachments(): array
return TestAttachmentBuilder::make($this->mode)
->withLandscapeVideo()
->with480pStream()
+ ->withWavAudio()
->toArray();
}
}
diff --git a/tests/Support/Models/LaruploadRemoteQueueTestModel.php b/tests/Support/Models/LaruploadRemoteQueueTestModel.php
index 7702a17..fbd4ed2 100755
--- a/tests/Support/Models/LaruploadRemoteQueueTestModel.php
+++ b/tests/Support/Models/LaruploadRemoteQueueTestModel.php
@@ -23,6 +23,7 @@ public function attachments(): array
{
return TestAttachmentBuilder::make($this->mode, 's3')
->withLandscapeVideo()
+ ->withWavAudio()
->with480pStream()
->toArray();
}
diff --git a/tests/Support/Models/Traits/TestAttachments.php b/tests/Support/Models/Traits/TestAttachments.php
index 05e9cc3..10a4bed 100755
--- a/tests/Support/Models/Traits/TestAttachments.php
+++ b/tests/Support/Models/Traits/TestAttachments.php
@@ -45,6 +45,13 @@ public function withAllVideos(): array
);
}
+ public function withAllAudios(): array
+ {
+ return $this->setAttachments(
+ TestAttachmentBuilder::make($this->mode)->withAllAudios()->toArray()
+ );
+ }
+
public function withStreams(): array
{
return $this->setAttachments(
diff --git a/tests/Support/TestAttachmentBuilder.php b/tests/Support/TestAttachmentBuilder.php
index e8b0445..0f418de 100755
--- a/tests/Support/TestAttachmentBuilder.php
+++ b/tests/Support/TestAttachmentBuilder.php
@@ -2,6 +2,10 @@
namespace Mostafaznv\Larupload\Test\Support;
+use FFMpeg\Format\Audio\Aac;
+use FFMpeg\Format\Audio\Flac;
+use FFMpeg\Format\Audio\Mp3;
+use FFMpeg\Format\Audio\Wav;
use FFMpeg\Format\Video\X264;
use Mostafaznv\Larupload\Enums\LaruploadMediaStyle;
use Mostafaznv\Larupload\Enums\LaruploadMode;
@@ -85,6 +89,36 @@ public function withAllImages(): self
return $this;
}
+ public function withMp3Audio(): self
+ {
+ $this->attachment = $this->attachment->audio('audio_mp3', new Mp3);
+
+ return $this;
+ }
+
+ public function withWavAudio(): self
+ {
+ $this->attachment = $this->attachment->audio('audio_wav', new Wav);
+
+ return $this;
+ }
+
+ public function withFlacAudio(): self
+ {
+ $this->attachment = $this->attachment->audio('audio_flac', new Flac);
+
+ return $this;
+ }
+
+ public function withAllAudios(): self
+ {
+ $this->withMp3Audio()
+ ->withWavAudio()
+ ->withFlacAudio();
+
+ return $this;
+ }
+
public function withSmallSizeVideo(): self
{
$this->attachment = $this->attachment->video('small_size', 200, 200, LaruploadMediaStyle::CROP);
@@ -199,7 +233,7 @@ public function withAllVideosAndStreams(): self
public function withAll(): self
{
- $this->withAllImages()->withAllVideosAndStreams();
+ $this->withAllImages()->withAllVideosAndStreams()->withAllAudios();
return $this;
}
diff --git a/tests/Unit/AudioStyleTest.php b/tests/Unit/AudioStyleTest.php
new file mode 100644
index 0000000..a2e5088
--- /dev/null
+++ b/tests/Unit/AudioStyleTest.php
@@ -0,0 +1,10 @@
+throws(Exception::class, 'Style name [12] is numeric. please use string name for your style');
+
diff --git a/tests/Unit/FFMpegTest.php b/tests/Unit/FFMpegTest.php
index 5dc92a0..188ffc5 100644
--- a/tests/Unit/FFMpegTest.php
+++ b/tests/Unit/FFMpegTest.php
@@ -1,12 +1,16 @@
throws(Exception::class);
+it('can manipulate audios', function(AudioStyle $style, string $fileName, int $bitrate, string $codec) {
+ $path = get_larupload_save_path('local', $fileName)['local'];
+
+ expect(file_exists($path))->toBeFalse();
+
+ $ffmpeg = new FFMpeg(mp3(), 'local', 10);
+ $ffmpeg->audio($style, $fileName);
+
+ expect(file_exists($path))->toBeTrue();
+
+ $file = new UploadedFile($path, $fileName, null, null, true);
+ $audio = new FFMpeg($file, 'local', 10);
+ $meta = $audio->getMeta();
+
+
+ expect($meta->width)
+ ->toBeNull()
+ ->and($meta->height)
+ ->toBeNull()
+ ->and($meta->duration)
+ ->toBe(67)
+ ->and($audio->getMedia()->getStreams()->first()->isAudio())
+ ->toBeTrue()
+ ->and((int)$audio->getMedia()->getStreams()->first()->get('bit_rate'))
+ ->toBe($bitrate)
+ ->and($audio->getMedia()->getStreams()->first()->get('codec_type'))
+ ->toBe('audio')
+ ->and($audio->getMedia()->getStreams()->first()->get('codec_name'))
+ ->toBe($codec);
+
+ @unlink($path);
+
+})->with([
+ fn() => [
+ 'style' => AudioStyle::make('mp3', (new Mp3())->setAudioKiloBitrate(32)),
+ 'file_name' => 'audio.mp3',
+ 'bit_rate' => 32000,
+ 'codec' => 'mp3'
+ ],
+ fn() => [
+ 'style' => AudioStyle::make('wav', new Wav()),
+ 'file_name' => 'audio.wav',
+ 'bit_rate' => 705600,
+ 'codec' => 'pcm_s16le'
+ ],
+ fn() => [
+ 'style' => AudioStyle::make('wav', new Flac()),
+ 'file_name' => 'audio.flac',
+ 'bit_rate' => 0,
+ 'codec' => 'flac'
+ ],
+]);
+
+
+it('can guess correct file extension based on audio-style', function(AudioStyle $style, string $fileName) {
+ $path = get_larupload_save_path('local', $fileName)['local'];
+
+ expect(file_exists($path))->toBeFalse();
+
+ $ffmpeg = new FFMpeg(mp3(), 'local', 10);
+ $ffmpeg->audio($style, 'audio.ext');
+
+ expect(file_exists($path))->toBeTrue();
+
+ @unlink($path);
+
+})->with([
+ fn() => [
+ 'style' => AudioStyle::make('mp3', new Mp3()),
+ 'file_name' => 'audio.mp3',
+ ],
+ fn() => [
+ 'style' => AudioStyle::make('wav', new Wav()),
+ 'file_name' => 'audio.wav',
+ ],
+ fn() => [
+ 'style' => AudioStyle::make('wav', new Flac()),
+ 'file_name' => 'audio.flac',
+ ],
+]);
+
+it('can upload manipulated audios to remote disks', function() {
+ $disk = 's3';
+ Storage::fake($disk);
+
+ $ffmpeg = new FFMpeg(mp3(), $disk, 10);
+ $ffmpeg->audio(
+ style: AudioStyle::make('wav', new Wav()),
+ saveTo: 'audio.wav'
+ );
+
+ $files = Storage::disk($disk)->allFiles();
+
+ expect($files)
+ ->toBeArray()
+ ->toHaveCount(1)
+ ->toMatchArray([
+ 'audio.wav'
+ ]);
+});
+
+it('can convert video to audio', function() {
+ $fileName = 'audio.mp3';
+ $path = get_larupload_save_path('local', $fileName)['local'];
+
+ $style = AudioStyle::make('mp3', new Mp3());
+
+ $ffmpeg = new FFMpeg(mp4(), 'local', 10);
+ $ffmpeg->audio($style, $fileName);
+
+ expect(file_exists($path))->toBeTrue();
+
+ $file = new UploadedFile($path, $fileName, null, null, true);
+ $audio = new FFMpeg($file, 'local', 10);
+ $meta = $audio->getMeta();
+
+ expect($meta->width)
+ ->toBeNull()
+ ->and($meta->height)
+ ->toBeNull()
+ ->and($meta->duration)
+ ->toBe(5)
+ ->and($audio->getMedia()->getStreams()->first()->isAudio())
+ ->toBeTrue()
+ ->and($audio->getMedia()->getStreams()->first()->get('codec_type'))
+ ->toBe('audio')
+ ->and($audio->getMedia()->getStreams()->first()->get('codec_name'))
+ ->toBe('mp3');
+
+ @unlink($path);
+});
+
it('can manipulate videos', function(VideoStyle $style, int $width, int $height) {
$fileName = 'video.mp4';
$path = get_larupload_save_path('local', $fileName)['local'];
diff --git a/tests/Unit/FixExceptionNamesActionTest.php b/tests/Unit/FixExceptionNamesActionTest.php
new file mode 100644
index 0000000..a62a161
--- /dev/null
+++ b/tests/Unit/FixExceptionNamesActionTest.php
@@ -0,0 +1,42 @@
+run();
+
+ expect($res)->toBe($path);
+
+})->with([
+ Larupload::ORIGINAL_FOLDER,
+ Larupload::COVER_FOLDER
+]);
+
+it('will convert svg to jpg for custom styles', function() {
+ $res = FixExceptionNamesAction::make('path/to/file.svg', 'custom-style')->run();
+
+ expect($res)->toBe('path/to/file.jpg');
+});
+
+it('will change file extension based on style', function() {
+ $style = AudioStyle::make('custom-style', new Aac());
+ $res = FixExceptionNamesAction::make('path/to/file.mp3', $style->name, $style)->run();
+
+ expect($res)->toBe('path/to/file.aac');
+});
+
+it('wont change file extension if style doesnt have custom extension', function() {
+ $style = ImageStyle::make('custom-style', 100, 100);
+ $path = 'path/to/file.png';
+ $res = FixExceptionNamesAction::make($path, $style->name, $style)->run();
+
+ expect($res)->toBe($path);
+});
+
diff --git a/tests/Unit/UtilsTest.php b/tests/Unit/UtilsTest.php
index 3b230c2..4e27bcc 100644
--- a/tests/Unit/UtilsTest.php
+++ b/tests/Unit/UtilsTest.php
@@ -85,6 +85,45 @@ enum TestEnum
]);
});
+it('can generate save path with custom extension', function() {
+ $path = 'path/to/file.png';
+ $newPath = 'path/to/file.jpg';
+ $localPath = config('filesystems.disks.local.root');
+
+ $result = get_larupload_save_path('local', $path, 'jpg');
+
+ expect($result)
+ ->toBeArray()
+ ->toHaveCount(5)
+ ->toMatchArray([
+ 'path' => 'path/to',
+ 'name' => 'file.jpg',
+ 'temp' => null,
+ 'local' => $localPath . '/' . $newPath,
+ 'permanent' => $localPath . '/' . $newPath,
+ ]);
+
+
+ $carbon = Carbon::createFromFormat('Y-m-d H:i:s', '1990-09-20 07:10:48');
+ $time = $carbon->unix();
+ testTime()->freeze($carbon);
+
+ $result = get_larupload_save_path('s3', $path, 'jpg');
+
+ $tempPath = larupload_temp_dir();
+
+ expect($result)
+ ->toBeArray()
+ ->toHaveCount(5)
+ ->toMatchArray([
+ 'path' => 'path/to',
+ 'name' => 'file.jpg',
+ 'temp' => $tempPath . "/$time-file.jpg",
+ 'local' => $tempPath . "/$time-file.jpg",
+ 'permanent' => $newPath,
+ ]);
+});
+
it('can upload file to remote disks', function() {
$driver = 's3';
$file = pdf();
@@ -171,3 +210,24 @@ enum TestEnum
file_is_valid(png(2), 'file', 'cover');
})->throws(RuntimeException::class);
+
+
+it('will return path unchanged if extension is null', function() {
+ $original = 'path/to/file.mp3';
+ $path = larupload_style_path($original, null);
+
+ expect($path)->toBe($original);
+});
+
+it('will return path unchanged if extension is an empty string', function() {
+ $original = 'path/to/file.mp3';
+ $path = larupload_style_path($original, '');
+
+ expect($path)->toBe($original);
+});
+
+it('will change path using the given extension', function() {
+ $path = larupload_style_path('path/to/file.mp3', 'wav');
+
+ expect($path)->toBe('path/to/file.wav');
+});