YouTube Data API v3 사용하기

quinones·2024년 2월 7일

YouTube Data API

유튜브 데이터를 사용해서 동영상의 썸네일사진과 제목을 가져와보려고 한다.

요청 파라미터

사이트에서 보면 요청 파라미터에 GET이 있는데 미리 저장해둔다.

GET https://www.googleapis.com/youtube/v3/videos

마지막 videos와 그앞의 내용을 따로 사용해줄 예정이다.

필수 매개변수 - part

이건 많은 내용이 담겨있는 snippet을 사용할거다.

택1 필수 변수

chart , id , myRating 3가지중 1가지는 필수로 작성해줘야한다. chart는 인기많은 영상순, id는 원하는 영상의 Id를 가져와서 직접 사용해줄수 있다. MyRating은 인증된 사용자가 좋아요/싫어요 표시한 동영상을 반환해준다고한다.

선택적 매개변수

많은 값들이있는데 나는 그중에서 maxResults(반환 최대개수, 기본값은 5)와 videoCategoryId를 사용해줄거다.
유튜브는 1~40까지의 동영상 카테고리를 제공한다.
카테고리검색
위 링크에서 직접 사용해보고 원하는 카테고리를 넣어주면 된다.

데이터

비디오
위 링크에서 데이터를 사용해보면 나오는 값들로 데이터클래스를 만들어준다.


data class SearchResponse(
    val kind: String,
    val etag: String,
    @SerializedName("items")
    val items: List<SearchItems>,
    val nextPageToken: String,
    @SerializedName("pageInfo")
    val pageInfo: PageInfo
)

data class PageInfo(
    val resultsPerPage: Int,
    val totalResults: Int
)
data class SearchItems(
    val etag: String,
    val id: String,
    val kind: String,
    @SerializedName("snippet")
    val snippet: Snippet
)
data class Snippet(
    val publishedAt: String,
    val channelId: String,
    val title: String,
    val description: String,
    @SerializedName("thumbnails")
    val thumbnails: Thumbnails,
    val channelTitle: String,
    val categoryId: String,
    val liveBroadcastContent: String,
    @SerializedName("localized")
    val localized: Localized,
    val defaultAudioLanguage: String,
    @SerializedName("tags")
    val tags: List<String>,
)
data class Thumbnails(
    @SerializedName("default")
    val default: Default,
    @SerializedName("high")
    val high: High,
    @SerializedName("maxres")
    val maxres: Maxres,
    @SerializedName("medium")
    val medium: Medium,
    @SerializedName("standard")
    val standard: Standard
)
data class Localized(
    val description: String,
    val title: String
)
data class Default(
    val height: Int,
    val url: String,
    val width: Int
)
data class High(
    val height: Int,
    val url: String,
    val width: Int
)
data class Maxres(
    val height: Int,
    val url: String,
    val width: Int
)
data class Medium(
    val height: Int,
    val url: String,
    val width: Int
)
data class Standard(
    val height: Int,
    val url: String,
    val width: Int
)

interface

interface NetWorkInterface {
    @GET(Contract.REQUEST_ADDRESS)
    suspend fun getYoutubeVideo(
        @QueryMap param: HashMap<String, String>
    ): SearchResponse
}

여기서 GET에는 아까 봐둔 videos를 넣어준다.

client


object NetWorkClient {

    private fun createOkHttpClient(): OkHttpClient {
        val interceptor = HttpLoggingInterceptor()

        if (BuildConfig.DEBUG)
            interceptor.level = HttpLoggingInterceptor.Level.BODY
        else
            interceptor.level = HttpLoggingInterceptor.Level.NONE

        return OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .addNetworkInterceptor(interceptor)
            .build()
    }

    private val youtubeRetrofit = Retrofit.Builder()
        .baseUrl(Contract.SERVICE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(createOkHttpClient())
        .build()

    val youtubeNetWork: NetWorkInterface = youtubeRetrofit.create(NetWorkInterface::class.java)

}

다른 api를 사용할때와 이용방법은 같다.

프래그먼트에서 사용

private fun setUpVideoParameter(): HashMap<String, String> {
        val authKey = BuildConfig.youtube_api_key
        return hashMapOf(
            "key" to authKey,
            "part" to "snippet",
            "chart" to "mostPopular",
            "maxResults" to "20",
            "regionCode" to "kr",
            "videoCategoryId" to "17"
        )
    }

발급받은 내 api_key값을 저장해서 해쉬맵으로 리턴해주는 함수를 만들어준다. 여기서 아까 말한 필수, 선택 파라미터들의 값들을 넣어주는데, 키값, part는 snippet으로, 인기있는영상으로 20개 한국에서 17번째 카테고리 영상을 가져오려 한다.

그리고

    private fun communicateNetWork(param: HashMap<String, String>) =
        lifecycleScope.launch() {

            val responseData = NetWorkClient.youtubeNetWork.getYoutubeVideo(param)
            val searchItems = responseData.items

            if (searchItems.isNotEmpty()) {
                for (item in searchItems) {
                    val videoItem = MyVideoItems(
                        videoUri = item.id,
                        title = item.snippet.title,
                        thumbnail = item.snippet.thumbnails.default.url,
                        content = item.snippet.description,
                        isLike = false
                    )
                    videoList.add(videoItem)
                }
                withContext(Dispatchers.Main){
                    adapter.submitList(videoList.toList())
                }
            } else {
                // 데이터가 없을 경우에 대한 처리
            }
        }

내가 미리 만들어둔 MyVideoItems형태로 가져온 데이터를 가공해서 저장해주고, 리사이클러뷰에 데이터를 뿌려주면 된다.
여기서는 리스트 어뎁터를 사용했다.

MyVideoItems

@Parcelize
data class MyVideoItems(
    val videoUri: String?,
    var title: String,
    var thumbnail: String,
    var content: String,
    var isLike: Boolean
) : Parcelable

VideoAdapter

class VideoAdapter(
    private val onClickItem: (Int, MyVideoItems) -> Unit,
) : ListAdapter<MyVideoItems, VideoAdapter.VideoViewHolder>(VideoDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoViewHolder {
        val binding = VideoItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return VideoViewHolder(binding)
    }

    override fun onBindViewHolder(holder: VideoViewHolder, position: Int) {
        val videoItem = getItem(position)
        holder.bind(videoItem)
        holder.itemView.setOnClickListener {
            onClickItem(position, videoItem)
        }
    }

    class VideoViewHolder(private val binding: VideoItemBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(videoItem: MyVideoItems) {
            binding.videoTitle.text = videoItem.title
            Glide.with(binding.root).load(videoItem.thumbnail).into(binding.videoImage)
        }
    }

    private class VideoDiffCallback : DiffUtil.ItemCallback<MyVideoItems>() {
        override fun areItemsTheSame(oldItem: MyVideoItems, newItem: MyVideoItems): Boolean {
            return oldItem.videoUri == newItem.videoUri
        }

        override fun areContentsTheSame(oldItem: MyVideoItems, newItem: MyVideoItems): Boolean {
            return oldItem == newItem
        }
    }
}

더 간편한 사용을 위해서 listAdapter를 사용해줬고, diffUtill로 알아서 데이터의 변환을 감지해 설정해준다.
아이템의 제목과 사진을 넣어주기만 했다.

profile
이우진

0개의 댓글