diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6e6f31c..410f502 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -47,6 +47,9 @@
+
${browseId}")
+ initData(browseId)
+ }
+
+ private fun initImmersionBar() {
+ immersionBar {
+ statusBarDarkFont(false)
+ statusBarView(binding.view)
+ }
+ }
+
+ private fun initView() {
+ binding.backBtn.setOnClickListener {
+ finish()
+ }
+ }
+
+ private suspend fun initData(browseId: String) {
+ Innertube.moPlaylistPage(browseId)
+ ?.onSuccess {
+ Glide.with(this)
+ .load(it.thumbnail)
+ .into(binding.imageView)
+
+ binding.title.text = it.title
+ binding.subtitle.text = it.subtitle
+ binding.secondSubtitle.text = it.secondSubtitle
+
+ val adapter = DetailsListAdapter(this, it.moPlaylistOrAlbumListBean)
+ binding.rv.layoutManager =
+ LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
+ binding.rv.adapter = adapter
+
+ }?.onFailure {
+ Log.d(TAG, "moPlaylistPage onFailure->${it}")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/player/musicoo/activity/MoBaseActivity.kt b/app/src/main/java/com/player/musicoo/activity/MoBaseActivity.kt
index 546bccb..855a77d 100644
--- a/app/src/main/java/com/player/musicoo/activity/MoBaseActivity.kt
+++ b/app/src/main/java/com/player/musicoo/activity/MoBaseActivity.kt
@@ -1,15 +1,33 @@
package com.player.musicoo.activity
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.drawable.Drawable
import android.os.Bundle
+import android.renderscript.Allocation
+import android.renderscript.Element
+import android.renderscript.RenderScript
+import android.renderscript.ScriptIntrinsicBlur
+import android.view.LayoutInflater
+import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.target.CustomTarget
+import com.bumptech.glide.request.transition.Transition
+import com.player.musicoo.R
import com.player.musicoo.sp.AppStore
import com.player.musicoo.util.LogTag
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import java.io.IOException
+import java.io.InputStream
abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope() {
@@ -70,4 +88,63 @@ abstract class MoBaseActivity : AppCompatActivity(), CoroutineScope by MainScope
}
}
}
+
+ suspend fun loadBitmapWithGlide(imageUrl: String): Bitmap? {
+ return withContext(Dispatchers.IO) {
+ try {
+ Glide.with(this@MoBaseActivity)
+ .asBitmap()
+ .load(imageUrl)
+ .submit() // 异步加载Bitmap
+ .get() // 阻塞等待获取Bitmap
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+ }
+ }
+
+ fun applyGaussianBlur(inputBitmap: Bitmap, radius: Float, context: Context): Bitmap {
+ val rsContext = RenderScript.create(context)
+ val outputBitmap =
+ Bitmap.createBitmap(inputBitmap.width, inputBitmap.height, inputBitmap.config)
+ val blurScript = ScriptIntrinsicBlur.create(rsContext, Element.U8_4(rsContext))
+ val tmpIn = Allocation.createFromBitmap(rsContext, inputBitmap)
+ val tmpOut = Allocation.createFromBitmap(rsContext, outputBitmap)
+ blurScript.setRadius(radius)
+ blurScript.setInput(tmpIn)
+ blurScript.forEach(tmpOut)
+ tmpOut.copyTo(outputBitmap)
+ rsContext.finish()
+ return outputBitmap
+ }
+
+ fun loadBitmapFromAsset(id: Int): Bitmap {
+ return try {
+ val inputStream: InputStream = resources.openRawResource(id)
+ BitmapFactory.decodeStream(inputStream)
+ } catch (e: IOException) {
+ e.printStackTrace()
+ throw RuntimeException("Could not load bitmap from asset")
+ }
+ }
+
+ fun showSongDescriptionDialog(description: String) {
+ val inflater = LayoutInflater.from(this)
+ val dialogView = inflater.inflate(R.layout.dialog_description, null)
+ val title = dialogView.findViewById(R.id.dialog_title)
+ title.text = getString(R.string.description)
+ val content = dialogView.findViewById(R.id.dialog_content)
+ content.text = description
+ val okBtn = dialogView.findViewById(R.id.dialog_ok_btn)
+ val dialogBuilder = AlertDialog.Builder(this)
+ .setView(dialogView)
+ val dialog = dialogBuilder.create()
+ dialog.show()
+ okBtn.setOnClickListener {
+ dialog.dismiss()
+ }
+ }
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/player/musicoo/adapter/DetailsListAdapter.kt b/app/src/main/java/com/player/musicoo/adapter/DetailsListAdapter.kt
new file mode 100644
index 0000000..d7b59db
--- /dev/null
+++ b/app/src/main/java/com/player/musicoo/adapter/DetailsListAdapter.kt
@@ -0,0 +1,82 @@
+package com.player.musicoo.adapter
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.player.musicoo.App
+import com.player.musicoo.R
+import com.player.musicoo.activity.PlayDetailsActivity
+import com.player.musicoo.bean.Audio
+import com.player.musicoo.databinding.DetailsListItemBinding
+import com.player.musicoo.databinding.MusicResponsiveItemBinding
+import com.player.musicoo.databinding.SoundsOfAppliancesLayoutBinding
+import com.player.musicoo.databinding.SoundsOfNatureLayoutBinding
+import com.player.musicoo.innertube.Innertube
+import com.player.musicoo.innertube.models.MusicCarouselShelfRenderer
+import com.player.musicoo.util.convertMillisToMinutesAndSecondsString
+import com.player.musicoo.util.getAudioDurationFromAssets
+
+class DetailsListAdapter(
+ private val context: Context,
+ private val list: List,
+) :
+ RecyclerView.Adapter() {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val binding = DetailsListItemBinding.inflate(LayoutInflater.from(context), parent, false)
+ return ViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val bean = list[position]
+ holder.bind(bean)
+ }
+
+ override fun getItemCount(): Int = list.size
+
+ inner class ViewHolder(private val binding: DetailsListItemBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+
+ @SuppressLint("SetTextI18n")
+ fun bind(bean: Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean) {
+
+ binding.apply {
+ if (!bean.thumbnailUrl.isNullOrEmpty()) {
+ image.visibility = View.VISIBLE
+ Glide.with(context)
+ .load(bean.thumbnailUrl)
+ .into(image)
+ sortTv.visibility = View.GONE
+ } else {
+ image.visibility = View.GONE
+ sortTv.visibility = View.VISIBLE
+ sortTv.text = "${bindingAdapterPosition + 1}"
+ }
+
+ title.text = bean.title
+ if (bean.name.isNullOrEmpty()) {
+ name.visibility = View.GONE
+ } else {
+ name.visibility = View.VISIBLE
+ name.text = bean.name
+ }
+
+ }
+ }
+ }
+
+ private var itemClickListener: OnItemClickListener? = null
+
+ fun setOnItemClickListener(listener: OnItemClickListener) {
+ itemClickListener = listener
+ }
+
+ interface OnItemClickListener {
+ fun onItemClick(position: Int)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/player/musicoo/adapter/TowRowListAdapter.kt b/app/src/main/java/com/player/musicoo/adapter/TowRowListAdapter.kt
index a7f9996..cf42bd1 100644
--- a/app/src/main/java/com/player/musicoo/adapter/TowRowListAdapter.kt
+++ b/app/src/main/java/com/player/musicoo/adapter/TowRowListAdapter.kt
@@ -2,6 +2,7 @@ package com.player.musicoo.adapter
import android.content.Context
import android.content.Intent
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -9,6 +10,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.player.musicoo.App
import com.player.musicoo.R
+import com.player.musicoo.activity.DetailsActivity
import com.player.musicoo.activity.PlayDetailsActivity
import com.player.musicoo.bean.Audio
import com.player.musicoo.databinding.MusicResponsiveItemBinding
@@ -16,6 +18,7 @@ import com.player.musicoo.databinding.MusicTowRowItemBinding
import com.player.musicoo.databinding.SoundsOfAppliancesLayoutBinding
import com.player.musicoo.databinding.SoundsOfNatureLayoutBinding
import com.player.musicoo.innertube.models.MusicCarouselShelfRenderer
+import com.player.musicoo.util.LogTag
import com.player.musicoo.util.convertMillisToMinutesAndSecondsString
import com.player.musicoo.util.getAudioDurationFromAssets
@@ -33,7 +36,23 @@ class TowRowListAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val bean = list[position]
+
+ val browseEndpoint = bean.musicTwoRowItemRenderer
+ ?.title
+ ?.runs
+ ?.firstOrNull()
+ ?.navigationEndpoint
+ ?.browseEndpoint
+
+ val browseId = browseEndpoint?.browseId
+
holder.bind(bean)
+
+ holder.itemView.setOnClickListener {
+ val intent = Intent(context, DetailsActivity::class.java)
+ intent.putExtra(DetailsActivity.PLAY_LIST_PAGE_BROWSE_ID, browseId)
+ context.startActivity(intent)
+ }
}
override fun getItemCount(): Int = list.size
diff --git a/app/src/main/java/com/player/musicoo/innertube/Innertube.kt b/app/src/main/java/com/player/musicoo/innertube/Innertube.kt
index 3b1725b..58d64f0 100644
--- a/app/src/main/java/com/player/musicoo/innertube/Innertube.kt
+++ b/app/src/main/java/com/player/musicoo/innertube/Innertube.kt
@@ -177,6 +177,28 @@ object Innertube {
val contents: List
)
+ data class MoPlaylistOrAlbumPage(
+ val title: String?,
+ val subtitle: String?,
+ val thumbnail: String?,
+ val secondSubtitle: String?,
+ val description: String?,
+ val moPlaylistOrAlbumListBean: List
+ ) {
+ data class MoPlaylistOrAlbumListBean(
+ val title: String?,
+ val name: String?,
+ val desc: String?,
+ val timeText: String?,
+ val browseId: String,
+ val videoId: String?,
+ val playlistId: String?,
+ val musicVideoType: String?,
+ val pageType: String?,
+ val thumbnailUrl: String?
+ )
+ }
+
data class ArtistPage(
val name: String?,
val description: String?,
diff --git a/app/src/main/java/com/player/musicoo/innertube/models/BrowseResponse.kt b/app/src/main/java/com/player/musicoo/innertube/models/BrowseResponse.kt
index 7297521..227ebf7 100644
--- a/app/src/main/java/com/player/musicoo/innertube/models/BrowseResponse.kt
+++ b/app/src/main/java/com/player/musicoo/innertube/models/BrowseResponse.kt
@@ -41,6 +41,7 @@ data class BrowseResponse(
val subtitle: Runs?,
val secondSubtitle: Runs?,
val thumbnail: ThumbnailRenderer?,
+ val description: Runs?
)
@Serializable
diff --git a/app/src/main/java/com/player/musicoo/innertube/requests/MoPlaylistPage.kt b/app/src/main/java/com/player/musicoo/innertube/requests/MoPlaylistPage.kt
new file mode 100644
index 0000000..e6cb842
--- /dev/null
+++ b/app/src/main/java/com/player/musicoo/innertube/requests/MoPlaylistPage.kt
@@ -0,0 +1,135 @@
+package com.player.musicoo.innertube.requests
+
+import com.player.musicoo.innertube.Innertube
+import com.player.musicoo.innertube.models.BrowseResponse
+import com.player.musicoo.innertube.models.MusicShelfRenderer
+import com.player.musicoo.innertube.models.bodies.BrowseBody
+import com.player.musicoo.innertube.utils.runCatchingNonCancellable
+import io.ktor.client.call.body
+import io.ktor.client.request.post
+import io.ktor.client.request.setBody
+
+suspend fun Innertube.moPlaylistPage(browseId: String): Result? =
+ runCatchingNonCancellable {
+ val response = client.post(browse) {
+ setBody(BrowseBody(browseId = browseId))
+ }.body()
+
+
+ val musicDetailHeaderRenderer = response
+ .header
+ ?.musicDetailHeaderRenderer
+
+ val sectionListRendererContents = response
+ .contents
+ ?.singleColumnBrowseResultsRenderer
+ ?.tabs
+ ?.firstOrNull()
+ ?.tabRenderer
+ ?.content
+ ?.sectionListRenderer
+ ?.contents
+
+ val musicShelfRenderer = sectionListRendererContents
+ ?.firstOrNull()
+ ?.musicShelfRenderer
+
+ val musicCarouselShelfRenderer = sectionListRendererContents
+ ?.getOrNull(1)
+ ?.musicCarouselShelfRenderer
+
+ val list: MutableList =
+ mutableListOf()
+ list.clear()
+ val contents = musicShelfRenderer?.contents
+ if (contents != null) {
+ for (content: MusicShelfRenderer.Content in contents) {
+ val runs0 = content.musicResponsiveListItemRenderer
+ ?.flexColumns
+ ?.getOrNull(0)
+ ?.musicResponsiveListItemFlexColumnRenderer
+ ?.text
+ ?.runs
+ ?.firstOrNull()
+ val watchEndpoint = runs0?.navigationEndpoint?.watchEndpoint
+ val runs1 = content.musicResponsiveListItemRenderer
+ ?.flexColumns
+ ?.getOrNull(1)
+ ?.musicResponsiveListItemFlexColumnRenderer
+ ?.text
+ ?.runs
+ ?.firstOrNull()
+ val browseEndpoint = runs1?.navigationEndpoint?.browseEndpoint
+
+ val runs2 = content.musicResponsiveListItemRenderer
+ ?.flexColumns
+ ?.getOrNull(2)
+ ?.musicResponsiveListItemFlexColumnRenderer
+ ?.text
+ ?.runs
+ ?.firstOrNull()
+
+ val thumbnailUrl = content.musicResponsiveListItemRenderer
+ ?.thumbnail
+ ?.musicThumbnailRenderer
+ ?.thumbnail
+ ?.thumbnails
+ ?.firstOrNull()
+ ?.url
+
+
+ val bean = Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean(
+ title = runs0?.text,
+ name = runs1?.text,
+ desc = runs2?.text,
+ timeText = content.musicResponsiveListItemRenderer
+ ?.fixedColumns?.firstOrNull()
+ ?.musicResponsiveListItemFlexColumnRenderer
+ ?.text
+ ?.runs
+ ?.firstOrNull()
+ ?.text,
+ browseId = browseEndpoint?.browseId.toString(),
+ videoId = watchEndpoint?.videoId,
+ playlistId = watchEndpoint?.playlistId,
+ musicVideoType = watchEndpoint?.type,
+ pageType = browseEndpoint?.type,
+ thumbnailUrl = thumbnailUrl
+ )
+
+ list.add(bean)
+ }
+ }
+
+
+ Innertube.MoPlaylistOrAlbumPage(
+ title = musicDetailHeaderRenderer
+ ?.title
+ ?.runs
+ ?.firstOrNull()
+ ?.text,
+ subtitle = musicDetailHeaderRenderer
+ ?.subtitle
+ ?.runs
+ ?.map { it.text }
+ ?.joinToString(""),
+ thumbnail = musicDetailHeaderRenderer
+ ?.thumbnail
+ ?.musicThumbnailRenderer
+ ?.thumbnail
+ ?.thumbnails
+ ?.let { it.getOrNull(3) ?: it.getOrNull(2) ?: it.getOrNull(1) ?: it.getOrNull(0) }
+ ?.url,
+ secondSubtitle = musicDetailHeaderRenderer
+ ?.secondSubtitle
+ ?.runs
+ ?.map { it.text }
+ ?.joinToString(""),
+ description = musicDetailHeaderRenderer
+ ?.description
+ ?.runs
+ ?.firstOrNull()
+ ?.text,
+ moPlaylistOrAlbumListBean = list
+ )
+ }
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_details.xml b/app/src/main/res/layout/activity_details.xml
new file mode 100644
index 0000000..d018cbe
--- /dev/null
+++ b/app/src/main/res/layout/activity_details.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/details_list_item.xml b/app/src/main/res/layout/details_list_item.xml
new file mode 100644
index 0000000..9358577
--- /dev/null
+++ b/app/src/main/res/layout/details_list_item.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_description.xml b/app/src/main/res/layout/dialog_description.xml
new file mode 100644
index 0000000..639be3e
--- /dev/null
+++ b/app/src/main/res/layout/dialog_description.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 1ab11ba..905ca71 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -4,6 +4,7 @@
#99000000
#FFFFFFFF
#99FFFFFF
+ #CCFFFFFF
#151718
#FF80F988
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a4a54d6..b8fb464 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -16,4 +16,6 @@
Terms of Service
Listen Music Anytime
Resource Loading…
+ EXPAND
+ Description
\ No newline at end of file