Skip to content

Commit

Permalink
feat + fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
abourtnik committed Dec 21, 2023
1 parent c0b4e7a commit 216ecb4
Show file tree
Hide file tree
Showing 38 changed files with 463 additions and 228 deletions.
117 changes: 99 additions & 18 deletions app/Console/Commands/SyncComments.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,59 @@
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class SyncComments extends Command
{

private YoutubeService $youtubeService;

public function __construct(YoutubeService $youtubeService)
{
parent::__construct();
$this->youtubeService = $youtubeService;
}

/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'comments:sync {id : ClipZone video id} {youtubeId : Youtube video id}';
protected $signature = 'comments:sync';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Get comments from Youtube for specific video';
protected $description = 'Synchronize comments from Youtube';

/**
* Execute the console command.
*
* @param YoutubeService $youtubeService
* @return int
*/
public function handle(YoutubeService $youtubeService) : int
public function handle() : int
{
list('id' => $id, 'youtubeId' => $youtubeId) = $this->arguments();
$videos = Video::whereNotNull('youtube_id')->get();

$video = Video::findOrFail($id);
foreach ($videos as $video) {

$video->comments->each->delete();
$this->info('Sync comments for video : ' .$video->title. ' ...');

$data = $youtubeService->getComments($youtubeId);
$video->comments->each->delete();

$this->saveComments($data['items'], $video, null);
$data = $this->youtubeService->getComments($video->youtube_id);

$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);
Expand All @@ -61,11 +72,13 @@ private function saveComments (array $items, Video $video, ?Comment $parent) {

$date = Carbon::create($comment['publishedAt']);

$users = $this->getUsers([$video->user_id], $date)->diff($usedUsers);

$userId = $users->random();

$usedUsers[] = $userId;
// Author of video is author of comment
if ($comment['channelId'] === $comment['authorChannelId']['value']) {
$userId = $video->user_id;
} else {
$user = $this->importUser($comment['authorChannelId']['value']);
$userId = $user->id;
}

$savedComment = Comment::withoutEvents(function () use ($video, $comment, $userId, $date, $parent) {
$data = [
Expand All @@ -85,7 +98,7 @@ private function saveComments (array $items, Video $video, ?Comment $parent) {

// Add Comment interaction
$this->generateInteraction($savedComment, $randomCount, $date);
$randomCount = rand($randomCount - 5, $randomCount - 1);
$randomCount = $randomCount - rand(1, 5);

$replies = $item['replies']['comments'] ?? [];

Expand Down Expand Up @@ -123,9 +136,77 @@ private function generateInteraction(Comment $comment, int $count, Carbon $after

$comment->interactions()->create([
'user_id' => $userId,
'status' => fake()->boolean(93),
'status' => fake()->boolean(96),
'perform_at' => fake()->dateTimeBetween($afterDate)
]);
}
}

private function importUser (string $youtubeChannelId) : User {

$this->info($youtubeChannelId);

$data = $this->youtubeService->getChannelInfo($youtubeChannelId);

$channel = $data['items'][0]['snippet'];

$user = User::where('username' , $channel['title'])->first();

if ($user) {
$user->update([
'description' => $channel['description'] ?: null,
'created_at' => Carbon::create($channel['publishedAt']),
'country' => $channel['country'] ?? null,
]);

return $user;

} else {

// Save avatar

try {
$contentAvatar = file_get_contents($channel['thumbnails']['medium']['url']);
}
catch (\Exception $e){
$this->info('error get avatar : '. $e->getMessage());
}

if ($contentAvatar ?? null) {
$avatarName = Str::random(40) . '.jpg';
Storage::put(User::AVATAR_FOLDER . '/' . $avatarName, $contentAvatar);
}

// Save Banner
if ($data['items'][0]['brandingSettings']['image']['bannerExternalUrl'] ?? null) {

$url = $data['items'][0]['brandingSettings']['image']['bannerExternalUrl'] . '=w2120-fcrop64=1,00005a57ffffa5a8-k-c0xffffffff-no-nd-rj';

try {
$contentBanner = file_get_contents($url);
}
catch (\Exception $e){
$this->info('error get banner : '. $e->getMessage());
}

if ($contentBanner ?? null) {
$bannerName = Str::random(40) . '.jpg';
Storage::put(User::BANNER_FOLDER . '/' .$bannerName, $contentBanner);
}
}

return User::create([
'username' => $channel['title'],
'email' => fake()->unique()->safeEmail(),
'password' => Str::random(),
'email_verified_at' => Carbon::create($channel['publishedAt'])->addSeconds(rand(10, 300)),
'avatar' => $avatarName ?? null,
'banner' => $bannerName ?? null,
'description' => $channel['description'] ?: null,
'country' => $channel['country'] ?? null,
'show_subscribers' => true,
'created_at' => Carbon::create($channel['publishedAt']),
]);
}
}
}
53 changes: 53 additions & 0 deletions app/Helpers/Parser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace App\Helpers;

class Parser
{
const PARSERS = [
'links' => 'parseLinks',
'timecodes' => 'parseTimeCodes',
];

public static function applyParsers(string $string, array $parsers): string|null {

$result = htmlspecialchars($string);

foreach ($parsers as $parser) {

if (!in_array($parser, array_keys(self::PARSERS))) {
throw new \Exception('Invalid parser :'. $parser);
}

$method = self::PARSERS[$parser];

$result = self::$method($result);
}

return $result;
}

private static function parseLinks(string $string): string|null {

$regex = '/(https?:\/\/)?([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/\S*)?)/m';

return preg_replace($regex, '<a class="text-decoration-none" href="//${2}" target="_blank" title="$0" rel="external nofollow">$0</a>', $string);
}

private static function parseTimeCodes(string $string): string|null
{
$regex = '/(\d{1,2}:){1,2}\d{2}/m';

return preg_replace_callback($regex, function ($matches) {

$times = array_reverse(explode(':', $matches[0]));

$timecode = array_reduce(array_keys($times), function($carry, $index) use ($times) {
return $carry + $times[$index] * pow(60, $index);
} , 0);

return "<button onclick='time($timecode)' class='btn btn-link btn-sm p-0 text-decoration-none' data-timecode='$timecode'>{$matches[0]}</button>";

}, $string);
}
}
23 changes: 15 additions & 8 deletions app/Http/Controllers/CommentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

class CommentController extends Controller
{
const REPLIES_PER_PAGE = 10;

public function __construct()
{
//$this->authorizeResource(Comment::class, 'comment');
Expand Down Expand Up @@ -60,21 +62,23 @@ public function list(Request $request) : ResourceCollection {
'dislikes as disliked_by_auth_user' => fn($q) => $q->where('user_id', Auth::id()),
])
->orderByRaw('likes_count - dislikes_count DESC')
->latest();
->latest()
->limit(self::REPLIES_PER_PAGE);
},
'reportByAuthUser'
])
->withCount([
'replies as total_replies' => fn($q) => $q->public(),
'likes',
'dislikes',
'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()),
'replies as author_replies' => fn ($query) => $query->where('user_id', $video->user->id),
])
->when($video->pinned_comment, fn($query) => $query->orderByRaw('id <> ' .$video->pinned_comment->id))
->when($sort === 'top', fn($query) => $query->orderByRaw('likes_count - dislikes_count DESC')->latest())
->when($sort === 'newest', fn($query) => $query->latest())
->paginate(24)
->when($sort === 'top', fn($query) => $query->orderByRaw('likes_count - dislikes_count DESC'))
->latest()
->simplePaginate(20)
->withQueryString()
))->additional([
'count' => $video->comments_count,
Expand All @@ -92,7 +96,8 @@ public function replies (Comment $comment, Request $request) : ResourceCollectio
->with([
'user',
'video' => fn($q) => $q->with('user'),
'replies'
'replies',
'reportByAuthUser'
])
->withCount([
'likes',
Expand All @@ -101,10 +106,12 @@ public function replies (Comment $comment, Request $request) : ResourceCollectio
'dislikes as disliked_by_auth_user' => fn($q) => $q->where('user_id', Auth::id())
])
->when($sort === 'top', fn($query) => $query->orderByRaw('likes_count - dislikes_count DESC'))
->when($sort === 'recent', fn($query) => $query->latest())
->paginate(12)
->latest()
->simplePaginate(self::REPLIES_PER_PAGE)
->withQueryString()
));
))->additional([
'count' => $comment->replies_count,
]);

}

