[
  {
    "path": ".editorconfig",
    "content": "; This file is for unifying the coding style for different editors and IDEs.\n; More information at http://editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nindent_size = 4\nindent_style = space\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.blade.php]\ninsert_final_newline = false\ntrim_trailing_whitespace = false\n\n[*.md]\ntrim_trailing_whitespace = false"
  },
  {
    "path": ".gitattributes",
    "content": "\n# Path-based git attributes\n# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html\n\n# Ignore all test and documentation with \"export-ignore\".\n/.github            export-ignore\n/.gitattributes     export-ignore\n/.gitignore         export-ignore\n/.travis.yml        export-ignore\n/phpunit.xml.dist   export-ignore\n/.styleci.yml       export-ignore\n/tests              export-ignore\n/.editorconfig      export-ignore\n/changelog.md       export-ignore\n/phpunit.xml        export-ignore\n/README.md          export-ignore\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: tests\non:\n    push:\n    pull_request:\n    schedule:\n        - cron: '0 0 * * *'\n\njobs:\n    run-tests:\n        runs-on: ubuntu-latest\n        strategy:\n            fail-fast: false\n            matrix:\n                php: [8.0, 8.1, 8.2, 8.3]\n                laravel: [9.*]\n                dependency-version: [prefer-lowest, prefer-stable]\n                include:\n                    - laravel: 9.*\n                      testbench: 7.*\n                      laravel-medialibrary: 10.*\n\n        name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }}\n\n        steps:\n            - name: Update apt\n              run: sudo apt-get update --fix-missing\n\n            - name: Install ffmpeg\n              run: sudo apt-get install ffmpeg\n\n            - name: Checkout code\n              uses: actions/checkout@v2\n\n            - name: Setup PHP\n              uses: shivammathur/setup-php@v2\n              with:\n                  php-version: ${{ matrix.php }}\n                  extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick\n                  coverage: none\n\n            - name: Setup Problem Matches\n              run: |\n                  echo \"::add-matcher::${{ runner.tool_cache }}/php.json\"\n                  echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"\n            - name: Fix Imagick Policy\n              run: sudo sed -i 's/none/read|write/g' /etc/ImageMagick-6/policy.xml\n\n            - name: Install dependencies\n              run: |\n                  composer require \"laravel/framework:${{ matrix.laravel }}\" \"orchestra/testbench:${{ matrix.testbench }}\" --no-interaction --no-update\n                  composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest\n            - name: Execute tests\n              run: vendor/bin/phpunit\n              env:\n                  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n                  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n                  AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}\n                  AWS_BUCKET: ${{ secrets.AWS_BUCKET }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\nvendor\n.phpunit.result.cache\ncomposer.lock"
  },
  {
    "path": ".styleci.yml",
    "content": "preset: laravel\n"
  },
  {
    "path": "README.md",
    "content": "# Laravel Media Uploader\n<p align=\"center\">\n<a href=\"https://github.com/ahmed-aliraqi/laravel-media-uploader/actions\"><img src=\"https://github.com/ahmed-aliraqi/laravel-media-uploader/workflows/tests/badge.svg\" alt=\"Build Status\"></a>\n\t<a href=\"https://github.styleci.io/repos/275045511\"><img src=\"https://github.styleci.io/repos/275045511/shield?style=flat\" alt=\"StyleCI\"></a>\n\t<a href=\"https://packagist.org/packages/ahmed-aliraqi/laravel-media-uploader\"><img src=\"https://poser.pugx.org/ahmed-aliraqi/laravel-media-uploader/d/total.svg\" alt=\"Total Downloads\"></a>\n\t<a href=\"https://packagist.org/packages/ahmed-aliraqi/laravel-media-uploader\"><img src=\"https://poser.pugx.org/ahmed-aliraqi/laravel-media-uploader/v/stable.svg\" alt=\"Latest Stable Version\"></a>\n\t<a href=\"https://packagist.org/packages/ahmed-aliraqi/laravel-media-uploader\"><img src=\"https://poser.pugx.org/ahmed-aliraqi/laravel-media-uploader/license.svg\" alt=\"License\"></a>\n</p>\n\n> This package used to upload files using laravel-media-library before saving model.\n\n![Uploader](https://github.com/ahmed-aliraqi/laravel-file-uploader/blob/master/screenshots/uploader-v2.gif?raw=true)\n\n> In this package all uploaded media will be processed.\n* All videos will converted to `mp4`.\n* All audios will converted to `mp3`.\n* All images `width` & `height` & `ratio` will be saved as custom property. \n* All videos & audios `duration` will be saved as custom property. \n#### Requirements\n- PHP >= 7.4\n- You should be ensured that the [ffmpeg](https://ffmpeg.org) was installed on your server\n\n#### Installation\n```bash\ncomposer require ahmed-aliraqi/laravel-media-uploader\n```\n> The package will automatically register a service provider.\n  \n> You need to publish and run the migration:\n\n```bash\nphp artisan vendor:publish --provider=\"AhmedAliraqi\\LaravelMediaUploader\\Providers\\UploaderServiceProvider\" --tag=\"migrations\"\n\nphp artisan migrate\n```\n> Publish [laravel-media-library](https://github.com/spatie/laravel-medialibrary) migrations:\n\n```bash\nphp artisan vendor:publish --provider=\"Spatie\\MediaLibrary\\MediaLibraryServiceProvider\" --tag=\"migrations\"\nphp artisan migrate\n```\n\n> If you want to customize `attachments` validation rules, you should publish the config file:\n\n```bash\nphp artisan vendor:publish --provider=\"AhmedAliraqi\\LaravelMediaUploader\\Providers\\UploaderServiceProvider\" --tag=\"config\"\n```\n\n> If you want to customize validation translations, you should publish the `lang` files:\n\n```bash\nphp artisan vendor:publish --provider=\"AhmedAliraqi\\LaravelMediaUploader\\Providers\\UploaderServiceProvider\" --tag=\"uploader:translations\"\n```\n\n> This is the default content of the config file:\n\n```php\n<?php\n\nreturn [\n    /*\n     * Regenerate uploaded media after assign to model\n     */\n    'regenerate-after-assigning' => true,\n\n    'documents_mime_types' => [\n        'application/msword',\n        'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .doc & .docx\n        'application/vnd.ms-powerpoint',\n        'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .ppt & .pptx\n        'application/vnd.ms-excel',\n        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xls & .xlsx\n        'text/plain',\n        'application/pdf',\n        'application/zip',\n        'application/x-rar',\n        'application/x-rar-compressed',\n        'application/octet-stream',\n    ],\n];\n```\n\n> Use `HasUploader` trait in your model:\n\n```php\n<?php\n\nnamespace App;\n\n\nuse Spatie\\MediaLibrary\\InteractsWithMedia;\nuse Spatie\\MediaLibrary\\MediaCollections\\Models\\Media;\nuse Spatie\\MediaLibrary\\HasMedia;\nuse AhmedAliraqi\\LaravelMediaUploader\\Entities\\Concerns\\HasUploader;\n\nclass Blog extends Model implements HasMedia\n{\n    use InteractsWithMedia, HasUploader;\n    ...\n}\n```\n> In your controller use `addAllMediaFromTokens()` method to assign the uploaded media to model using the generated tokens:\n\n```php\nclass BlogController extends Controller\n{\n        public function store(Request $request)\n        {\n            $blog = Blog::create($request->all());\n            \n            $blog->addAllMediaFromTokens();\n    \n            return back();\n        }\n}\n``` \n> If you do not add any arguments in `addAllMediaFromTokens()` method will add all tokens in `request('media')` with any collection.\n>\n>If you want to save specific collection name add it to the second argument.\n```php\n// specified collection name\n$blog->addAllMediaFromTokens([], 'pictures');\n\n// specified tokens\n$blog->addAllMediaFromTokens($request->input('tokens', []), 'pictures');\n```\n\n#### Front End Basic Usage\n```blade\n<div id=\"app\">\n    <file-uploader\n            :unlimited=\"true\"\n            collection=\"avatars\"\n            :tokens=\"{{ json_encode(old('media', [])) }}\"\n            label=\"Upload Avatar\"\n            notes=\"Supported types: jpeg, png,jpg,gif\"\n            accept=\"image/jpeg,image/png,image/jpg,image/gif\"\n    ></file-uploader>\n</div>\n\n<script src=\"https://cdn.jsdelivr.net/npm/vue/dist/vue.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/laravel-file-uploader\"></script>\n<script>\n  new Vue({\n    el: '#app'\n  })\n</script>\n```\n###### Or Install Component Via NPM\n\n```bash\nnpm i laravel-file-uploader --save-dev\n``` \n> Now you should register the component in your `resources/js/app.js`:\n\n```js\n// app.js\n\nimport FileUploader from 'laravel-file-uploader';\n\nVue.use(FileUploader);\n```\n\n#### Usage\n```blade\n<file-uploader :media=\"{{ $user->getMediaResource('avatars') }}\"\n               :unlimited=\"true\"\n               collection=\"avatars\"\n               :tokens=\"{{ json_encode(old('media', [])) }}\"\n               label=\"Upload Avatar\"\n               notes=\"Supported types: jpeg, png,jpg,gif\"\n               accept=\"image/jpeg,image/png,image/jpg,image/gif\"\n></file-uploader>\n```\n##### Attributes\n| Attribute |Rule | Type  |Description |\n|--|--|--|--|\n| media | optional - default: `[]`  |array | used to display an existing files  |\n| unlimited |optional - default:`false`| boolean| upload unlimited files - if let it `false` will not be multiple select|\n| max|optional - default:`12`| int| the maximum uploaded files - if `1` will not me multiple select|\n|accept| optional - default: `*`| string| the accepted mime types|\n|form| optional - default: `false`| string| the form id of the uploaded media|\n|notes| optional - default `null`| string| the help-block that will be displayed under the files|\n|label| optional - default `null`| string| the label of the uploader|\n|collection| optional - default `default`|string| the media library collection that the file will store in|\n|tokens| optional - default: `[]`|array|the recently uploaded files tokens, used to display recently uploaded files in validation case|\n|max-width| optional - default: `1200`|string|The maximum width of uploaded image|\n|max-height| optional - default: `1200`|string|The maximum height of uploaded image|\n\n#### API\n* Upload Files\n    * endpoint: /api/uploader/media/upload\n    * method: POST\n    * body: \n        * files[]: multipart form data\n    * response:\n        * ![upload response](https://i.imgur.com/dvPX9Wa.png)\n* Display Recently Uploaded Files\n    * endpoint: /api/uploader/media\n    * method: GET\n    * params:\n        * tokens[]: temporary token\n    * response:\n        * ![response](https://i.imgur.com/0xaaDPK.png)\n* Delete Files\n    * endpoint: /api/uploader/media/{id}\n    * method: DELETE\n    * response:\n        * ![response](https://i.imgur.com/dghxe47.png)\n"
  },
  {
    "path": "_ide_helper.php",
    "content": "<?php\n// @formatter:off\n\n/**\n * A helper file for Laravel, to provide autocomplete information to your IDE\n **\n * @author Ahmed Fathy <aliraqi.dev@gmail.com>\n */\n\n/**\n * @method static \\AhmedAliraqi\\LaravelMediaUploader\\Forms\\Components\\ImageComponent image($name = null)\n * @method static \\AhmedAliraqi\\LaravelMediaUploader\\Forms\\Components\\AudioComponent audio($name = null)\n * @method static \\AhmedAliraqi\\LaravelMediaUploader\\Forms\\Components\\VideoComponent video($name = null)\n * @method static \\AhmedAliraqi\\LaravelMediaUploader\\Forms\\Components\\MediaComponent media($name = null)\n */\nclass BsForm extends \\Laraeast\\LaravelBootstrapForms\\Facades\\BsForm {}"
  },
  {
    "path": "changelog.md",
    "content": "# Release Notes for Laravel Media Uploader\n### v8.0.0\n* **Fixes**\n  - Remove support for BsForm package [2d17c04](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/2d17c04831f52838a7c1bc9157e57940030f81a8)\n### v6.3.3\n* **Fixes**\n  - Run the artisan command once after saving the media instead of running in loop [22](https://github.com/ahmed-aliraqi/laravel-media-uploader/pull/22) by [AbdullahFaqeir](https://github.com/AbdullahFaqeir)\n  - Fix base64 validation issue [05fed33](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/05fed333a5b96196cc78b4fa4aa1e533aef4f1e9)\n### v6.3.0\n* **Added**\n  - Add Support for laravel 9.x [18](https://github.com/ahmed-aliraqi/laravel-media-uploader/pull/18) by [AbdullahFaqeir](https://github.com/AbdullahFaqeir)\n  ### v6.2.0\n* **Fixes**\n  - Clean the temporary files every six hours [b132699](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/b1326999f3cac6a548bad11c00cf2d7da0287b0d)\n* **Added**\n  - Add Uploader helper [4e743bf](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/4e743bfefdcf03e6d9b3e0d05966f2c08e71ddda)\n### v6.1.2\n* **Fixes**\n  - Replace Hindu-Arabic numerals to Arabic numerals [4e45b49](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/4e45b4945a8311eecb53e3fd26062934b43aeea4)\n### v6.1.0\n* **Added**\n  - Optimize and Upload images as base64.\n### v6.0.1\n* **Fixes**\n  - Add ability to filter by collection with token to avoid duplicate the old media.\n### v6.0.0\n* **Added**\n  - Add support for php 8.0\n* **Changes**\n  - Use `MediaHasBeenAdded` Event instead of `PerformConversionsJob`\n  - Bump `laravel media library` from ^8.0 to ^9.0\n### v5.1.0\n* **Added**\n  - Add `AudioComponent` for `laravel-bootstrap-forms`,\n  - Add `VideoComponent` for `laravel-bootstrap-forms`,\n  - Add `Audioomponent` for `laravel-bootstrap-forms`,\n  - Add `Mediaomponent` for `laravel-bootstrap-forms`,\n  - Add `_ide_helper.php` file to provide autocomplete information to your IDE.\n\n### v5.0.1\n* **Fixes**\n    - Keep only configured latest media [4e3f6e6](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/4e3f6e6c4b25797fafa1cae3173e89a93e260339).\n### v5.0.0\n* **Added**\n    - Add `form` and `unlimited` option to form component.\n### v4.1.1\n* **Fixes**\n    - Fix support for laravel 8.x [678f06d](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/678f06d8441c2cbd8923bc3f0c6aa7b831c36f78)\n### v4.1.0\n* **Added**\n    - Add support for laravel 8.x\n### v4.0.0\n* **Changes**\n    - Upgraded media-library to ^8.0. [c7f1e8e](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/c7f1e8eda602d4b377cb33c98cf244c200dd1cf1)\n### v3.0.0\n* **Changes**\n    - change vendor name of laravel-bootstrap-forms. [d09599d](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/d09599d07d8e6ca92f393de0dd0a47cc1c934b32)\n### v2.1.0\n* **Added**\n    - Add \"regenerate-after-assigning\" option in config file [4fb569b](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/4fb569ba99dafd3098698e4aa274c1868d0d9206)\n* **Changes**\n    - The first argument of `addAllMediaFromTokens($tokens)` now support `string`, `array`, `null` value. [a451ebb](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/a451ebbdfac6e94ca1c588977a4ada4c489a48bf)\n### v2.0.1\n* **Fixes**\n    - Register and publish translations [b5b7dd3](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/b5b7dd3efd11a6c0c6aeac82e83003da645a1a09)\n### v2.0.0\n* **Changes**\n    - Remove built in migration and use published instead [8611ac6](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/8611ac6bbb9b8833c8231ae8d03e4cf1cb7d6866).\n    - Remove `uploader:install` command line [7f0bb58](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/7f0bb58b45f634ba4937ff7cdfee025e8a6e021b).\n    - Optional `preview` flag in MediaResource [e16344d](https://github.com/ahmed-aliraqi/laravel-media-uploader/commit/e16344de7eed1fdd33c33186fc4c0b21df23f835).\n### v1.0.1\n* **Changes**\n    - Add tow optional arguments in `addAllMediaFromTokens()`\n        - $tokens = []\n        - $collection = 'default'\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"ahmed-aliraqi/laravel-media-uploader\",\n    \"description\": \"This package used to upload files using laravel-media-library\",\n    \"type\": \"library\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Ahmed Fathy\",\n            \"email\": \"aliraqi.dev@gmail.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.4|^8.0\",\n        \"laravel/framework\": \"~5.7|~5.8|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0\",\n        \"spatie/laravel-medialibrary\": \"^9.0|^10.0|^11.0\",\n        \"php-ffmpeg/php-ffmpeg\": \"^1.0\"\n    },\n    \"require-dev\": {\n        \"orchestra/testbench\": \"~3.0|~5.3|~6.0|~7.0\",\n        \"mockery/mockery\": \"^1.4\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"AhmedAliraqi\\\\LaravelMediaUploader\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"AhmedAliraqi\\\\LaravelMediaUploader\\\\Tests\\\\\": \"tests/\"\n        }\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"AhmedAliraqi\\\\LaravelMediaUploader\\\\Providers\\\\UploaderServiceProvider\"\n            ]\n        }\n    }\n}\n"
  },
  {
    "path": "phpunit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" bootstrap=\"vendor/autoload.php\" backupGlobals=\"false\" backupStaticAttributes=\"false\" colors=\"true\" verbose=\"true\" convertErrorsToExceptions=\"true\" convertNoticesToExceptions=\"true\" convertWarningsToExceptions=\"true\" processIsolation=\"false\" stopOnFailure=\"false\" xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/9.3/phpunit.xsd\">\n  <coverage>\n    <include>\n      <directory suffix=\".php\">src/</directory>\n    </include>\n  </coverage>\n  <testsuites>\n    <testsuite name=\"Laravel Media Uploader Test Suite\">\n      <directory>tests</directory>\n    </testsuite>\n  </testsuites>\n</phpunit>\n"
  },
  {
    "path": "src/Config/laravel-media-uploader.php",
    "content": "<?php\n\nreturn [\n    /*\n     * Regenerate uploaded media after assign to model\n     */\n    'regenerate-after-assigning' => true,\n\n    'documents_mime_types' => [\n        'application/msword',\n        'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .doc & .docx\n        'application/vnd.ms-powerpoint',\n        'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .ppt & .pptx\n        'application/vnd.ms-excel',\n        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xls & .xlsx\n        'text/plain',\n        'application/pdf',\n        'application/zip',\n        'application/x-rar',\n        'application/x-rar-compressed',\n        'application/octet-stream',\n    ],\n];\n"
  },
  {
    "path": "src/Console/TemporaryClearCommand.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Console;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Entities\\TemporaryFile;\nuse Illuminate\\Console\\Command;\n\nclass TemporaryClearCommand extends Command\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'temporary:clean';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Clean expired uploaded temporary files.';\n\n    /**\n     * Create a new command instance.\n     *\n     * @return void\n     */\n    public function __construct()\n    {\n        parent::__construct();\n    }\n\n    /**\n     * Execute the console command.\n     *\n     * @return mixed\n     */\n    public function handle()\n    {\n        TemporaryFile::whereDate('created_at', '<=', today()->subHours(6))\n            ->each(function (TemporaryFile $file) {\n                $file->delete();\n            });\n\n        $this->info(\n            \"\\nThe temporary files has been cleaned successfully. \"\n            .now()->toDateTimeString()\n        );\n    }\n}\n"
  },
  {
    "path": "src/Database/Migrations/2020_06_03_131044_create_temporary_files_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateTemporaryFilesTable extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('temporary_files', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->string('token');\n            $table->string('collection')->default('default');\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('temporary_files');\n    }\n}\n"
  },
  {
    "path": "src/Entities/Concerns/HasUploader.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Entities\\Concerns;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Entities\\TemporaryFile;\nuse AhmedAliraqi\\LaravelMediaUploader\\Transformers\\MediaResource;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Facades\\Artisan;\nuse Illuminate\\Support\\Facades\\Config;\n\ntrait HasUploader\n{\n    /**\n     * Assign all uploaded temporary files to the model.\n     *\n     * @param  string|array|null  $tokens\n     * @param  string|null  $collection\n     * @return void\n     */\n    public function addAllMediaFromTokens($tokens = null, $collection = null)\n    {\n        $tokens = Arr::wrap($tokens);\n\n        if (count($tokens) == 0) {\n            $tokens = Arr::wrap(request('media'));\n        }\n\n        $query = TemporaryFile::query();\n\n        if ($collection) {\n            $query->where('collection', $collection);\n        }\n\n        $mediaIds = [];\n\n        $query->whereIn('token', $tokens)\n            ->each(function (TemporaryFile $file) use (&$mediaIds) {\n                foreach ($file->getMedia($file->collection) as $media) {\n                    $media->forceFill([\n                        'model_type' => $this->getMorphClass(),\n                        'model_id' => $this->getKey(),\n                    ])->save();\n                    $mediaIds[] = $media->id;\n                }\n\n                $file->delete();\n            });\n\n        if (count($mediaIds) > 0 && Config::get('laravel-media-uploader.regenerate-after-assigning')) {\n            Artisan::call('media-library:regenerate', [\n                '--ids' => implode(',', $mediaIds),\n                '--force' => true,\n            ]);\n        }\n\n        $collection = $collection ?: 'default';\n\n        if ($collectionSizeLimit = optional($this->getMediaCollection($collection))->collectionSizeLimit) {\n            $collectionMedia = $this->refresh()->getMedia($collection);\n\n            if ($collectionMedia->count() > $collectionSizeLimit) {\n                $this->clearMediaCollectionExcept(\n                    $collection,\n                    $collectionMedia\n                        ->reverse()\n                        ->take($collectionSizeLimit)\n                );\n            }\n        }\n    }\n\n    /**\n     * Get all the model media of the given collection using \"MediaResource\".\n     *\n     * @param  string  $collection\n     * @return \\Illuminate\\Support\\Collection\n     */\n    public function getMediaResource($collection = 'default')\n    {\n        return collect(\n            MediaResource::collection(\n                $this->getMedia($collection)\n            )->jsonSerialize()\n        );\n    }\n}\n"
  },
  {
    "path": "src/Entities/TemporaryFile.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Entities;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Spatie\\MediaLibrary\\HasMedia;\nuse Spatie\\MediaLibrary\\InteractsWithMedia;\nuse Spatie\\MediaLibrary\\MediaCollections\\Models\\Media;\n\nclass TemporaryFile extends Model implements HasMedia\n{\n    use InteractsWithMedia;\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     */\n    protected $fillable = [\n        'token',\n        'collection',\n    ];\n\n    /**\n     * Register the conversions for the specified model.\n     *\n     *\n     * @throws \\Spatie\\Image\\Exceptions\\InvalidManipulation\n     */\n    public function registerMediaConversions(?Media $media = null): void\n    {\n        $this->addMediaConversion('thumb')\n            ->width(70)\n            ->format('png');\n\n        $this->addMediaConversion('small')\n            ->width(120)\n            ->format('png');\n\n        $this->addMediaConversion('medium')\n            ->width(160)\n            ->format('png');\n\n        $this->addMediaConversion('large')\n            ->width(320)\n            ->format('png');\n    }\n}\n"
  },
  {
    "path": "src/Http/Controllers/MediaController.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Http\\Controllers;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Entities\\TemporaryFile;\nuse AhmedAliraqi\\LaravelMediaUploader\\Http\\Requests\\MediaRequest;\nuse AhmedAliraqi\\LaravelMediaUploader\\Support\\Uploader;\nuse AhmedAliraqi\\LaravelMediaUploader\\Transformers\\MediaResource;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Routing\\Controller;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Str;\n\nclass MediaController extends Controller\n{\n    /**\n     * Display a listing of the resource.\n     *\n     * @return \\Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection\n     */\n    public function index()\n    {\n        $modelClass = Config::get(\n            'media-library.media_model',\n            \\Spatie\\MediaLibrary\\MediaCollections\\Models\\Media::class\n        );\n\n        $tokens = is_array(request('tokens')) ? request('tokens') : [];\n\n        $media = $modelClass::whereHasMorph(\n            'model',\n            [TemporaryFile::class],\n            function (Builder $builder) use ($tokens) {\n                $builder->whereIn('token', $tokens);\n                $builder->when(request('collection'), function (Builder $builder) {\n                    $builder->where(request()->only('collection'));\n                });\n            }\n        )->get();\n\n        return MediaResource::collection($media);\n    }\n\n    /**\n     * Store a newly created resource in storage.\n     *\n     * @return \\Illuminate\\Http\\Resources\\Json\\AnonymousResourceCollection\n     *\n     * @throws \\Spatie\\MediaLibrary\\MediaCollections\\Exceptions\\FileDoesNotExist\n     * @throws \\Spatie\\MediaLibrary\\MediaCollections\\Exceptions\\FileIsTooBig\n     */\n    public function store(MediaRequest $request)\n    {\n        /** @var \\AhmedAliraqi\\LaravelMediaUploader\\Entities\\TemporaryFile $temporaryFile */\n        $temporaryFile = TemporaryFile::create([\n            'token' => Str::random(60),\n            'collection' => $request->input('collection', 'default'),\n        ]);\n\n        if (is_string($request->file) && base64_decode(base64_encode($request->file)) === $request->file) {\n            $temporaryFile->addMediaFromBase64($request->file)\n                ->usingFileName(time().'.png')\n                ->toMediaCollection($temporaryFile->collection);\n        }\n\n        if ($request->hasFile('file')) {\n            $temporaryFile->addMedia($request->file)\n                ->usingFileName(Uploader::formatName($request->file))\n                ->toMediaCollection($temporaryFile->collection);\n        }\n\n        foreach ($request->file('files', []) as $file) {\n            $temporaryFile->addMedia($file)\n                ->usingFileName(Uploader::formatName($file))\n                ->toMediaCollection($temporaryFile->collection);\n        }\n\n        return MediaResource::collection(\n            $temporaryFile->getMedia(\n                $temporaryFile->collection ?: 'default'\n            )\n        )->additional([\n            'token' => $temporaryFile->token,\n        ]);\n    }\n\n    /**\n     * @return \\Illuminate\\Http\\JsonResponse\n     */\n    public function destroy($media)\n    {\n        $modelClass = Config::get(\n            'media-library.media_model',\n            \\Spatie\\MediaLibrary\\MediaCollections\\Models\\Media::class\n        );\n\n        $media = $modelClass::findOrFail($media);\n\n        $media->delete();\n\n        return response()->json([\n            'message' => 'deleted',\n        ]);\n    }\n}\n"
  },
  {
    "path": "src/Http/Requests/MediaRequest.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Http\\Requests;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Rules\\MediaRule;\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nclass MediaRequest extends FormRequest\n{\n    /**\n     * Get the validation rules that apply to the request.\n     *\n     * @return array\n     */\n    public function rules()\n    {\n        return [\n            'file' => ['sometimes', 'required', new MediaRule('image', 'video', 'audio', 'document')],\n            'files' => ['sometimes', 'required', 'array'],\n            'files.*' => ['sometimes', 'required', new MediaRule('image', 'video', 'audio', 'document')],\n            'collection' => ['nullable', 'string'],\n        ];\n    }\n\n    /**\n     * Determine if the user is authorized to make this request.\n     *\n     * @return bool\n     */\n    public function authorize()\n    {\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Listeners/ProcessUploadedMedia.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Listeners;\n\nuse FFMpeg\\Format\\Audio\\Mp3;\nuse FFMpeg\\Format\\Video\\X264;\nuse FFMpeg\\Media\\Audio;\nuse FFMpeg\\Media\\Video;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Support\\Facades\\Config;\nuse Intervention\\Image\\Facades\\Image;\nuse RuntimeException;\nuse Spatie\\MediaLibrary\\Conversions\\ImageGenerators\\Image as ImageGenerator;\nuse Spatie\\MediaLibrary\\MediaCollections\\Events\\MediaHasBeenAdded;\nuse Spatie\\MediaLibrary\\MediaCollections\\Models\\Media;\n\nclass ProcessUploadedMedia implements ShouldQueue\n{\n    /**\n     * Handle the event.\n     *\n     * @return void\n     *\n     * @throws \\Exception\n     */\n    public function handle(MediaHasBeenAdded $event)\n    {\n        if (app()->runningUnitTests()) {\n            return;\n        }\n\n        if ($event->media->getCustomProperty('status') == 'processed') {\n            // Skipped Processing Media File\n            return;\n        }\n\n        try {\n            if ($this->isImage($event->media)) {\n                $path = $this->processImage($event->media);\n            } elseif ($this->isDocument($event->media)) {\n                $path = $this->processDocument($event->media);\n            } elseif ($this->isVideo($event->media)) {\n                $path = $this->processVideo($event->media);\n            } elseif ($this->isAudio($event->media)) {\n                $path = $this->processAudio($event->media);\n            } else {\n                $path = null;\n            }\n            $this->processingDone($event->media, $path);\n        } catch (RuntimeException $e) {\n            $this->processingFailed($event->media);\n        }\n\n        $event->media->setCustomProperty('status', 'processing')->save();\n    }\n\n    /**\n     * Determine if the media file is an image.\n     *\n     * @return bool\n     */\n    protected function isImage(Media $media)\n    {\n        return (new ImageGenerator)->canHandleMime($media->mime_type);\n    }\n\n    /**\n     * Determine if the media file is a document.\n     *\n     * @return bool\n     */\n    protected function isDocument(Media $media)\n    {\n        return in_array(\n            $media->mime_type,\n            Config::get('laravel-media-uploader.documents_mime_types')\n        );\n    }\n\n    /**\n     * Determine if the media file is a video and initiate the required driver.\n     *\n     * @return bool\n     */\n    protected function isVideo(Media $media)\n    {\n        return app('ffmpeg-driver')->open($media->getPath()) instanceof Video;\n    }\n\n    /**\n     * Determine if the media file is an audio and the initiate required driver.\n     *\n     * @return bool\n     */\n    protected function isAudio(Media $media)\n    {\n        return app('ffmpeg-driver')->open($media->getPath()) instanceof Audio;\n    }\n\n    /**\n     * Process Image File.\n     *\n     * @return null\n     */\n    protected function processImage(Media $media)\n    {\n        $image = Image::make($media->getPath())->orientate();\n\n        $media\n            ->setCustomProperty('type', 'image')\n            ->setCustomProperty('width', $image->width())\n            ->setCustomProperty('height', $image->height())\n            ->setCustomProperty('ratio', (string) round($image->width() / $image->height(), 3))\n            ->save();\n    }\n\n    /**\n     * Process Document File.\n     *\n     * @return null\n     */\n    protected function processDocument(Media $media)\n    {\n        $media->setCustomProperty('type', 'document')->save();\n    }\n\n    /**\n     * Process Video File.\n     *\n     * @return string\n     */\n    protected function processVideo(Media $media)\n    {\n        $media->setCustomProperty('type', 'video')->save();\n\n        $video = app('ffmpeg-driver')->open($media->getPath());\n\n        $format = new X264;\n\n        $format->on('progress', $this->increaseProcessProgress($media));\n\n        $format->setAudioCodec('aac');\n\n        $format->setAdditionalParameters(['-vf', 'pad=ceil(iw/2)*2:ceil(ih/2)*2']);\n\n        $video->save($format, $processedFile = $this->generatePathForProcessedFile($media, 'mp4'));\n\n        return $processedFile;\n    }\n\n    /**\n     * Process Audio File.\n     *\n     * @return string\n     */\n    protected function processAudio(Media $media)\n    {\n        $media->setCustomProperty('type', 'audio')->save();\n\n        $audio = app('ffmpeg-driver')->open($media->getPath());\n\n        $format = new Mp3;\n\n        $format->on('progress', $this->increaseProcessProgress($media));\n\n        $audio->save($format, $processedFile = $this->generatePathForProcessedFile($media, 'mp3'));\n\n        return $processedFile;\n    }\n\n    protected function increaseProcessProgress(Media $media): \\Closure\n    {\n        return function (\n            $file,\n            $format,\n            $percentage\n        ) use ($media) {\n            // Progress Percentage is $percentage\n            $media->setCustomProperty('progress', $percentage);\n            $media->save();\n        };\n    }\n\n    /**\n     * @param  null  $processedFilePath\n     * @return void\n     *\n     * @throws \\Exception\n     */\n    protected function processingDone(Media $media, $processedFilePath = null)\n    {\n        // If the processing does not ended with generating a new file.\n        if (is_null($processedFilePath)) {\n            $media->setCustomProperty('status', 'processed')\n                ->setCustomProperty('progress', 100)\n                ->save();\n        } else {\n            // New Converted Media Will Be Added\n            $duration = app('ffmpeg-driver')\n                ->getFFProbe()\n                ->format($processedFilePath)\n                ->get('duration');\n\n            $media->model\n                ->addMedia($processedFilePath)\n                ->withCustomProperties([\n                    'type' => $media->getCustomProperty('type'),\n                    'status' => 'processed',\n                    'progress' => 100,\n                    'duration' => $duration,\n                ])\n                ->preservingOriginal()\n                ->toMediaCollection($media->collection_name);\n\n            (clone $media)->delete();\n        }\n    }\n\n    /**\n     * Mark media status as failed.\n     */\n    protected function processingFailed(Media $media)\n    {\n        $media->setCustomProperty('status', 'failed')->save();\n    }\n\n    /**\n     * @param  null  $extension\n     * @return string\n     */\n    protected function generatePathForProcessedFile(Media $media, $extension = null)\n    {\n        $path = $media->getPath();\n\n        return pathinfo($path, PATHINFO_DIRNAME)\n            .DIRECTORY_SEPARATOR.pathinfo($path, PATHINFO_FILENAME)\n            .'.processed.'.$extension;\n    }\n}\n"
  },
  {
    "path": "src/Providers/EventServiceProvider.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Providers;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Listeners\\ProcessUploadedMedia;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\nuse Spatie\\MediaLibrary\\MediaCollections\\Events\\MediaHasBeenAdded;\n\nclass EventServiceProvider extends ServiceProvider\n{\n    /**\n     * The event listener mappings for the application.\n     *\n     * @var array\n     */\n    protected $listen = [\n        MediaHasBeenAdded::class => [\n            ProcessUploadedMedia::class,\n        ],\n    ];\n}\n"
  },
  {
    "path": "src/Providers/RouteServiceProvider.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Providers;\n\nuse Illuminate\\Foundation\\Support\\Providers\\RouteServiceProvider as ServiceProvider;\nuse Illuminate\\Support\\Facades\\Route;\n\nclass RouteServiceProvider extends ServiceProvider\n{\n    /**\n     * The namespace to assume when generating URLs to actions.\n     *\n     * @var string\n     */\n    protected $namespace = 'AhmedAliraqi\\LaravelMediaUploader\\Http\\Controllers';\n\n    /**\n     * Called before routes are registered.\n     *\n     * Register any model bindings or pattern based filters.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        parent::boot();\n    }\n\n    /**\n     * Define the routes for the application.\n     *\n     * @return void\n     */\n    public function map()\n    {\n        $this->mapApiRoutes();\n    }\n\n    /**\n     * Define the \"api\" routes for the application.\n     *\n     * These routes are typically stateless.\n     *\n     * @return void\n     */\n    protected function mapApiRoutes()\n    {\n        Route::prefix('api')\n            ->middleware('api')\n            ->namespace($this->namespace)\n            ->group(__DIR__.'/../Routes/api.php');\n    }\n}\n"
  },
  {
    "path": "src/Providers/UploaderServiceProvider.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Providers;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Console\\TemporaryClearCommand;\nuse AhmedAliraqi\\LaravelMediaUploader\\Support\\FFmpegDriver;\nuse Illuminate\\Console\\Scheduling\\Schedule;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass UploaderServiceProvider extends ServiceProvider\n{\n    /**\n     * Boot the application events.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        if (! defined('STDIN')) {\n            define('STDIN', fopen('php://stdin', 'r'));\n        }\n\n        $this->registerConfig();\n\n        $this->registerTranslations();\n\n        $this->publishes([\n            __DIR__.'/../Database/Migrations' => database_path('/migrations'),\n        ], 'migrations');\n\n        $this->commands([\n            TemporaryClearCommand::class,\n        ]);\n\n        if (! $this->app->runningUnitTests()) {\n            $this->app->booted(function () {\n                $schedule = $this->app->make(Schedule::class);\n                $schedule->command('temporary:clean')->everySixHours();\n            });\n        }\n    }\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->app->register(RouteServiceProvider::class);\n        $this->app->register(EventServiceProvider::class);\n\n        $this->app->singleton('ffmpeg-driver', function () {\n            return (new FFmpegDriver)->driver();\n        });\n    }\n\n    /**\n     * Register config.\n     *\n     * @return void\n     */\n    protected function registerConfig()\n    {\n        $this->publishes([\n            __DIR__.'/../Config/laravel-media-uploader.php' => config_path('laravel-media-uploader.php'),\n        ], 'config');\n        $this->mergeConfigFrom(\n            __DIR__.'/../Config/laravel-media-uploader.php',\n            'laravel-media-uploader'\n        );\n    }\n\n    /**\n     * Register translations.\n     *\n     * @return void\n     */\n    public function registerTranslations()\n    {\n        $this->publishes([\n            __DIR__.'/../Resources/lang' => resource_path('lang/vendor/uploader'),\n        ], 'uploader:translations');\n\n        $this->loadTranslationsFrom(__DIR__.'/../Resources/lang', 'uploader');\n    }\n}\n"
  },
  {
    "path": "src/Resources/lang/ar/validation.php",
    "content": "<?php\n\nreturn [\n    'invalid' => 'قيمة حقل :attribute غير مدعومة',\n];\n"
  },
  {
    "path": "src/Resources/lang/en/validation.php",
    "content": "<?php\n\nreturn [\n    'invalid' => 'The :attribute is not supported.',\n];\n"
  },
  {
    "path": "src/Routes/api.php",
    "content": "<?php\n\nRoute::get('uploader/media', 'MediaController@index')->name('uploader.media.index');\nRoute::post('uploader/media/upload', 'MediaController@store')->name('uploader.media.store');\nRoute::delete('uploader/media/{media}', 'MediaController@destroy')->name('uploader.media.destroy');\n"
  },
  {
    "path": "src/Rules/MediaRule.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Rules;\n\nuse FFMpeg\\Exception\\RuntimeException;\nuse Illuminate\\Contracts\\Validation\\Rule;\nuse Illuminate\\Http\\UploadedFile;\nuse Illuminate\\Support\\Facades\\Config;\nuse Spatie\\MediaLibrary\\Conversions\\ImageGenerators\\Image;\n\nclass MediaRule implements Rule\n{\n    /**\n     * @var array\n     */\n    private $types;\n\n    /**\n     * @var \\FFMpeg\\FFMpeg\n     */\n    private $driver;\n\n    /**\n     * Create a new rule instance.\n     */\n    public function __construct(...$types)\n    {\n        $this->types = $types;\n    }\n\n    /**\n     * Determine if the validation rule passes.\n     *\n     * @param  string  $attribute\n     * @param  UploadedFile|mixed  $value\n     * @return bool\n     */\n    public function passes($attribute, $value)\n    {\n        if (! $value instanceof UploadedFile && ! $this->isBase64($value)) {\n            return false;\n        }\n\n        try {\n            $type = $this->getTypeString($value);\n        } catch (RuntimeException $e) {\n            return false;\n        }\n\n        return in_array($type, $this->types);\n    }\n\n    /**\n     * Get the validation error message.\n     *\n     * @return string\n     */\n    public function message()\n    {\n        return trans('uploader::validation.invalid');\n    }\n\n    /**\n     * @param  UploadedFile|mixed  $value\n     */\n    protected function getTypeString($value): string\n    {\n        if ($this->isBase64($value)) {\n            return 'image';\n        }\n\n        $fileFullPath = $value->getRealPath();\n\n        if ((new Image)->canHandleMime($value->getMimeType())) {\n            $type = 'image';\n        } elseif (in_array($value->getMimeType(), $this->documentsMimeTypes())) {\n            $type = 'document';\n        } else {\n            $type = strtolower(class_basename(get_class(\n                app('ffmpeg-driver')->open($fileFullPath)\n            )));\n        }\n\n        return $type; // either: image, video or audio.\n    }\n\n    /**\n     * The supported mime types for document files.\n     *\n     * @return string[]\n     */\n    protected function documentsMimeTypes()\n    {\n        return Config::get('laravel-media-uploader.documents_mime_types');\n    }\n\n    /**\n     * Determine whither the value is base64 image.\n     *\n     * @return bool\n     */\n    protected function isBase64($value)\n    {\n        return is_string($value) && base64_decode(base64_encode($value)) === $value;\n    }\n}\n"
  },
  {
    "path": "src/Support/FFmpegDriver.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Support;\n\nuse FFMpeg\\FFMpeg;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass FFmpegDriver\n{\n    /**\n     * @var \\FFMpeg\\FFMpeg\n     */\n    private $driver;\n\n    /**\n     * Create driver instance.\n     */\n    public function __construct()\n    {\n        $this->driver = FFMpeg::create([\n            'ffmpeg.binaries' => Config::get('media-library.ffmpeg_path'),\n            'ffprobe.binaries' => Config::get('media-library.ffprobe_path'),\n            'timeout' => 3600,\n            'ffmpeg.threads' => 12,\n        ]);\n    }\n\n    /**\n     * @return \\FFMpeg\\FFMpeg\n     */\n    public function driver()\n    {\n        return $this->driver;\n    }\n}\n"
  },
  {
    "path": "src/Support/Uploader.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Support;\n\nuse Illuminate\\Http\\UploadedFile;\nuse Illuminate\\Support\\Str;\n\nclass Uploader\n{\n    /**\n     * Get the formatted name of the given file.\n     */\n    public static function formatName(UploadedFile $file): string\n    {\n        $extension = '.'.$file->getClientOriginalExtension();\n\n        $name = trim($file->getClientOriginalName(), $extension);\n\n        $name = self::replaceNumbers($name);\n\n        return Str::slug($name).$extension;\n    }\n\n    /**\n     * Convert arabic & persian decimal to valid decimal.\n     */\n    public static function replaceNumbers(string $string): string\n    {\n        $newNumbers = range(0, 9);\n\n        // 1. Persian HTML decimal\n        $persianDecimal = [\n            '&#1776;',\n            '&#1777;',\n            '&#1778;',\n            '&#1779;',\n            '&#1780;',\n            '&#1781;',\n            '&#1782;',\n            '&#1783;',\n            '&#1784;',\n            '&#1785;',\n        ];\n        // 2. Arabic HTML decimal\n        $arabicDecimal = [\n            '&#1632;',\n            '&#1633;',\n            '&#1634;',\n            '&#1635;',\n            '&#1636;',\n            '&#1637;',\n            '&#1638;',\n            '&#1639;',\n            '&#1640;',\n            '&#1641;',\n        ];\n        // 3. Arabic Numeric\n        $arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];\n        // 4. Persian Numeric\n        $persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];\n\n        $string = str_replace($persianDecimal, $newNumbers, $string);\n        $string = str_replace($arabicDecimal, $newNumbers, $string);\n        $string = str_replace($arabic, $newNumbers, $string);\n\n        return str_replace($persian, $newNumbers, $string);\n    }\n}\n"
  },
  {
    "path": "src/Transformers/MediaResource.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Transformers;\n\nuse Illuminate\\Http\\Resources\\Json\\JsonResource;\nuse Spatie\\MediaLibrary\\Conversions\\Conversion;\nuse Spatie\\MediaLibrary\\Conversions\\ConversionCollection;\n\nclass MediaResource extends JsonResource\n{\n    /**\n     * Transform the resource into an array.\n     *\n     * @param  \\Illuminate\\Http\\Request  $request\n     * @return array\n     */\n    public function toArray($request)\n    {\n        return [\n            'id' => $this->id,\n            'url' => $this->getFullUrl(),\n            'preview' => $this->getPreviewUrl(),\n            'name' => $this->name,\n            'file_name' => $this->file_name,\n            'type' => $this->getType(),\n            'mime_type' => $this->mime_type,\n            'size' => $this->size,\n            'human_readable_size' => $this->human_readable_size,\n            'details' => $this->mediaDetails(),\n            'status' => $this->mediaStatus(),\n            'progress' => $this->when($this->mediaStatus() == 'processing', $this->getCustomProperty('progress')),\n            'conversions' => $this->when(\n                ($this->isImage() || $this->isVideo()) && ! empty($this->getConversions()),\n                $this->getConversions()\n            ),\n            'links' => [\n                'delete' => [\n                    'href' => url('api/uploader/media/'.$this->getRouteKey()),\n                    'method' => 'DELETE',\n                ],\n            ],\n        ];\n    }\n\n    /**\n     * Get the generated conversions links.\n     *\n     * @return array\n     */\n    public function getConversions()\n    {\n        $results = [];\n\n        foreach (array_keys($this->getGeneratedConversions()->toArray()) as $conversionName) {\n            $conversion = ConversionCollection::createForMedia($this->resource)\n                ->first(fn (Conversion $conversion) => $conversion->getName() === $conversionName);\n\n            if ($conversion) {\n                $results[$conversionName] = $this->getFullUrl($conversionName);\n            }\n        }\n\n        return $results;\n    }\n\n    /**\n     * Determine if the media type is video.\n     *\n     * @return bool\n     */\n    public function isVideo()\n    {\n        return $this->getType() == 'video';\n    }\n\n    /**\n     * Determine if the media type is image.\n     *\n     * @return bool\n     */\n    public function isImage()\n    {\n        return $this->getType() == 'image';\n    }\n\n    /**\n     * Determine if the media type is audio.\n     *\n     * @return bool\n     */\n    public function isAudio()\n    {\n        return $this->getType() == 'audio';\n    }\n\n    /**\n     * Get the media type.\n     *\n     * @return mixed|string\n     */\n    public function getType()\n    {\n        return $this->getCustomProperty('type') ?: $this->type;\n    }\n\n    /**\n     * Get the preview url.\n     *\n     * @return string|void\n     */\n    public function getPreviewUrl()\n    {\n        if ($this->getType() == 'image') {\n            return $this->getFullUrl();\n        }\n\n        return 'https://cdn.jsdelivr.net/npm/laravel-file-uploader/dist/img/attach.png';\n    }\n\n    protected function mediaDetails(): array\n    {\n        $duration = (float) $this->getCustomProperty('duration');\n\n        return [\n            $this->mergeWhen($this->isImage(), [\n                'width' => $this->getCustomProperty('width'),\n                'height' => $this->getCustomProperty('height'),\n                'ratio' => (float) $this->getCustomProperty('ratio'),\n            ]),\n            'duration' => $this->when($this->isVideo() || $this->isAudio(), $duration),\n        ];\n    }\n\n    /**\n     * @return mixed\n     */\n    protected function mediaStatus()\n    {\n        return $this->getCustomProperty('status');\n    }\n}\n"
  },
  {
    "path": "tests/Feature/UploaderFeatureTest.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Tests\\Feature;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Tests\\Models\\Blog;\nuse AhmedAliraqi\\LaravelMediaUploader\\Tests\\TestCase;\nuse Illuminate\\Http\\UploadedFile;\nuse Illuminate\\Support\\Facades\\Storage;\n\nclass UploaderFeatureTest extends TestCase\n{\n    /** @test */\n    public function it_can_upload_and_display_temporary_files()\n    {\n        Storage::fake('public');\n\n        $response = $this->postJson(url('/api/uploader/media/upload'), [\n            'files' => [UploadedFile::fake()->image('thumbnail.jpg', 200)],\n            'collection' => 'images',\n        ]);\n\n        $response->assertSuccessful();\n\n        $response->assertJsonStructure([\n            'data' => [\n                [\n                    'id',\n                    'url',\n                    'name',\n                    'file_name',\n                    'type',\n                    'type',\n                    'mime_type',\n                    'size',\n                    'human_readable_size',\n                    'status',\n                    'links',\n                ],\n            ],\n        ]);\n\n        // Display recently uploaded files via token.\n\n        $response = $this->getJson(\n            url('/api/uploader/media').'?tokens[]='.$response->json('token')\n        );\n\n        $response->assertSuccessful();\n\n        $this->assertEquals(1, count($response->json('data')));\n    }\n\n    /** @test */\n    public function it_can_delete_uploaded_files()\n    {\n        Storage::fake('public');\n\n        /** @var Blog $blog */\n        $blog = Blog::create();\n\n        $blog->addMedia(\n            UploadedFile::fake()\n                ->create('thumbnail.jpg', 200)\n        )->toMediaCollection();\n\n        $this->assertEquals(1, $blog->getMedia()->count());\n\n        $this->deleteJson(url('/api/uploader/media/'.$blog->getFirstMedia()->id));\n\n        $blog->refresh();\n\n        $this->assertEquals(0, $blog->getMedia()->count());\n    }\n}\n"
  },
  {
    "path": "tests/Models/Blog.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Tests\\Models;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Entities\\Concerns\\HasUploader;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Spatie\\MediaLibrary\\HasMedia;\nuse Spatie\\MediaLibrary\\InteractsWithMedia;\n\nclass Blog extends Model implements HasMedia\n{\n    use HasUploader, InteractsWithMedia;\n\n    /**\n     * The table associated with the model.\n     *\n     * @var string\n     */\n    protected $table = 'blogs';\n\n    /**\n     * Define the media collections.\n     */\n    public function registerMediaCollections(): void\n    {\n        $this\n            ->addMediaCollection('default')\n            ->onlyKeepLatest(2);\n    }\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Tests;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Providers\\UploaderServiceProvider;\nuse Illuminate\\Console\\Application;\nuse Orchestra\\Testbench\\TestCase as OrchestraTestCase;\nuse Spatie\\MediaLibrary\\Conversions\\Commands\\RegenerateCommand;\n\nclass TestCase extends OrchestraTestCase\n{\n    /**\n     * Set up the test environment.\n     */\n    protected function setUp(): void\n    {\n        parent::setUp();\n\n        $this->loadLaravelMigrations(['--database' => 'testbench']);\n\n        $this->loadMigrationsFrom(__DIR__.'/database/migrations');\n\n        Application::starting(function ($artisan) {\n            $artisan->resolveCommands([\n                RegenerateCommand::class,\n            ]);\n        });\n    }\n\n    /**\n     * Load package service provider.\n     *\n     * @param  \\Illuminate\\Foundation\\Application  $app\n     * @return array\n     */\n    protected function getPackageProviders($app)\n    {\n        return [\n            UploaderServiceProvider::class,\n        ];\n    }\n\n    /**\n     * Define environment setup.\n     *\n     * @param  \\Illuminate\\Foundation\\Application  $app\n     * @return void\n     */\n    protected function getEnvironmentSetUp($app)\n    {\n        $app['config']->set('media-library', require __DIR__.'/config/media-library.php');\n        $app['config']->set('laravel-media-uploader', require __DIR__.'/config/laravel-media-uploader.php');\n        // Setup default database to use sqlite :memory:\n        $app['config']->set('database.default', 'testbench');\n        $app['config']->set('database.connections.testbench', [\n            'driver' => 'sqlite',\n            'database' => ':memory:',\n            'prefix' => '',\n        ]);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/UploaderUnitTest.php",
    "content": "<?php\n\nnamespace AhmedAliraqi\\LaravelMediaUploader\\Tests\\Unit;\n\nuse AhmedAliraqi\\LaravelMediaUploader\\Entities\\TemporaryFile;\nuse AhmedAliraqi\\LaravelMediaUploader\\Support\\Uploader;\nuse AhmedAliraqi\\LaravelMediaUploader\\Tests\\Models\\Blog;\nuse AhmedAliraqi\\LaravelMediaUploader\\Tests\\TestCase;\nuse Illuminate\\Http\\UploadedFile;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass UploaderUnitTest extends TestCase\n{\n    public function test_get_media_resource()\n    {\n        Storage::fake('public');\n\n        /** @var Blog $blog */\n        $blog = Blog::create();\n\n        $blog->addMedia(\n            UploadedFile::fake()\n                ->create('thumbnail.jpg', 200)\n        )->toMediaCollection();\n\n        $this->assertInstanceOf(Collection::class, $blog->getMediaResource());\n    }\n\n    public function test_add_all_media_from_token()\n    {\n        Storage::fake('public');\n\n        /** @var Blog $blog */\n        $blog = Blog::create();\n\n        $tmp = TemporaryFile::create([\n            'token' => 123,\n            'collection' => 'default',\n        ]);\n\n        $tmp->addMedia(\n            UploadedFile::fake()\n                ->image('thumbnail.jpg', 200)\n        )->toMediaCollection();\n\n        $media = $tmp->getFirstMedia('default');\n\n        $this->assertEquals($media->model_type, TemporaryFile::class);\n        $this->assertEquals($media->model_id, $tmp->id);\n\n        $blog->addAllMediaFromTokens([123], 'avatars');\n\n        $media->refresh();\n\n        $this->assertEquals($media->model_type, TemporaryFile::class);\n        $this->assertEquals($media->model_id, $tmp->id);\n\n        $blog->addAllMediaFromTokens([123]);\n\n        $media->refresh();\n\n        $this->assertEquals($media->model_type, Blog::class);\n        $this->assertEquals($media->model_id, $blog->id);\n    }\n\n    /** @test */\n    public function it_keep_only_configured_latest_media()\n    {\n        $blog = Blog::create();\n\n        $blog->addMedia(UploadedFile::fake()->image('thumbnail.jpg', 200))->toMediaCollection();\n\n        $this->assertCount(1, $blog->refresh()->getMedia());\n\n        $tmp = TemporaryFile::create(['token' => 123, 'collection' => 'default']);\n\n        $tmp->addMedia(UploadedFile::fake()->image('thumbnail.jpg', 200))->toMediaCollection();\n\n        $blog->addAllMediaFromTokens([123]);\n\n        $this->assertCount(2, $blog->refresh()->getMedia());\n\n        $tmp = TemporaryFile::create(['token' => 123, 'collection' => 'default']);\n\n        $tmp->addMedia(UploadedFile::fake()->image('thumbnail.jpg', 200))->toMediaCollection();\n        $tmp->addMedia(UploadedFile::fake()->image('thumbnail.jpg', 200))->toMediaCollection();\n\n        $blog->addAllMediaFromTokens([123]);\n\n        $this->assertCount(2, $blog->refresh()->getMedia());\n    }\n\n    public function test_uploader_helper()\n    {\n        $this->assertEquals(\n            Str::slug('صورة').'.jpg',\n            Uploader::formatName(UploadedFile::fake()->image('صورة.jpg', 200))\n        );\n\n        $this->assertEquals(\n            '123.jpg',\n            Uploader::formatName(UploadedFile::fake()->image('١٢٣.jpg', 200))\n        );\n    }\n}\n"
  },
  {
    "path": "tests/config/laravel-media-uploader.php",
    "content": "<?php\n\nreturn [\n    'documents_mime_types' => [\n        'application/msword',\n        'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .doc & .docx\n        'application/vnd.ms-powerpoint',\n        'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .ppt & .pptx\n        'application/vnd.ms-excel',\n        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xls & .xlsx\n        'text/plain',\n        'application/pdf',\n        'application/zip',\n        'application/x-rar',\n        'application/x-rar-compressed',\n        'application/octet-stream',\n    ],\n];\n"
  },
  {
    "path": "tests/config/media-library.php",
    "content": "<?php\n\nreturn [\n\n    /*\n     * The disk on which to store added files and derived images by default. Choose\n     * one or more of the disks you've configured in config/filesystems.php.\n     */\n    'disk_name' => env('MEDIA_DISK', 'public'),\n\n    /*\n     * The maximum file size of an item in bytes.\n     * Adding a larger file will result in an exception.\n     */\n    'max_file_size' => 1024 * 1024 * 10,\n\n    /*\n     * This queue will be used to generate derived and responsive images.\n     * Leave empty to use the default queue.\n     */\n    'queue_name' => '',\n\n    /*\n     * By default all conversions will be performed on a queue.\n     */\n    'queue_conversions_by_default' => env('QUEUE_CONVERSIONS_BY_DEFAULT', true),\n\n    /*\n     * The fully qualified class name of the media model.\n     */\n    'media_model' => Spatie\\MediaLibrary\\MediaCollections\\Models\\Media::class,\n\n    /*\n     * The fully qualified class name of the model used for temporary uploads.\n     *\n     * This model is only used in Media Library Pro (https://medialibrary.pro)\n     */\n    'temporary_upload_model' => Spatie\\MediaLibraryPro\\Models\\TemporaryUpload::class,\n\n    /*\n     * When enabled, Media Library Pro will only process temporary uploads there were uploaded\n     * in the same session. You can opt to disable this for stateless usage of\n     * the pro components.\n     */\n    'enable_temporary_uploads_session_affinity' => true,\n\n    /*\n     * When enabled, Media Library pro will generate thumbnails for uploaded file.\n     */\n    'generate_thumbnails_for_temporary_uploads' => true,\n\n    /*\n     * This is the class that is responsible for naming generated files.\n     */\n    'file_namer' => Spatie\\MediaLibrary\\Support\\FileNamer\\DefaultFileNamer::class,\n\n    /*\n     * The class that contains the strategy for determining a media file's path.\n     */\n    'path_generator' => Spatie\\MediaLibrary\\Support\\PathGenerator\\DefaultPathGenerator::class,\n\n    /*\n     * When urls to files get generated, this class will be called. Use the default\n     * if your files are stored locally above the site root or on s3.\n     */\n    'url_generator' => Spatie\\MediaLibrary\\Support\\UrlGenerator\\DefaultUrlGenerator::class,\n\n    /*\n     * Moves media on updating to keep path consistent. Enable it only with a custom\n     * PathGenerator that uses, for example, the media UUID.\n     */\n    'moves_media_on_update' => false,\n\n    /*\n     * Whether to activate versioning when urls to files get generated.\n     * When activated, this attaches a ?v=xx query string to the URL.\n     */\n    'version_urls' => false,\n\n    /*\n     * The media library will try to optimize all converted images by removing\n     * metadata and applying a little bit of compression. These are\n     * the optimizers that will be used by default.\n     */\n    'image_optimizers' => [\n        Spatie\\ImageOptimizer\\Optimizers\\Jpegoptim::class => [\n            '-m85', // set maximum quality to 85%\n            '--strip-all', // this strips out all text information such as comments and EXIF data\n            '--all-progressive', // this will make sure the resulting image is a progressive one\n        ],\n        Spatie\\ImageOptimizer\\Optimizers\\Pngquant::class => [\n            '--force', // required parameter for this package\n        ],\n        Spatie\\ImageOptimizer\\Optimizers\\Optipng::class => [\n            '-i0', // this will result in a non-interlaced, progressive scanned image\n            '-o2', // this set the optimization level to two (multiple IDAT compression trials)\n            '-quiet', // required parameter for this package\n        ],\n        Spatie\\ImageOptimizer\\Optimizers\\Svgo::class => [\n            '--disable=cleanupIDs', // disabling because it is known to cause troubles\n        ],\n        Spatie\\ImageOptimizer\\Optimizers\\Gifsicle::class => [\n            '-b', // required parameter for this package\n            '-O3', // this produces the slowest but best results\n        ],\n        Spatie\\ImageOptimizer\\Optimizers\\Cwebp::class => [\n            '-m 6', // for the slowest compression method in order to get the best compression.\n            '-pass 10', // for maximizing the amount of analysis pass.\n            '-mt', // multithreading for some speed improvements.\n            '-q 90', // quality factor that brings the least noticeable changes.\n        ],\n    ],\n\n    /*\n     * These generators will be used to create an image of media files.\n     */\n    'image_generators' => [\n        Spatie\\MediaLibrary\\Conversions\\ImageGenerators\\Image::class,\n        Spatie\\MediaLibrary\\Conversions\\ImageGenerators\\Webp::class,\n        Spatie\\MediaLibrary\\Conversions\\ImageGenerators\\Pdf::class,\n        Spatie\\MediaLibrary\\Conversions\\ImageGenerators\\Svg::class,\n        Spatie\\MediaLibrary\\Conversions\\ImageGenerators\\Video::class,\n    ],\n\n    /*\n     * The path where to store temporary files while performing image conversions.\n     * If set to null, storage_path('media-library/temp') will be used.\n     */\n    'temporary_directory_path' => null,\n\n    /*\n     * The engine that should perform the image conversions.\n     * Should be either `gd` or `imagick`.\n     */\n    'image_driver' => env('IMAGE_DRIVER', 'gd'),\n\n    /*\n     * FFMPEG & FFProbe binaries paths, only used if you try to generate video\n     * thumbnails and have installed the php-ffmpeg/php-ffmpeg composer\n     * dependency.\n     */\n    'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'),\n    'ffprobe_path' => env('FFPROBE_PATH', '/usr/bin/ffprobe'),\n\n    /*\n     * Here you can override the class names of the jobs used by this package. Make sure\n     * your custom jobs extend the ones provided by the package.\n     */\n    'jobs' => [\n        'perform_conversions' => Spatie\\MediaLibrary\\Conversions\\Jobs\\PerformConversionsJob::class,\n        'generate_responsive_images' => Spatie\\MediaLibrary\\ResponsiveImages\\Jobs\\GenerateResponsiveImagesJob::class,\n    ],\n\n    /*\n     * When using the addMediaFromUrl method you may want to replace the default downloader.\n     * This is particularly useful when the url of the image is behind a firewall and\n     * need to add additional flags, possibly using curl.\n     */\n    'media_downloader' => Spatie\\MediaLibrary\\Downloaders\\DefaultDownloader::class,\n\n    'remote' => [\n        /*\n         * Any extra headers that should be included when uploading media to\n         * a remote disk. Even though supported headers may vary between\n         * different drivers, a sensible default has been provided.\n         *\n         * Supported by S3: CacheControl, Expires, StorageClass,\n         * ServerSideEncryption, Metadata, ACL, ContentEncoding\n         */\n        'extra_headers' => [\n            'CacheControl' => 'max-age=604800',\n        ],\n    ],\n\n    'responsive_images' => [\n        /*\n         * This class is responsible for calculating the target widths of the responsive\n         * images. By default we optimize for filesize and create variations that each are 20%\n         * smaller than the previous one. More info in the documentation.\n         *\n         * https://docs.spatie.be/laravel-medialibrary/v9/advanced-usage/generating-responsive-images\n         */\n        'width_calculator' => Spatie\\MediaLibrary\\ResponsiveImages\\WidthCalculator\\FileSizeOptimizedWidthCalculator::class,\n\n        /*\n         * By default rendering media to a responsive image will add some javascript and a tiny placeholder.\n         * This ensures that the browser can already determine the correct layout.\n         */\n        'use_tiny_placeholders' => true,\n\n        /*\n         * This class will generate the tiny placeholder used for progressive image loading. By default\n         * the media library will use a tiny blurred jpg image.\n         */\n        'tiny_placeholder_generator' => Spatie\\MediaLibrary\\ResponsiveImages\\TinyPlaceholderGenerator\\Blurred::class,\n    ],\n\n    /*\n     * When enabling this option, a route will be registered that will enable\n     * the Media Library Pro Vue and React components to move uploaded files\n     * in a S3 bucket to their right place.\n     */\n    'enable_vapor_uploads' => env('ENABLE_MEDIA_LIBRARY_VAPOR_UPLOADS', false),\n\n    /*\n     * When converting Media instances to response the media library will add\n     * a `loading` attribute to the `img` tag. Here you can set the default\n     * value of that attribute.\n     *\n     * Possible values: 'lazy', 'eager', 'auto' or null if you don't want to set any loading instruction.\n     *\n     * More info: https://css-tricks.com/native-lazy-loading/\n     */\n    'default_loading_attribute_value' => null,\n];\n"
  },
  {
    "path": "tests/database/migrations/2020_06_03_131044_create_temporary_files_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateTemporaryFilesTable extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('temporary_files', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->string('token');\n            $table->string('collection')->default('default');\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('temporary_files');\n    }\n}\n"
  },
  {
    "path": "tests/database/migrations/2020_06_03_131049_create_blogs_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateBlogsTable extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('blogs', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::dropIfExists('blogs');\n    }\n}\n"
  },
  {
    "path": "tests/database/migrations/2020_06_26_194753_create_media_table.php",
    "content": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateMediaTable extends Migration\n{\n    /**\n     * Run the migrations.\n     */\n    public function up()\n    {\n        Schema::create('media', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->morphs('model');\n            $table->uuid('uuid')->nullable()->unique();\n            $table->string('collection_name');\n            $table->string('name');\n            $table->string('file_name');\n            $table->string('mime_type')->nullable();\n            $table->string('disk');\n            $table->string('conversions_disk')->nullable();\n            $table->unsignedBigInteger('size');\n            $table->json('manipulations');\n            $table->json('custom_properties');\n            $table->json('generated_conversions');\n            $table->json('responsive_images');\n            $table->unsignedInteger('order_column')->nullable();\n            $table->nullableTimestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     */\n    public function down()\n    {\n        Schema::dropIfExists('media');\n    }\n}\n"
  }
]