Browse Source

Add /api/v1/media endpoint

Daniel Supernault 5 năm trước cách đây
mục cha
commit
39f3e3138d

+ 93 - 4
app/Http/Controllers/Api/ApiV1Controller.php

@@ -6,11 +6,8 @@ use Illuminate\Http\Request;
 use App\Http\Controllers\Controller;
 use App\Http\Controllers\Controller;
 use Illuminate\Support\Str;
 use Illuminate\Support\Str;
 use App\Util\ActivityPub\Helpers;
 use App\Util\ActivityPub\Helpers;
-use App\Jobs\LikePipeline\LikePipeline;
-use App\Jobs\StatusPipeline\StatusDelete;
-use App\Jobs\FollowPipeline\FollowPipeline;
 use Laravel\Passport\Passport;
 use Laravel\Passport\Passport;
-use Auth, Cache, DB;
+use Auth, Cache, DB, URL;
 use App\{
 use App\{
     Follower,
     Follower,
     FollowRequest,
     FollowRequest,
@@ -24,6 +21,7 @@ use App\{
 use League\Fractal;
 use League\Fractal;
 use App\Transformer\Api\{
 use App\Transformer\Api\{
     AccountTransformer,
     AccountTransformer,
+    MediaTransformer,
     RelationshipTransformer,
     RelationshipTransformer,
     StatusTransformer,
     StatusTransformer,
 };
 };
@@ -31,6 +29,16 @@ use App\Http\Controllers\FollowerController;
 use League\Fractal\Serializer\ArraySerializer;
 use League\Fractal\Serializer\ArraySerializer;
 use League\Fractal\Pagination\IlluminatePaginatorAdapter;
 use League\Fractal\Pagination\IlluminatePaginatorAdapter;
 
 
+use App\Jobs\LikePipeline\LikePipeline;
+use App\Jobs\StatusPipeline\StatusDelete;
+use App\Jobs\FollowPipeline\FollowPipeline;
+use App\Jobs\ImageOptimizePipeline\ImageOptimize;
+use App\Jobs\VideoPipeline\{
+    VideoOptimize,
+    VideoPostProcess,
+    VideoThumbnail
+};
+
 use App\Services\NotificationService;
 use App\Services\NotificationService;
 
 
 class ApiV1Controller extends Controller 
 class ApiV1Controller extends Controller 
@@ -873,6 +881,87 @@ class ApiV1Controller extends Controller
         return response()->json([]);        
         return response()->json([]);        
     }
     }
 
 
+    /**
+     * POST /api/v1/media
+     *
+     *
+     * @return App\Transformer\Api\MediaTransformer
+     */
+    public function mediaUpload(Request $request)
+    {
+        abort_if(!$request->user(), 403);
+
+        $this->validate($request, [
+          'file.*'      => function() {
+            return [
+                'required',
+                'mimes:' . config('pixelfed.media_types'),
+                'max:' . config('pixelfed.max_photo_size'),
+            ];
+          },
+          'filter_name' => 'nullable|string|max:24',
+          'filter_class' => 'nullable|alpha_dash|max:24'
+        ]);
+
+        $user = $request->user();
+        $profile = $user->profile;
+
+        if(config('pixelfed.enforce_account_limit') == true) {
+            $size = Cache::remember($user->storageUsedKey(), now()->addDays(3), function() use($user) {
+                return Media::whereUserId($user->id)->sum('size') / 1000;
+            }); 
+            $limit = (int) config('pixelfed.max_account_size');
+            if ($size >= $limit) {
+               abort(403, 'Account size limit reached.');
+            }
+        }
+
+        $monthHash = hash('sha1', date('Y').date('m'));
+        $userHash = hash('sha1', $user->id . (string) $user->created_at);
+
+        $photo = $request->file('file');
+
+        $mimes = explode(',', config('pixelfed.media_types'));
+        if(in_array($photo->getMimeType(), $mimes) == false) {
+            abort(403, 'Invalid or unsupported mime type.');
+        }
+
+        $storagePath = "public/m/{$monthHash}/{$userHash}";
+        $path = $photo->store($storagePath);
+        $hash = \hash_file('sha256', $photo);
+
+        $media = new Media();
+        $media->status_id = null;
+        $media->profile_id = $profile->id;
+        $media->user_id = $user->id;
+        $media->media_path = $path;
+        $media->original_sha256 = $hash;
+        $media->size = $photo->getSize();
+        $media->mime = $photo->getMimeType();
+        $media->filter_class = $request->input('filter_class');
+        $media->filter_name = $request->input('filter_name');
+        $media->save();
+        
+        switch ($media->mime) {
+            case 'image/jpeg':
+            case 'image/png':
+                ImageOptimize::dispatch($media);
+                break;
+
+            case 'video/mp4':
+                VideoThumbnail::dispatch($media);
+                $preview_url = '/storage/no-preview.png';
+                $url = '/storage/no-preview.png';
+                break;
+        }
+
+        $resource = new Fractal\Resource\Item($media, new MediaTransformer());
+        $res = $this->fractal->createData($resource)->toArray();
+        $res['preview_url'] = url('/storage/no-preview.png');
+        $res['url'] = url('/storage/no-preview.png');
+        return response()->json($res);
+    }
+
     public function statusById(Request $request, $id)
     public function statusById(Request $request, $id)
     {
     {
         $status = Status::whereVisibility('public')->findOrFail($id);
         $status = Status::whereVisibility('public')->findOrFail($id);

+ 8 - 7
routes/web.php

@@ -110,14 +110,15 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
             Route::get('lists', 'Api\ApiV1Controller@accountLists')->middleware('auth:api');
             Route::get('lists', 'Api\ApiV1Controller@accountLists')->middleware('auth:api');
             Route::get('accounts/{id}/lists', 'Api\ApiV1Controller@accountListsById')->middleware('auth:api');
             Route::get('accounts/{id}/lists', 'Api\ApiV1Controller@accountListsById')->middleware('auth:api');
             Route::get('lists/{id}/accounts', 'Api\ApiV1Controller@accountListsById')->middleware('auth:api');
             Route::get('lists/{id}/accounts', 'Api\ApiV1Controller@accountListsById')->middleware('auth:api');
+            Route::post('media', 'Api\ApiV1Controller@mediaUpload')->middleware('auth:api');
 
 
-            Route::get('likes', 'ApiController@hydrateLikes');
-            Route::post('media', 'ApiController@uploadMedia')->middleware('auth:api');
-            Route::delete('media', 'ApiController@deleteMedia')->middleware('auth:api');
-            Route::get('notifications', 'ApiController@notifications')->middleware('auth:api');
-            Route::get('timelines/public', 'PublicApiController@publicTimelineApi');
-            Route::get('timelines/home', 'PublicApiController@homeTimelineApi')->middleware('auth:api');
-            Route::post('status', 'Api\ApiV1Controller@createStatus')->middleware('auth:api');
+            // Route::get('likes', 'ApiController@hydrateLikes');
+            // Route::post('media', 'ApiController@uploadMedia')->middleware('auth:api');
+            // Route::delete('media', 'ApiController@deleteMedia')->middleware('auth:api');
+            // Route::get('notifications', 'ApiController@notifications')->middleware('auth:api');
+            // Route::get('timelines/public', 'PublicApiController@publicTimelineApi');
+            // Route::get('timelines/home', 'PublicApiController@homeTimelineApi')->middleware('auth:api');
+            // Route::post('status', 'Api\ApiV1Controller@createStatus')->middleware('auth:api');
         });
         });
         Route::group(['prefix' => 'v2'], function() {
         Route::group(['prefix' => 'v2'], function() {
             Route::get('config', 'ApiController@siteConfiguration');
             Route::get('config', 'ApiController@siteConfiguration');