Skip to content

Commit

Permalink
almost working nowplaying, lrc ignore empty tag
Browse files Browse the repository at this point in the history
  • Loading branch information
nift4 committed May 22, 2024
1 parent 645ed3c commit dec77e2
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import coil3.util.Logger
import org.akanework.gramophone.BuildConfig
import org.akanework.gramophone.logic.ui.BugHandlerActivity
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import kotlin.system.exitProcess

/**
Expand Down Expand Up @@ -148,7 +148,7 @@ class GramophoneApplication : Application(), SingletonImageLoader.Factory {
}
// Let's keep the log readable and ignore normal events' stack traces.
if (throwable != null && throwable !is NullRequestDataException
&& (throwable !is FileNotFoundException
&& (throwable !is IOException
|| throwable.message != "No album art found")) {
Log.println(priority, tag, Log.getStackTraceString(throwable))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
completer.set((result as BitmapImage).bitmap)
},
onError = { _ ->
completer.setException(Exception("coil onError called"))
completer.setException(Exception("coil onError called" +
" (normal if no album art exists)"))
}
)
.build())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,27 @@ object LrcUtils {

@OptIn(UnstableApi::class)
fun extractAndParseLyrics(metadata: Metadata, trim: Boolean, multilineEnable: Boolean): MutableList<MediaStoreUtils.Lyric>? {
return extractLyrics(metadata)?.let {
try {
parseLrcString(it, trim, multilineEnable)
} catch (e: Exception) {
Log.e(TAG, Log.getStackTraceString(e))
null
} }
for (i in 0..<metadata.length()) {
val meta = metadata.get(i)
val data =
if (meta is VorbisComment && meta.key == "LYRICS") // ogg / flac
meta.value
else if (meta is BinaryFrame && (meta.id == "USLT" || meta.id == "SYLT")) // mp3 / other id3 based
UsltFrameDecoder.decode(ParsableByteArray(meta.data))
else if (meta is TextInformationFrame && (meta.id == "USLT" || meta.id == "SYLT")) // m4a
meta.values.joinToString("\n")
else null
val lyrics = data?.let {
try {
parseLrcString(it, trim, multilineEnable)
} catch (e: Exception) {
Log.e(TAG, Log.getStackTraceString(e))
null
}
}
return lyrics ?: continue
}
return null
}

@OptIn(UnstableApi::class)
Expand All @@ -40,20 +54,6 @@ object LrcUtils {
} }
}

@OptIn(UnstableApi::class)
private fun extractLyrics(metadata: Metadata): String? {
for (i in 0..<metadata.length()) {
val meta = metadata.get(i)
if (meta is VorbisComment && meta.key == "LYRICS") // ogg / flac
return meta.value
if (meta is BinaryFrame && (meta.id == "USLT" || meta.id == "SYLT")) // mp3 / other id3 based
return UsltFrameDecoder.decode(ParsableByteArray(meta.data))
if (meta is TextInformationFrame && (meta.id == "USLT" || meta.id == "SYLT")) // m4a
return meta.values.joinToString("\n")
}
return null
}

private fun loadLrcFile(lrcFile: File?): String? {
return try {
if (lrcFile?.exists() == true)
Expand Down Expand Up @@ -88,7 +88,8 @@ object LrcUtils {
* We completely ignore all ID3 tags from the header as MediaStore is our source of truth.
*/
@VisibleForTesting
fun parseLrcString(lrcContent: String, trim: Boolean, multilineEnable: Boolean): MutableList<MediaStoreUtils.Lyric> {
fun parseLrcString(lrcContent: String, trim: Boolean, multilineEnable: Boolean): MutableList<MediaStoreUtils.Lyric>? {
if (lrcContent.isBlank()) return null
val timeMarksRegex = "\\[(\\d{2}:\\d{2})([.:]\\d+)?]".toRegex()
val list = mutableListOf<MediaStoreUtils.Lyric>()
var foundNonNull = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,25 @@ class MediaControllerViewModel(application: Application) : AndroidViewModel(appl
}
}

fun addOneOffControllerCallback(lifecycle: Lifecycle?,
callback: LifecycleCallbackListImpl.Disposable.(MediaController, Lifecycle) -> Unit) {
fun addControllerCallback(lifecycle: Lifecycle?,
callback: LifecycleCallbackListImpl.Disposable.(MediaController, Lifecycle) -> Unit) {
// TODO migrate this to kt flows or LiveData?
val instance = get()
val ds = LifecycleCallbackListImpl.DisposableImpl()
var skip = false
if (instance != null) {
val ds = LifecycleCallbackListImpl.DisposableImpl()
ds.callback(instance, controllerLifecycle!!.lifecycle)
skip = ds.disposed
}
if (instance == null || !ds.disposed) {
if (instance == null || !skip) {
connectionListeners.addCallback(lifecycle, callback)
}
}

fun addRecreationalPlayerListener(lifecycle: Lifecycle, callback: Player.Listener) {
addOneOffControllerCallback(lifecycle) { controller, controllerLifecycle ->
fun addRecreationalPlayerListener(lifecycle: Lifecycle, callback: (Player) -> Player.Listener) {
addControllerCallback(lifecycle) { controller, controllerLifecycle ->
controller.registerLifecycleCallback(
LifecycleIntersection(lifecycle, controllerLifecycle).lifecycle, callback)
LifecycleIntersection(lifecycle, controllerLifecycle).lifecycle, callback(controller))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ abstract class BaseAdapter<T>(
override val concatAdapter by lazy { ConcatAdapter(decorAdapter, this) }
override val itemHeightHelper by lazy {
DefaultItemHeightHelper.concatItemHeightHelper(decorAdapter, {1}, this) }
private val handler = Handler(Looper.getMainLooper())
protected val handler = Handler(Looper.getMainLooper())
private var bgHandlerThread: HandlerThread? = null
private var bgHandler: Handler? = null
private val rawList = ArrayList<T>(liveData?.value?.size ?: 0)
Expand Down Expand Up @@ -188,7 +188,7 @@ abstract class BaseAdapter<T>(
view: View,
) : RecyclerView.ViewHolder(view) {
val songCover: ImageView = view.findViewById(R.id.cover)
val nowPlaying: MaterialButton = view.findViewById(R.id.now_playing)
val nowPlaying: ImageView = view.findViewById(R.id.now_playing)
val title: TextView = view.findViewById(R.id.title)
val subTitle: TextView = view.findViewById(R.id.artist)
val moreButton: MaterialButton = view.findViewById(R.id.more)
Expand Down Expand Up @@ -354,7 +354,7 @@ abstract class BaseAdapter<T>(

override fun onBindViewHolder(
holder: ViewHolder,
position: Int,
position: Int
) {
if (layoutType == LayoutType.GRID) {
val newHeight = gridHeight ?: gridHeightCache
Expand Down Expand Up @@ -411,7 +411,7 @@ abstract class BaseAdapter<T>(
}

override fun onViewRecycled(holder: ViewHolder) {
holder.nowPlaying.icon = null
holder.nowPlaying.setImageDrawable(null)
holder.nowPlaying.visibility = View.GONE
holder.songCover.dispose()
super.onViewRecycled(holder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class SongAdapter(
private val viewModel: LibraryViewModel by fragment.activityViewModels()
private val mediaControllerViewModel: MediaControllerViewModel by fragment.activityViewModels()
private var idToPosMap: HashMap<String, Int>? = null
private var currentMediaItem = mediaControllerViewModel.get()?.currentMediaItem?.mediaId
private var currentMediaItem: String? = null
set(value) {
if (field != value) {
val oldValue = field
Expand All @@ -113,24 +113,41 @@ class SongAdapter(
val oldPos = idToPosMap!![oldValue]
val newPos = idToPosMap!![value]
if (oldPos != null) {
notifyItemChanged(oldPos)
notifyItemChanged(oldPos, true)
}
if (newPos != null) {
notifyItemChanged(newPos)
notifyItemChanged(newPos, true)
}
}
}
}
private var currentIsPlaying: Boolean? = null
set(value) {
if (field != value) {
field = value
if (value != null && currentMediaItem != null) {
idToPosMap?.get(currentMediaItem)?.let {
notifyItemChanged(it, false)
}
}
}
}

init {
mediaControllerViewModel.addRecreationalPlayerListener(
fragment.viewLifecycleOwner.lifecycle,
fragment.viewLifecycleOwner.lifecycle) {
currentMediaItem = it.currentMediaItem?.mediaId
currentIsPlaying = it.isPlaying
object : Player.Listener {
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
currentMediaItem = mediaItem?.mediaId
}

override fun onIsPlayingChanged(isPlaying: Boolean) {
currentIsPlaying = isPlaying
}
}
)
}
}

override fun onListUpdated() {
Expand Down Expand Up @@ -303,20 +320,25 @@ class SongAdapter(
}
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
super.onBindViewHolder(holder, position)
if (currentMediaItem != null && list[position].mediaId == currentMediaItem) {
holder.nowPlaying.icon = NowPlayingDrawable()
holder.nowPlaying.visibility = View.VISIBLE
mediaControllerViewModel.addRecreationalPlayerListener( // TODO
fragment.viewLifecycleOwner.lifecycle,
object : Player.Listener {
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
currentMediaItem = mediaItem?.mediaId
}
}
)
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
if (payloads.isNotEmpty()) {
if (payloads.none { it is Boolean && it }) {
holder.nowPlaying.drawable.level = if (currentIsPlaying == true) 1 else 0
return
}
if (currentMediaItem == null || list[position].mediaId != currentMediaItem) {
holder.nowPlaying.visibility = View.GONE
holder.nowPlaying.setImageDrawable(null)
return
}
} else {
super.onBindViewHolder(holder, position, payloads)
if (currentMediaItem == null || list[position].mediaId != currentMediaItem)
return
}
holder.nowPlaying.setImageDrawable(NowPlayingDrawable()
.also { it.level = if (currentIsPlaying == true) 1 else 0 })
holder.nowPlaying.visibility = View.VISIBLE
}

class MediaItemHelper(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,9 +513,9 @@ class FullBottomSheet(context: Context, attrs: AttributeSet?, defStyleAttr: Int,
}

fun onStart() {
activity.controllerViewModel.addOneOffControllerCallback(activity.lifecycle) { _, _ ->
activity.controllerViewModel.addControllerCallback(activity.lifecycle) { _, _ ->
firstTime = true
instance?.addListener(this)
instance?.addListener(this@FullBottomSheet)
bottomSheetTimerButton.isChecked = instance?.hasTimer() == true
onRepeatModeChanged(instance?.repeatMode ?: Player.REPEAT_MODE_OFF)
onShuffleModeEnabledChanged(instance?.shuffleModeEnabled ?: false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ private inline val barWidth
class NowPlayingDrawable : Drawable() {

private val paint = Paint()
private var state: Int = 0 // 0 = paused, 1 = playing
private var sx: Float = 1f // scale x
private var sy: Float = 1f // scale y
private var lc: Float = 0f // left current
Expand All @@ -35,13 +34,13 @@ class NowPlayingDrawable : Drawable() {

override fun draw(canvas: Canvas) {
// Left bar
canvas.drawBar(0f, 320f)
canvas.drawBar(0f, if (level == 1) 320f else 10f)

// Middle bar
canvas.drawBar(240f, 640f)
canvas.drawBar(240f, if (level == 1) 640f else 10f)

// Right bar
canvas.drawBar(480f, 480f)
canvas.drawBar(480f, if (level == 1) 480f else 10f)

// invalidateSelf()
}
Expand Down Expand Up @@ -71,6 +70,11 @@ class NowPlayingDrawable : Drawable() {
return tr
}

override fun onLevelChange(level: Int): Boolean {
invalidateSelf()
return true
}

override fun setAlpha(alpha: Int) {
paint.alpha = alpha
}
Expand Down Expand Up @@ -109,11 +113,6 @@ class NowPlayingDrawable : Drawable() {
if (tintMode == null) tintColor!! else Color.WHITE
}

override fun onLevelChange(level: Int): Boolean {
this.state = level
return true
}

@Deprecated("Deprecated in Java",
ReplaceWith("PixelFormat.TRANSLUCENT", "android.graphics.PixelFormat")
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,8 @@ class PlayerBottomSheet private constructor(

override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
activity.controllerViewModel.addOneOffControllerCallback(activity.lifecycle) { _, _ ->
instance?.addListener(this)
activity.controllerViewModel.addControllerCallback(activity.lifecycle) { _, _ ->
instance?.addListener(this@PlayerBottomSheet)
onPlaybackStateChanged(instance?.playbackState ?: Player.STATE_IDLE)
onMediaItemTransition(
instance?.currentMediaItem,
Expand All @@ -423,6 +423,7 @@ class PlayerBottomSheet private constructor(
) {
instance?.play()
}
dispose() // do not call callback again
}
fullPlayer.onStart()
}
Expand Down
21 changes: 8 additions & 13 deletions app/src/main/res/layout/adapter_grid_card.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,23 +74,18 @@

</LinearLayout>

<com.google.android.material.button.MaterialButton
<ImageView
android:id="@+id/now_playing"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintTop_toTopOf="@id/linearLayout"
app:layout_constraintBottom_toBottomOf="@id/linearLayout"
app:layout_constraintEnd_toStartOf="@id/more"
android:background="@drawable/rp_buttons"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
android:padding="12dp"
app:tint="?attr/colorControlNormal"
android:layout_gravity="end|center_vertical"
android:contentDescription="@string/now_playing"
android:visibility="gone"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/more"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.button.MaterialButton
android:id="@+id/more"
Expand Down
14 changes: 4 additions & 10 deletions app/src/main/res/layout/adapter_list_card.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,15 @@

</LinearLayout>

<com.google.android.material.button.MaterialButton
<ImageView
android:id="@+id/now_playing"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="12dp"
app:tint="?attr/colorControlNormal"
android:layout_gravity="end|center_vertical"
android:background="@drawable/rp_buttons"
android:insetLeft="0dp"
android:insetTop="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
android:contentDescription="@string/now_playing"
android:visibility="gone"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/more"
app:layout_constraintTop_toTopOf="parent" />
Expand Down
Loading

0 comments on commit dec77e2

Please sign in to comment.