Expand Down
9 changes: 6 additions & 3 deletions app/Http/Controllers/SearchController.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ public function index(Request $request, SearchFilters $filters): View

$videos = in_array($type, ['videos', null]) ? Video::active()
->filter($filters)
->where(function($query) use ($match) {
$query->where('title', 'LIKE', $match)->orWhere('description', 'LIKE', $match);
})
->where(
fn($query) => $query
->where('title', 'LIKE', $match)
->orWhere('description', 'LIKE', $match)
->orWhereRelation('user', 'username', 'LIKE', $match)
)
->with('user')
->latest('publication_date')
->withCount('views')
Expand Down
14 changes: 12 additions & 2 deletions app/Http/Resources/CommentResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function toArray($request) : array
'id' => $this->id,
'class' => Comment::class,
'content' => $this->content,
'parsed_content' => $this->parsed_content,
'short_content' => $this->short_content,
'is_long' => $this->is_long,
'user' => [
Expand All @@ -37,7 +38,6 @@ public function toArray($request) : array
],
'created_at' => $this->created_at->diffForHumans(),
'is_updated' => $this->is_updated,
'model' => Comment::class,
'likes_count' => $this->likes_count,
'dislikes_count' => $this->dislikes_count,
'liked_by_auth_user' => $this->liked_by_auth_user > 0,
Expand All @@ -46,7 +46,17 @@ public function toArray($request) : array
'can_update' => Auth::user()?->can('update', $this->resource) ?? false,
'can_report' => Auth::user()?->can('report', $this->resource) ?? false,
'can_pin' => Auth::user()?->can('pin', $this->resource) ?? false,
'replies' => CommentResource::collection($this->replies),
'replies' => $this->when($this->total_replies > 0, function () {
return [
'data' => CommentResource::collection($this->replies),
'links' => [
'next' => $this->replies->count() < $this->total_replies ? route('comments.replies', ['comment' => $this->resource , 'page' => 2]) : null,
],
'meta' => [
'total' => $this->total_replies
]
];
}),
'is_pinned' => $this->is_pinned,
'is_reply' => $this->is_reply,
'is_author_reply' => $this->when(!$this->is_reply, fn() => $this->author_replies > 0),
Expand Down
Loading

0 comments on commit 216ecb4

Please sign in to comment.