It's me ;-)

Youtube player frame

Mấy sprint trước mình có nhận 1 task đại khái là cho phép người dùng paste Youtube link (share link, embedded link, shorten link) và hệ thống sẽ tự động lấy thumbnail của Video để hiển thị dạng player frame trong bài viết.

Check qua thì Youtube chỉ hỗ trợ lấy ảnh thumbnail chứ không có cả player frame.

Để lấy ảnh thumbnail thì thậm chí còn không cần phải dùng API để lấy, nó hỗ trợ sẵn theo syntax sau: https://img.youtube.com/vi/<video_id>/<size>.jpg

Trong đó thì size có 2 dạng là số nguyên dương và chuỗi, cụ thể như bảng bên dưới:

Như vậy với bài toán của mình thì lấy luôn ảnh 0.jpg là đơn giản nhất. Chỉ cần làm sao bóc được ID trong URL mà người dùng paste xong cộng thêm chuỗi URL như Youtube định nghĩa là được.

Vậy làm sao để có ảnh thumbnail trong cái player control khi mà Youtube không hỗ trợ? Chẳng còn cách nào phải chơi fake cả =))

Ý tưởng ở đây là sẽ capture 1 cái player control của Youtube, sau đó xóa nền toàn bộ video đi, chỉ để lại cái player thôi:

Youtube player frame

Tiếp đó lấy ảnh thumbnail của Video, ví dụ: https://www.youtube.com/watch?v=-tq_2QHGhqo

Thì video ID sẽ là -tq_2QHGhqo, và URL để lấy ảnh thumbnail sẽ là: https://img.youtube.com/vi/-tq_2QHGhqo/0.jpg

Ảnh thumbnail mặc định

OK kool, vậy giờ làm sao để ghép giữa ảnh thumbnail và ảnh player frame kia thành một? Có rất nhiều cách, nhưng trong trường hợp của mình thì mình dùng luôn package Intervention Image cho Laravel

// Backend - create Youtube player frame
$fileName = sprintf('campaigns/videos/%s/%s.jpg', $user->id, md5(time() . $user->id) . $request->video_id);
$frame = storage_path('campaigns/youtube-player-frame-480x360.png');
                
$thumbnail = Image::make(file_get_contents("https://img.youtube.com/vi/{$request->video_id}/0.jpg"))
            ->insert($frame)
            ->stream('jpg', 100);

$isUploaded = Storage::disk('s3-assets')->put($fileName, $thumbnail);

if ($isUploaded) {
  $url = Storage::disk('s3-assets')->url($fileName);
  return $this->response->array(['url' => $url]);
}

Tada, work like a charm luôn 🙂

Ảnh sau khi ghép player frame + ảnh thumbnail

Bonus thêm đoạn code để lấy ID của video, hỗ trợ các link dạng:

  • bình thường
  • link rút gọn
  • link nhúng
let videoId = '';
const url = video_url.replace(/(>|<)/gi, '').split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/);

if (url[2] !== undefined) {
  videoId = url[2].split(/[^0-9a-z_\-]/i);
  videoId = videoId[0];
}

Update: Mình có bán source code trên dưới dạng pure PHP để chạy standalone, hỗ trợ chạy cả command line tại https://www.codester.com/items/29058/generate-youtube-thumbnail-with-player-frame với giá 7$ nha mọi người 😘

Leave a Reply

Your email address will not be published. Required fields are marked *