From d0294198fea22dc2634d10e37affa26a8d4e0ef2 Mon Sep 17 00:00:00 2001 From: abourtnik Date: Thu, 14 Dec 2023 19:37:33 +0100 Subject: [PATCH] feat: add YouTube service api --- README.md | 21 ++- app/Console/Commands/CreateUser.php | 3 +- app/Console/Commands/SyncComments.php | 131 ++++++++++++++++++ .../Commands/SyncVideosInteractions.php | 93 +++++++++++++ app/Http/Controllers/CommentController.php | 1 + app/Http/Controllers/UserController.php | 2 +- app/Providers/AppServiceProvider.php | 3 + app/Services/YoutubeService.php | 30 ++++ config/services.php | 3 + database/factories/UserFactory.php | 2 +- resources/views/components/layout.blade.php | 2 +- .../layouts/menus/sidebars/front.blade.php | 14 +- resources/views/users/show.blade.php | 3 +- resources/views/videos/show.blade.php | 1 + 14 files changed, 289 insertions(+), 20 deletions(-) create mode 100644 app/Console/Commands/SyncComments.php create mode 100644 app/Console/Commands/SyncVideosInteractions.php create mode 100644 app/Services/YoutubeService.php diff --git a/README.md b/README.md index 187f183..119e2fb 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,17 @@ -

- - ClipZone logo - -
- ClipZone -
-

- -

Open Source Youtube Clone

+ClipZone +===== -

Build Status + +Donate Paypal + + +Open Source Youtube Clone + +

+ ClipZone logo

