Skip to content

Commit

Permalink
Merge pull request #34 from mostafaznv/dev
Browse files Browse the repository at this point in the history
Audio Style
  • Loading branch information
mostafaznv authored Dec 27, 2024
2 parents ba03f2c + b27b04c commit dee2b34
Show file tree
Hide file tree
Showing 31 changed files with 977 additions and 59 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.DS_Store
vendor
.idea
composer.lock
.phpunit.cache
coverage.xml
composer.lock
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions docs/advanced-usage/attachment/complete-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
37 changes: 37 additions & 0 deletions docs/advanced-usage/attachment/media-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,43 @@ class Media extends Model





### Audio Style

<table><thead><tr><th width="103" data-type="number">Index</th><th width="99">Name</th><th width="196">Type</th><th data-type="checkbox">Required</th><th width="155">Default</th><th width="515">Description</th></tr></thead><tbody><tr><td>1</td><td>name</td><td>string</td><td>true</td><td>–</td><td>style name. examples: hq, lq, ...</td></tr><tr><td>2</td><td>format</td><td>Mp3|Aac|Wav|Flac</td><td>false</td><td>Mp3</td><td>the format of the converted audio file</td></tr></tbody></table>

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Mostafaznv\Larupload\Enums\LaruploadMediaStyle;
use Mostafaznv\Larupload\Storage\Attachment;
use Mostafaznv\Larupload\Traits\Larupload;
use FFMpeg\Format\Audio\Wav;

class Media extends Model
{
use Larupload;

public function attachments(): array
{
return [
Attachment::make('file')
->audio('hq', new Wav())
];
}
}
```







### Video Style

<table><thead><tr><th width="103" data-type="number">Index</th><th width="99">Name</th><th width="196">Type</th><th data-type="checkbox">Required</th><th width="155">Default</th><th width="515">Description</th></tr></thead><tbody><tr><td>1</td><td>name</td><td>string</td><td>true</td><td>–</td><td>style name. examples: thumbnail, small, ...</td></tr><tr><td>2</td><td>width</td><td>?int</td><td>false</td><td>null</td><td>width of the manipulated video</td></tr><tr><td>3</td><td>height</td><td>?int</td><td>false</td><td>null</td><td>height of the manipulated video</td></tr><tr><td>4</td><td>mode</td><td>LaruploadMediaStyle</td><td>false</td><td>SCALE_HEIGHT</td><td>this argument specifies how Larupload should manipulate the uploaded video and can take on any of the following values: <code>FIT</code>, <code>AUTO</code>, <code>SCALE_WIDTH</code>, <code>SCALE_HEIGHT</code>, <code>CROP</code></td></tr><tr><td>5</td><td>format</td><td>X264</td><td>false</td><td>new X264</td><td>by default, the encoding format for video is <code>X264</code>. However, users can specify additional options for this format, including adjusting the <code>kilobitrate</code> for both <code>audio</code> and <code>video</code>. This allows for more precise configuration and optimization of the user's encoding preferences.</td></tr><tr><td>6</td><td>padding</td><td>bool</td><td>false</td><td>false</td><td>If set to <code>true</code>, padding will be applied to the video using a black color in order to fit the given dimensions.</td></tr></tbody></table>
Expand Down
13 changes: 5 additions & 8 deletions docs/cover/upload-cover.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<pre class="language-php"><code class="lang-php">$file = $request->file('file');
```php
$file = $request->file('file');
$cover = $request->file('cover');
# or
$upload->attachment('file')->attach($file, $cover);

<a data-footnote-ref href="#user-content-fn-2">$upload->attachment('file')->attach($file, $cover);</a>
$upload->save();
</code></pre>
```





[^1]: it's only available for image and videos

[^2]: ```php
# or
$upload->file->attach($file, $cover);
```
1 change: 1 addition & 0 deletions docs/standalone-uploader/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 8 additions & 0 deletions src/Actions/Cover/GenerateCoverFromFileAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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();
Expand Down
22 changes: 15 additions & 7 deletions src/Actions/FixExceptionNamesAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Mostafaznv\Larupload\Actions;

use Illuminate\Support\Str;
use Mostafaznv\Larupload\DTOs\Style\Style;
use Mostafaznv\Larupload\Larupload;

/**
Expand All @@ -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;
}
}
10 changes: 8 additions & 2 deletions src/Concerns/Storage/Attachment/QueueAttachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
/**
Expand All @@ -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(
Expand Down
3 changes: 2 additions & 1 deletion src/Concerns/Storage/Attachment/RetrieveAttachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
44 changes: 42 additions & 2 deletions src/Concerns/Storage/Attachment/StyleAttachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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
Expand All @@ -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'];
Expand All @@ -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";
Expand Down
55 changes: 45 additions & 10 deletions src/Concerns/Storage/UploadEntity/UploadEntityStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,6 +34,13 @@ trait UploadEntityStyle
*/
protected array $videoStyles = [];

/**
* Styles for audio files
*
* @var AudioStyle[]
*/
protected array $audioStyles = [];

/**
* Stream styles
*
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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;
}
}
Loading

0 comments on commit dee2b34

Please sign in to comment.