Android Youtube Search API with data v3 유튜브 검색 API

설명

유튜브 검색 API를 사용하기 위해서는 구글 클라우드에서 설정이 필요하다.

API 설정

preview

개발환경

코드

viewModel

fun getYoutubeVideo(keyword: String) = viewModelScope.launch {

        val result = searchRepository.getYoutubeVideo(keyword)

        when (result.code()) {
            200 -> {

                val idList = mutableListOf<String>()
                val convertedList = mutableListOf<Video>()

                result.body()?.let {

                    nextPageToken = it.nextPageToken

                    it.items?.let { list ->
                        for (item in list) {

                            val id = item.id
                            val snippet = item.snippet

                            convertedList.add(
                                Video(
                                    videoId = id.videoId,
                                    title = snippet.title,
                                    description = snippet.description,
                                    publishedAt = snippet.publishedAt,
                                    imgUrl = snippet.thumbnails.medium.url,
                                    channelTitle = snippet.channelTitle
                                )
                            )

                            idList.add(id.videoId)
                        }
                    }

                }

                coroutineScope {
                    (0 until idList.size).map { idx ->
                        async(Dispatchers.IO) {
                            val resultInfo = searchRepository.requestVideoInfo(idList[idx])

                            when (resultInfo.code()) {
                                200 -> {
                                    resultInfo.body()?.let {
                                        convertedList.find { video ->
                                            video.videoId == idList[idx]
                                        }?.let { findVideo ->
                                            it.items?.let { list ->
                                                for (item in list) {
                                                    findVideo.duration =
                                                        item.contentDetails.duration
                                                    findVideo.viewCount =
                                                        item.statistics.viewCount.toString()
                                                }
                                            }
                                        }
                                    }
                                }
                                else -> {
                                    Log.e(TAG, "onFailure ${resultInfo.message()}")
                                }
                            }
                        }
                    }.awaitAll()

                    firstSearch.postValue(convertedList)
                }

            }
            else -> {
                Log.e(TAG, "onFailure ${result.message()}")
            }
        }

    }

repository

@WorkerThread
suspend fun getYoutubeVideo(searchText: String) =
    YoutubeApiRequestFactory.retrofit.getYouTubeVideos(
        apiKey = apiKey, query = searchText, videoOrder = "relevance", maxResults = 10
    )

@WorkerThread
suspend fun requestVideoInfo(videoId: String) =
    YoutubeApiRequestFactory.retrofit.getVideoInfo(
        apiKey = apiKey,
        videoId = videoId
    )

object YoutubeApiRequestFactory {

    private const val youtubeBaseUrl = "https://www.googleapis.com/youtube/v3/"

    val retrofit: YoutubeApiService = Retrofit.Builder()
        .baseUrl(youtubeBaseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(
            OkHttpClient.Builder().addInterceptor(
                HttpLoggingInterceptor().apply { this.level = HttpLoggingInterceptor.Level.BODY }
            ).build())
        .build()
        .create(YoutubeApiService::class.java)
}

interface YoutubeApiService {

    @GET("search")
    suspend fun getYouTubeVideos(
        @Query("key") apiKey: String,
        @Query("q") query: String,
        @Query("order") videoOrder: String,
        @Query("type") videoType: String = "video",
        @Query("maxResults") maxResults: Int,
        @Query("channelId") channelId: String = "",
        @Query("part") part: String = "snippet",
    ): Response<YoutubeVideo>

    @GET("search")
    suspend fun getYouTubeMoreVideos(
        @Query("key") apiKey: String,
        @Query("q") query: String,
        @Query("pageToken") nextPageToken: String,
        @Query("order") videoOrder: String,
        @Query("type") videoType: String = "video",
        @Query("maxResults") maxResults: Int,
        @Query("channelId") channelId: String = "",
        @Query("part") part: String = "snippet",
    ): Response<YoutubeVideo>

    @GET("videos")
    suspend fun getVideoInfo(
        @Query("key") apiKey: String,
        @Query("id") videoId: String,
        @Query("part") part: String = "contentDetails, statistics",
    ): Response<YoutubeVideoInfo>
}

network model

import android.os.Parcelable
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize

@Parcelize
data class YoutubeVideo(
    @SerializedName("kind")
    @Expose
    val kind: String,
    @SerializedName("etag")
    @Expose
    val etag: String,
    @SerializedName("nextPageToken")
    @Expose
    val nextPageToken: String,
    @SerializedName("regionCode")
    @Expose
    val regionCode: String,
    @SerializedName("pageInfo")
    @Expose
    val pageInfo: PageInfo,
    @SerializedName("items")
    @Expose
    val items: List<Items>?
) : Parcelable

@Parcelize
data class PageInfo(
    @SerializedName("totalResults")
    @Expose
    val totalResults: Int,
    @SerializedName("resultsPerPage")
    @Expose
    val resultsPerPage: Int
) : Parcelable

@Parcelize
data class Items(
    @SerializedName("id")
    @Expose
    val id: Id,
    @SerializedName("snippet")
    @Expose
    val snippet: Snippet
) : Parcelable

@Parcelize
data class Id(
    @SerializedName("kind")
    @Expose
    val kind: String,
    @SerializedName("videoId")
    @Expose
    val videoId: String
) : Parcelable

@Parcelize
data class Snippet(
    @SerializedName("publishedAt")
    @Expose
    val publishedAt: String,
    @SerializedName("channelId")
    @Expose
    val channelId: String,
    @SerializedName("title")
    @Expose
    val title: String,
    @SerializedName("description")
    @Expose
    val description: String,
    @SerializedName("thumbnails")
    @Expose
    val thumbnails: ThumbNail,
    @SerializedName("publishTime")
    @Expose
    val publishTime: String,
    @SerializedName("channelTitle")
    @Expose
    val channelTitle: String,
) : Parcelable

@Parcelize
data class ThumbNail(
    @SerializedName("medium")
    @Expose
    val medium: Medium
) : Parcelable

@Parcelize
data class Medium(
    @SerializedName("url")
    @Expose
    val url: String,
    @SerializedName("width")
    @Expose
    val width: Int,
    @SerializedName("height")
    @Expose
    val height: Int
) : Parcelable


@Parcelize
data class YoutubeVideoInfo(
    @SerializedName("kind")
    @Expose
    val kind: String,
    @SerializedName("etag")
    @Expose
    val etag: String,
    @SerializedName("items")
    @Expose
    val items: List<TrendItem>?
) : Parcelable

@Parcelize
data class TrendItem(
    @SerializedName("kind")
    @Expose
    val kind: String,
    @SerializedName("etag")
    @Expose
    val etag: String,
    @SerializedName("id")
    @Expose
    val id: String,

    @SerializedName("snippet")
    @Expose
    val snippet: Snippet,

    @SerializedName("tags")
    @Expose
    val tags: List<String>,

    @SerializedName("contentDetails")
    @Expose
    val contentDetails: ContentDetails,

    @SerializedName("statistics")
    @Expose
    val statistics: Statistics
) : Parcelable

@Parcelize
data class ContentDetails(
    @SerializedName("duration")
    @Expose
    val duration: String
) : Parcelable

@Parcelize
data class Statistics(
    @SerializedName("viewCount")
    @Expose
    val viewCount: String? = ""
) : Parcelable

참조



Related Posts