Lecture 54 - Clean YouTube Project | Custom Hook and API Call

Lecture 54 - Clean YouTube Project | Custom Hook and API Call

Introduction

আগের ব্লগে আমরা MUI নিয়ে আলোচনা করেছিলাম। এই ব্লগে আমরা একটা ছোটখাট প্রজেক্ট বানাবো। পুরোপুরি ফ্রন্টএন্ড ফোকাসড। কোনো ব্যাকএন্ড থাকবে না। তবে ইউটিউবের এপিআই থাকবে। আর MUI ব্যবহার করে আমরা লেআউট বানাবো।

Project Idea

আমাদের এই প্রজেক্টের নাম হলো Clean Youtube। আমরা যখন কোনো কোর্স সাইটে যাই, তখন একটা কোর্স যখন দেখতে থাকি, তখন অন্য কিছু এসে আমাদের ডিসট্র্যাক্ট করে না। যেটা ইউটিউবে গেলে হয়। আমরা দেখতে গেলাম একটা প্লেলিস্ট, কিন্তু পাশে রিকমেন্ডেড ভিডিও দেখে সেটাতে ক্লিক করে সেটা দেখতে লাগলাম। এরপর একটার পর একটা দেখতে দেখতে আমরা যা দেখছিলাম সেটা আর দেখা হয়ে উঠে না, শেখাও হয়ে উঠে না। কিন্তু যদি এমন একটা অ্যাপ্লিকেশন আমাদের থাকে যেখানে আমরা আমাদের পছন্দের প্লেলিস্টের লিংক বা আইডি পেস্ট করলাম। সেটা কোনো ডিস্ট্র্যাকশন ছাড়াই আমরা দেখতে পারবো কোর্সসাইট ওয়েতে। আমরা প্লেলিস্ট সেইভ করে রাখতে পারবো, ফেভারিট প্লেলিস্ট করে রাখতে পারবো। এবং আমি সর্বশেষ কোন প্লেলিস্ট দেখছিলাম সেটাও দেখতে পারবো। এটার জন্য আমরা ব্যবহার করবো ইউটিউবের এপিআই, UI এর জন্য MUI এবং ডাটা সেইভ করে রাখার জন্য লোকালস্টোরেজ, এবং ন্যাভিগেশনের জন্য React-Router (যেটা আমরা এই প্রজেক্ট করতে করতে শিখবো)।

Tasks

  • Functionalities

  • Component tree

  • API integration

  • Make the UI

  • Add the functionalities

Functionalities

  • Show an alert to enter a playlist id

  • Check if the id is already in cache

  • Fetch the YouTube API and make a cache for the results

  • Add refresh button to refresh the cache

আমরা প্রথমে একটা অ্যালার্ট দিবো প্লেলিস্ট আইডি বা লিংক দেয়ার জন্য। দেয়ার পর সেটা চেক করে দেখবে ক্যাশে অলরেডি সেই প্লেলিস্ট আছে কিনা। যদি না থাকে তাহলে এপিআই কল হয়ে ফেচ করে নিবে এবং ক্যাশ করে রাখবে। আর যদি থাকে তাহলে এপিআই কল হবে না। কারণ যেহেতু আমরা ইউটিউবের ফ্রি সার্ভিস ব্যবহার করছি আমার দিনে লিমিট হচ্ছে ১০হাজার ইউনিট পর্যন্ত। এখন আমি যদি একটা প্লেলিস্ট একাধিকবার ফেচ করে আনি তাহলে আমার কোটা তাড়াতাড়ি খরচ হয়ে যাবে। অন্য কেউ আর তা ব্যবহার করতে পারবে না। আবার একটা প্লেলিস্টে একদিন ৫টা ভিডিও থাকতে পারে আবার পরেরদিন সেটা ৭টা হতে পারে। সেক্ষেত্রে আমাদের একটা রিফ্রেশ বাটন রাখতে হবে ক্যাশ রিফ্রেশ করার জন্য। অবশ্যই সেটা লিমিটেড সময়ের জন্য, হতে পারে ২৪ ঘন্টায় একবার অ্যাক্টিভ হলো। কারণ বারবার রিফ্রেশ হলে আমার কোটা তাড়াতাড়ি কনজিউম হয়ে যাবে। সেক্ষেত্রে অ্যাপ্লিকেশন আর ব্যবহার করা যাবে না। মোটামুটি আমাদের ফাংশনালিটিজ এতটুকুই।

Component tree

API

আমরা প্রথমে এপিআই নিয়ে কাজ করবো। এর জন্য প্রথমে আপনাদের Google Developer Console এ গিয়ে লগইন করতে হবে এবং একটা প্রজেক্ট ক্রিয়েট করে সেখানে কি কি এপিআই ব্যবহার করবেন তা সিলেক্ট করে দিতে পারেন। এই প্রজেক্টের জন্য আমরা ব্যবহার করবো Youtube Data API v3। সেখানে ক্লিক করে credentials এ গিয়ে একটা এপিআই কী তৈরি করে নিবেন। এরপর আপনাদের যেতে হবে Youtube Data API তে। সেখানে গিয়ে Reference এ ক্লিক করলে আপনারা অনেক অপশন দেখতে পাবেন। আমাদের দরকার playlistItem এপিআই। সেখানে ওভারভিউতে গেলে আপনারা এটা সম্পর্কে সম্পূর্ণ ডিটেইলস দেখতে পাবেন। আমাদের মূলত দরকার list মেথড। আমরা সেখানে গেলে দেখতে পাবো পাশে Try this method নামে একটা সাইডবার ওপেন হয়েছে। সেখানে আমরা বিভিন্নভাবে এপিআই কিভাবে কাজ করে না করে সেটা দেখতে পারবো। সেটা আর এখানে লিখলাম না। ভিডিওতে দেখানো হয়েছে।

