optixsolutions / laravel-media

Attach files to eloquent models
MIT License
341 stars 39 forks source link

Support for new manipulators? #14

Open deevus opened 5 years ago

deevus commented 5 years ago

I would like to implement a VideoManipulator class however the PerformConversions job does not support any manipulators other than ImageManipulator.

Maybe it would work something like this:

use Intervention\Image\Image;
use Optix\Media\Facades\Conversion;
use My\VideoManipulator;
use My\Video;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // register your manipulators
        // ImageManipulator could be the default
        Conversion::registerManipulators([
            'image' => ImageManipulator::class,
            'video' => VideoManipulator::class
        ]);

        // register by key
        Conversion::register('image', 'thumb', function (Image $image) {
            return $image->fit(64, 64);
        });

        // register by class
        Conversion::register(VideoManipulator::class, 'preview', function (Video $video) {
            return $video
                ->mute() // mute audio
                ->clip(0, 2); // clip from time 0 for 2 seconds
        });

        // or perhaps infer the manipulator by the function parameter type
        // Image infers ImageManipulator
        Conversion::register('thumb', function (Image $image) {
            return $image->fit(64, 64);
        });

        // Video infers VideoManipulator
        Conversion::register('preview', function (Video $video) {
            return $video
                ->mute() // mute audio
                ->clip(0, 2); // clip from time 0 for 2 seconds
        });
    }
}

Thoughts?

Jack97 commented 5 years ago

Hi @deevus

Really like this idea, not 100% sure on what the API would look like at first thought. Quite like the idea to add the manipulators via the ConversionRegistry and to have a manipulators key in the config file.

Perhaps the manipulator would be resolved depending on the type of media that gets passed to it.

For example:

'manipulators' => [
    ImageManipulator::class => [
        'extensions' => ['png', 'jpg'], // or...
        // 'mime_types' => ['image/*']
    ],
    VideoManipulator::class => [
        'extensions' => ['mp4']
    ]
]

Alternatively it could be slightly more flexible if the the resolved manipulator is specified by the user. For example:

// 1) All manipulator's should implement a FileManipulator interface.
// 2) The media item would be loaded into the manipulator expected by the callback parameter.
// 3) This class would be responsible for preparing the media item for manipulation, i.e 
// passing the image path to Intervention\Image and exposing a manipulation API.
// 4) It would also be responsible for returning a savable resource, such as a stream to
// the job that performs the manipulations.

Conversion::register('preview', function (VideoManipulator $manipulator) {
    return $manipulator->mute()->clip(0, 2);
});

I'll try and find some time to prototype this within the coming weeks, should all be a bit clearer then.

deevus commented 5 years ago

This is good.

One thing to note is that the manipulations should be flexible enough to be able to handle external conversion, such as video encoding using AWS services like Elastic Transcoder or Media Convert.

A closure may be enough for some implementations, but there should also be hooks so that Media manipulation can be marked as done, or failed etc asyncronously.

This is obviously more complex than my simple example but it should be doable.