## Technical detail diff --git a/app/Console/Commands/CreateUser.php b/app/Console/Commands/CreateUser.php index 4b232f6..6111a00 100644 --- a/app/Console/Commands/CreateUser.php +++ b/app/Console/Commands/CreateUser.php @@ -36,7 +36,8 @@ public function handle() : int 'avatar' => null, 'show_subscribers' => true, 'country' => null, - 'description' => null + 'description' => null, + 'website' => null ]); return Command::SUCCESS; diff --git a/app/Console/Commands/SyncComments.php b/app/Console/Commands/SyncComments.php new file mode 100644 index 0000000..c0bda2d --- /dev/null +++ b/app/Console/Commands/SyncComments.php @@ -0,0 +1,131 @@ + $id, 'youtubeId' => $youtubeId) = $this->arguments(); + + $video = Video::findOrFail($id); + + $video->comments->each->delete(); + + $data = $youtubeService->getComments($youtubeId); + + $this->saveComments($data['items'], $video, null); + + return Command::SUCCESS; + } + + private function saveComments (array $items, Video $video, ?Comment $parent) { + + $usedUsers = []; + + $count = count($items); + + $randomCount = rand($count - 5, $count); + + foreach ($items as $item) { + + $comment = $item['snippet']['topLevelComment']['snippet'] ?? $item['snippet']; + + $date = Carbon::create($comment['publishedAt']); + + $users = $this->getUsers([$video->user_id], $date)->diff($usedUsers); + + $userId = $users->random(); + + $usedUsers[] = $userId; + + $savedComment = Comment::withoutEvents(function () use ($video, $comment, $userId, $date, $parent) { + $data = [ + 'content' => $comment['textOriginal'], + 'ip' => '37.67.157.29', + 'user_id' => $userId, + 'created_at' => $date, + 'updated_at' => Carbon::create($comment['updatedAt']), + ]; + + if ($parent) { + $data['parent_id'] = $parent->id; + } + + return $video->comments()->create($data); + }); + + // Add Comment interaction + $this->generateInteraction($savedComment, $randomCount, $date); + $randomCount = rand($randomCount - 5, $randomCount - 1); + + $replies = $item['replies']['comments'] ?? []; + + if($replies) { + $this->saveComments($replies, $video, $savedComment); + } + } + + } + + private function getUsers (array $excludeIds, Carbon $createdBefore): Collection { + + return User::query() + ->active() + ->when($excludeIds, fn($q) => $q->whereNotIn('id', $excludeIds)) + ->where('created_at', '<', $createdBefore) + ->whereNotIn('id', [6, 7, 9, 10, 12, 14, 15, 16, 19, 20, 21, 23]) + ->inRandomOrder() + //->limit(5) + ->get() + ->pluck('id'); + } + + private function generateInteraction(Comment $comment, int $count, Carbon $afterDate) { + + $usedUsers = []; + + for ($i = $count; $i > 0; $i--) { + + $users = $this->getUsers([], $afterDate)->diff($usedUsers); + + $userId = $users->random(); + + $usedUsers[] = $userId; + + $comment->interactions()->create([ + 'user_id' => $userId, + 'status' => fake()->boolean(93), + 'perform_at' => fake()->dateTimeBetween($afterDate) + ]); + } + } +} diff --git a/app/Console/Commands/SyncVideosInteractions.php b/app/Console/Commands/SyncVideosInteractions.php new file mode 100644 index 0000000..575be55 --- /dev/null +++ b/app/Console/Commands/SyncVideosInteractions.php @@ -0,0 +1,93 @@ + $id, 'count' => $count) = $this->arguments(); + + $video = Video::findOrFail($id); + + $video->interactions()->delete(); + + $usedUsers = []; + + for ($i = $count; $i > 0; $i--) { + + $users = $this->getUsers([], $video->publication_date)->diff($usedUsers); + + $userId = $users->random(); + + $usedUsers[] = $userId; + + $video->interactions()->create([ + 'user_id' => $userId, + 'status' => fake()->boolean(93), + 'perform_at' => fake()->dateTimeBetween($video->publication_date) + ]); + } + + return Command::SUCCESS; + } + + private function getUsers (array $excludeIds, Carbon $createdBefore): Collection { + + return User::query() + ->active() + ->when($excludeIds, fn($q) => $q->whereNotIn('id', $excludeIds)) + ->where('created_at', '<', $createdBefore) + ->whereNotIn('id', [6, 7, 9, 10, 12, 14, 15, 16, 19, 20, 21, 23]) + ->inRandomOrder() + //->limit(5) + ->get() + ->pluck('id'); + } + + private function generateInteraction(Comment $comment, int $count, Carbon $afterDate) { + + $usedUsers = []; + + for ($i = $count; $i > 0; $i--) { + + $users = $this->getUsers([], $afterDate)->diff($usedUsers); + + $userId = $users->random(); + + $usedUsers[] = $userId; + + $comment->interactions()->create([ + 'user_id' => $userId, + 'status' => fake()->boolean(93), + 'perform_at' => fake()->dateTimeBetween($afterDate) + ]); + } + } +} diff --git a/app/Http/Controllers/CommentController.php b/app/Http/Controllers/CommentController.php index 6871203..9b51900 100644 --- a/app/Http/Controllers/CommentController.php +++ b/app/Http/Controllers/CommentController.php @@ -59,6 +59,7 @@ public function list(Request $request) : ResourceCollection { 'likes as liked_by_auth_user' => fn($q) => $q->where('user_id', Auth::id()), 'dislikes as disliked_by_auth_user' => fn($q) => $q->where('user_id', Auth::id()), ]) + ->orderByRaw('likes_count - dislikes_count DESC') ->latest(); }, 'reportByAuthUser' diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 6dff713..c6d0143 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -35,7 +35,7 @@ public function show (User $user) : View { ->limit(8) ]) ->active() - ->latest('created_at') + ->latest('updated_at') ->limit(6); }, 'pinned_video' => fn($q) => $q->withCount('views'), diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index af10ae1..f72656c 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -5,6 +5,7 @@ use App\Enums\ReportReason; use App\Http\Resources\NotificationResource; use App\Models\Category; +use App\Services\YoutubeService; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; @@ -30,6 +31,8 @@ class AppServiceProvider extends ServiceProvider public function register() : void { Cashier::ignoreMigrations(); + + $this->app->singleton(YoutubeService::class, fn() => new YoutubeService(config('services.youtube.api_key'))); } /** diff --git a/app/Services/YoutubeService.php b/app/Services/YoutubeService.php new file mode 100644 index 0000000..f960722 --- /dev/null +++ b/app/Services/YoutubeService.php @@ -0,0 +1,30 @@ +apiKey = $apiKey; + } + + public function getComments(string $videoID) : array|null + { + $response = Http::get(self::API_ENDPOINT. '/commentThreads', [ + 'key' => $this->apiKey, + 'part' => 'snippet,replies', + 'videoId' => $videoID, + 'order' => 'relevance', + 'maxResults' => 20 + ]); + + return $response->json(); + } +} diff --git a/config/services.php b/config/services.php index 14b42c3..0e91071 100644 --- a/config/services.php +++ b/config/services.php @@ -23,5 +23,8 @@ 'client_id' => env('FACEBOOK_CLIENT_ID'), 'client_secret' => env('FACEBOOK_CLIENT_SECRET'), 'redirect' => env('APP_URL') . '/oauth/callback/facebook', + ], + 'youtube' => [ + 'api_key' => env('YOUTUBE_API_KEY'), ] ]; diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 6e77a43..b19ce68 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -18,7 +18,7 @@ class UserFactory extends Factory */ public function definition() : array { - $date = fake()->dateTimeBetween('-1 year'); + $date = fake()->dateTimeBetween('-14 years'); return [ 'username' => fake()->unique()->userName(), diff --git a/resources/views/components/layout.blade.php b/resources/views/components/layout.blade.php index c5ca80f..8abe4d1 100644 --- a/resources/views/components/layout.blade.php +++ b/resources/views/components/layout.blade.php @@ -17,7 +17,7 @@ - + diff --git a/resources/views/layouts/menus/sidebars/front.blade.php b/resources/views/layouts/menus/sidebars/front.blade.php index b0c9663..dc9716e 100644 --- a/resources/views/layouts/menus/sidebars/front.blade.php +++ b/resources/views/layouts/menus/sidebars/front.blade.php @@ -155,10 +155,16 @@ Copyright © {{now()->format('Y')}} {{config('app.name')}} All Rights Reserved - - - Github - +
+ + + Github + + + + Donate + +
Anton Bourtnik diff --git a/resources/views/users/show.blade.php b/resources/views/users/show.blade.php index d882d45..597f00d 100644 --- a/resources/views/users/show.blade.php +++ b/resources/views/users/show.blade.php @@ -2,6 +2,7 @@ @section('title', $user->username) @section('description', Str::limit($user->description, 155)) +@section('image', asset($user->avatar_url)) @section('class', 'px-0') @section('style', 'margin-top: 0 !important') @@ -183,7 +184,7 @@ class="link-primary bg-transparent text-decoration-none d-flex align-items-cente @endif
- @if($user->playlists->count()) + @if($user->playlists_count)
@each('playlists.card', $user->playlists, 'playlist')
diff --git a/resources/views/videos/show.blade.php b/resources/views/videos/show.blade.php index 0f573f8..4fddb10 100644 --- a/resources/views/videos/show.blade.php +++ b/resources/views/videos/show.blade.php @@ -2,6 +2,7 @@ @section('title', $video->title) @section('description', Str::limit($video->description, 155)) +@section('image', $video->thumbnail_url) @section('class', 'mt-0 mt-lg-3 ms-0')