유튜브 데이터를 사용해서 동영상의 썸네일사진과 제목을 가져와보려고 한다.
사이트에서 보면 요청 파라미터에 GET이 있는데 미리 저장해둔다.
마지막 videos와 그앞의 내용을 따로 사용해줄 예정이다.
이건 많은 내용이 담겨있는 snippet을 사용할거다.
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 NetWorkInterface {
@GET(Contract.REQUEST_ADDRESS)
suspend fun getYoutubeVideo(
@QueryMap param: HashMap<String, String>
): SearchResponse
}
여기서 GET에는 아까 봐둔 videos를 넣어준다.
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형태로 가져온 데이터를 가공해서 저장해주고, 리사이클러뷰에 데이터를 뿌려주면 된다.
여기서는 리스트 어뎁터를 사용했다.
@Parcelize
data class MyVideoItems(
val videoUri: String?,
var title: String,
var thumbnail: String,
var content: String,
var isLike: Boolean
) : Parcelable
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로 알아서 데이터의 변환을 감지해 설정해준다.
아이템의 제목과 사진을 넣어주기만 했다.