এবার আমরা প্রজেক্ট ক্রিয়েট করবো vite দিয়ে। এরপর /src/api/index.js নামে একটি ফাইল ক্রিয়েট করবো। এরপর axios ইনস্টল করে নিবো। এরপর আমরা নিচের কোডটি লিখবো।

import axios from 'axios';

const key = 'YOUR_API_KEY';

const getPlaylist = async (playlistID, pageToken = '', result = []) => {
    const URL = `https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet%2CcontentDetails&maxResults=50&playlistId=${playlistID}&key=${key}&pageToken=${pageToken}`;

    const { data } = await axios.get(URL);
    result = [...result, ...data.items];
    if (data.nextPageToken) {
        result = getPlaylist(playlistID, data.nextPageToken, result);
    }
    return result;
};

export default getPlaylist;

আমাদের URL এ তিনটা জিনিস লাগবে। key, playlistId এবং pageToken। আমরা কী পাবো যে কী জেনারেট করে নিয়েছিলাম সেটা। playlistId হবে যে প্লেলিস্ট দেখতে চাইছি তার আইডি। আর pageToken হবে ফেচ করার পর যে ডাটা পাবো তার মধ্যকার nextPageToken। কারণ একসাথে ৫০টার বেশি ভিডিও শো করে না। যাতে সব ভিডিও একসাথে পাই তার জন্য আমাদের একটা রিকার্সিভ ফাংশন জেনারেট করতে হবে। যতক্ষণ নেক্সট পেইজ টোকেন পাওয়া যাবে ততক্ষণ getPlaylist ফাংশন কল হতে থাকবে। আর টোকেন পাওয়া না গেলে রেজাল্ট রিটার্ন করে দিবে।

usePlaylists Hook

এবার আমরা usePlaylists নামে একটি হুক ক্রিয়েট করবো। আমরা /src/hooks/usePlaylists/index.js এ গিয়ে নিচের হুকটি ক্রিয়েট করবো।

import { useState } from 'react';
import getPlaylist from '../api';

const usePlaylists = () => {
    const [state, setState] = useState({
        playlists: {},
        recentPlaylists: [],
        favorites: [],
    });

    const getPlaylistById = async (playlistId, force = false) => {
        if (state.playlists[playlistId] && !force) {
            return;
        }

        let result = await getPlaylist(playlistId);

        let cid, ct;

        result = result.map((item) => {
            const {
                channelId,
                title,
                description,
                thumbnails: { medium },
                channelTitle,
            } = item.snippet;

            if (!cid) {
                cid = channelId;
            }

            if (!ct) {
                ct = channelTitle;
            }

            return {
                title,
                description,
                thumbnail: medium,
                contentDetails: item.contentDetails,
            };
        });

        setState((prev) => ({
            ...prev,
            playlists: {
                ...prev.playlists,
                [playlistId]: {
                    items: result,
                    playlistId: playlistId,
                    channelId: cid,
                    channelTitle: ct,
                },
            },
        }));
    };

    const addToFavorites = (playlistId) => {
        setState((prev) => ({
            ...prev,
            favorites: [...prev, playlistId],
        }));
    };

    const addToRecent = (playlistId) => {
        setState((prev) => ({
            ...prev,
            recentPlaylists: [...prev, playlistId],
        }));
    };

    const getPlaylistsByIds = (ids = []) => {
        return ids.map((id) => state.playlists[id]);
    };

    return {
        playlists: state.playlists,
        favorites: getPlaylistsByIds(state.favorites),
        recentPlaylists: getPlaylistsByIds(state.recentPlaylists),
        getPlaylistById,
        addToRecent,
        addToFavorites,
    };
};

export default usePlaylists;

এখানে আমরা playlists নামক অবজেক্ট, favorites, recentPlaylists নামক অ্যারে রিটার্ন করলাম। সেই সাথে আইডি দিয়ে প্লেলিস্ট পাওয়ার জন্য আমরা getPlaylistById ফাংশন, রিসেন্ট প্লেলিস্ট পাওয়ার জন্য addToRecent ফাংশন, ফেভারিট প্লেলিস্ট অ্যাড করার জন্য addToFavorites ফাংশন ক্রিয়েট করলাম।

এরপর App.jsx এ গিয়ে নিচের কোড লিখবো।

import { useEffect } from 'react';
import usePlaylists from './hooks/usePlaylists';

const App = () => {
    const { getPlaylistById, playlists } = usePlaylists();

    useEffect(() => {
        getPlaylistById('PL_XxuZqN0xVD0op-QDEgyXFA4fRPChvkl');
    }, []);

    console.log('Playlist', playlists);

    return <div>App</div>;
};

export default App;

এখন যদি ব্রাউজার কনসোল চেক করি তাহলে একটা প্লেলিস্ট অবজেক্ট আমরা দেখবো।

মোটামুটি এতটুকুই ছিল এই লেকচারের আলোচ্য বিষয়। পরবর্তীতে এই প্রজেক্টটা পর্যায়ক্রমে আপডেট করা হবে।

Source Code

এই লেকচারের সোর্স কোড এই কমিট হিস্টোরি তে গেলে পাবেন।