Fixed lyrics crash
This commit is contained in:
parent
9fc25b71ce
commit
ff2574fffc
9 changed files with 249 additions and 279 deletions
|
@ -36,7 +36,6 @@ import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.MusicUtil
|
import code.name.monkey.retromusic.util.MusicUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -108,11 +107,6 @@ class AlbumCoverPagerAdapter(
|
||||||
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
|
||||||
ViewCompat.setTransitionName(view, "lyrics")
|
ViewCompat.setTransitionName(view, "lyrics")
|
||||||
albumCover = view.findViewById(R.id.player_image)
|
albumCover = view.findViewById(R.id.player_image)
|
||||||
view.setOnClickListener {
|
|
||||||
if (mainActivity.getBottomSheetBehavior().state == STATE_EXPANDED) {
|
|
||||||
showLyricsDialog()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,10 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
||||||
showLyricsIcon(item)
|
showLyricsIcon(item)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
R.id.action_go_to_lyrics -> {
|
||||||
|
goToLyrics(requireActivity())
|
||||||
|
return true
|
||||||
|
}
|
||||||
R.id.action_toggle_favorite -> {
|
R.id.action_toggle_favorite -> {
|
||||||
toggleFavorite(song)
|
toggleFavorite(song)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -231,13 +231,7 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
private fun editSyncedLyrics() {
|
private fun editSyncedLyrics() {
|
||||||
var lrcFile: File? = null
|
val content: String = LyricUtil.getStringFromLrc(LyricUtil.getSyncedLyricsFile(song))
|
||||||
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
|
|
||||||
lrcFile = LyricUtil.getLocalLyricOriginalFile(song.data)
|
|
||||||
} else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
|
|
||||||
lrcFile = LyricUtil.getLocalLyricFile(song.title, song.artistName)
|
|
||||||
}
|
|
||||||
val content: String = LyricUtil.getStringFromLrc(lrcFile)
|
|
||||||
|
|
||||||
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
||||||
title(res = R.string.edit_synced_lyrics)
|
title(res = R.string.edit_synced_lyrics)
|
||||||
|
@ -332,11 +326,8 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
|
||||||
|
|
||||||
fun loadLRCLyrics() {
|
fun loadLRCLyrics() {
|
||||||
binding.lyricsView.setLabel("Empty")
|
binding.lyricsView.setLabel("Empty")
|
||||||
val song = MusicPlayerRemote.currentSong
|
LyricUtil.getSyncedLyricsFile(MusicPlayerRemote.currentSong)?.let {
|
||||||
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
|
binding.lyricsView.loadLrc(it)
|
||||||
binding.lyricsView.loadLrc(LyricUtil.getLocalLyricOriginalFile(song.data))
|
|
||||||
} else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
|
|
||||||
binding.lyricsView.loadLrc(LyricUtil.getLocalLyricFile(song.title, song.artistName))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||||
import code.name.monkey.retromusic.lyrics.CoverLrcView
|
import code.name.monkey.retromusic.lyrics.CoverLrcView
|
||||||
|
@ -74,18 +73,16 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLyrics() {
|
private fun updateLyrics() {
|
||||||
binding.lyricsView.setLabel("Empty")
|
binding.lyricsView.setLabel(context?.getString(R.string.no_lyrics_found))
|
||||||
val song = MusicPlayerRemote.currentSong
|
val song = MusicPlayerRemote.currentSong
|
||||||
when {
|
val lrcFile = LyricUtil.getSyncedLyricsFile(song)
|
||||||
LyricUtil.isLrcOriginalFileExist(song.data) -> {
|
if (lrcFile != null) {
|
||||||
LyricUtil.getLocalLyricOriginalFile(song.data)
|
binding.lyricsView.loadLrc(lrcFile)
|
||||||
?.let { binding.lyricsView.loadLrc(it) }
|
} else {
|
||||||
}
|
val embeddedLyrics = LyricUtil.getEmbeddedSyncedLyrics(song.data)
|
||||||
LyricUtil.isLrcFileExist(song.title, song.artistName) -> {
|
if (embeddedLyrics != null) {
|
||||||
LyricUtil.getLocalLyricFile(song.title, song.artistName)
|
binding.lyricsView.loadLrc(embeddedLyrics)
|
||||||
?.let { binding.lyricsView.loadLrc(it) }
|
} else {
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
binding.lyricsView.reset()
|
binding.lyricsView.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,16 +123,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
|
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
|
||||||
// Don't show lyrics container for below conditions
|
maybeInitLyrics()
|
||||||
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
|
||||||
lrcView.isVisible = false
|
|
||||||
viewPager.isInvisible = false
|
|
||||||
progressViewUpdateHelper?.stop()
|
|
||||||
} else {
|
|
||||||
lrcView.isVisible = true
|
|
||||||
viewPager.isInvisible = true
|
|
||||||
progressViewUpdateHelper?.start()
|
|
||||||
}
|
|
||||||
lrcView.apply {
|
lrcView.apply {
|
||||||
setDraggable(true, object : CoverLrcView.OnPlayClickListener {
|
setDraggable(true, object : CoverLrcView.OnPlayClickListener {
|
||||||
override fun onPlayClick(time: Long): Boolean {
|
override fun onPlayClick(time: Long): Boolean {
|
||||||
|
@ -145,25 +133,11 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Go to lyrics activity when clicked lyrics
|
|
||||||
lrcView.setOnClickListener {
|
|
||||||
goToLyrics(requireActivity())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
val nps = PreferenceUtil.nowPlayingScreen
|
maybeInitLyrics()
|
||||||
// Don't show lyrics container for below conditions
|
|
||||||
if (nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics) {
|
|
||||||
lrcView.isVisible = false
|
|
||||||
viewPager.isInvisible = false
|
|
||||||
progressViewUpdateHelper?.stop()
|
|
||||||
} else {
|
|
||||||
lrcView.isVisible = true
|
|
||||||
viewPager.isInvisible = true
|
|
||||||
progressViewUpdateHelper?.start()
|
|
||||||
}
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
.registerOnSharedPreferenceChangeListener(this)
|
.registerOnSharedPreferenceChangeListener(this)
|
||||||
}
|
}
|
||||||
|
@ -194,22 +168,9 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
|
||||||
if (key == SHOW_LYRICS) {
|
if (key == SHOW_LYRICS) {
|
||||||
if (sharedPreferences.getBoolean(key, false)) {
|
if (sharedPreferences.getBoolean(key, false)) {
|
||||||
val nps = PreferenceUtil.nowPlayingScreen
|
maybeInitLyrics()
|
||||||
// Don't show lyrics container for below conditions
|
|
||||||
if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) {
|
|
||||||
lrcView.isVisible = true
|
|
||||||
viewPager.isInvisible = true
|
|
||||||
progressViewUpdateHelper?.start()
|
|
||||||
lrcView.animate().alpha(1f).duration =
|
|
||||||
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
|
||||||
} else {
|
} else {
|
||||||
lrcView.isVisible = false
|
showLyrics(false)
|
||||||
viewPager.isInvisible = false
|
|
||||||
progressViewUpdateHelper?.stop()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lrcView.isVisible = false
|
|
||||||
viewPager.isInvisible = false
|
|
||||||
progressViewUpdateHelper?.stop()
|
progressViewUpdateHelper?.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,6 +194,25 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showLyrics(visible: Boolean) {
|
||||||
|
lrcView.isVisible = visible
|
||||||
|
viewPager.isInvisible = visible
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeInitLyrics() {
|
||||||
|
val nps = PreferenceUtil.nowPlayingScreen
|
||||||
|
// Don't show lyrics container for below conditions
|
||||||
|
if (nps != Circle && nps != Peak && nps != Tiny && PreferenceUtil.showLyrics) {
|
||||||
|
showLyrics(true)
|
||||||
|
progressViewUpdateHelper?.start()
|
||||||
|
lrcView.animate().alpha(1f).duration =
|
||||||
|
AbsPlayerFragment.VISIBILITY_ANIM_DURATION
|
||||||
|
} else {
|
||||||
|
showLyrics(false)
|
||||||
|
progressViewUpdateHelper?.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updatePlayingQueue() {
|
private fun updatePlayingQueue() {
|
||||||
binding.viewPager.apply {
|
binding.viewPager.apply {
|
||||||
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
|
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
|
||||||
|
@ -266,15 +246,17 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
callbacks?.onColorChanged(color)
|
callbacks?.onColorChanged(color)
|
||||||
setLRCViewColors(
|
setLRCViewColors(
|
||||||
when (PreferenceUtil.nowPlayingScreen) {
|
when (PreferenceUtil.nowPlayingScreen) {
|
||||||
|
Adaptive, Fit, Plain, Simple -> surfaceColor()
|
||||||
Flat, Normal -> if (PreferenceUtil.isAdaptiveColor) {
|
Flat, Normal -> if (PreferenceUtil.isAdaptiveColor) {
|
||||||
color.backgroundColor
|
color.backgroundColor
|
||||||
} else {
|
} else {
|
||||||
surfaceColor()
|
surfaceColor()
|
||||||
}
|
}
|
||||||
Color, Gradient, Full ->color.backgroundColor
|
Color -> color.backgroundColor
|
||||||
Blur -> Color.BLACK
|
Blur -> Color.BLACK
|
||||||
else -> surfaceColor()
|
else -> color.backgroundColor
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setCallbacks(listener: Callbacks) {
|
fun setCallbacks(listener: Callbacks) {
|
||||||
|
|
|
@ -91,10 +91,10 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
private val mSimpleOnGestureListener: SimpleOnGestureListener =
|
private val mSimpleOnGestureListener: SimpleOnGestureListener =
|
||||||
object : SimpleOnGestureListener() {
|
object : SimpleOnGestureListener() {
|
||||||
override fun onDown(e: MotionEvent): Boolean {
|
override fun onDown(e: MotionEvent): Boolean {
|
||||||
|
if (hasLrc() && mOnPlayClickListener != null) {
|
||||||
if (mOffset != getOffset(0)) {
|
if (mOffset != getOffset(0)) {
|
||||||
parent.requestDisallowInterceptTouchEvent(true)
|
parent.requestDisallowInterceptTouchEvent(true)
|
||||||
}
|
}
|
||||||
if (hasLrc() && mOnPlayClickListener != null) {
|
|
||||||
mScroller!!.forceFinished(true)
|
mScroller!!.forceFinished(true)
|
||||||
removeCallbacks(hideTimelineRunnable)
|
removeCallbacks(hideTimelineRunnable)
|
||||||
isTouching = true
|
isTouching = true
|
||||||
|
@ -336,7 +336,7 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
* @param mainLrcFile 第一种语言歌词文件
|
* @param mainLrcFile 第一种语言歌词文件
|
||||||
* @param secondLrcFile 第二种语言歌词文件
|
* @param secondLrcFile 第二种语言歌词文件
|
||||||
*/
|
*/
|
||||||
fun loadLrc(mainLrcFile: File, secondLrcFile: File?) {
|
private fun loadLrc(mainLrcFile: File, secondLrcFile: File?) {
|
||||||
runOnUi {
|
runOnUi {
|
||||||
reset()
|
reset()
|
||||||
val sb = StringBuilder("file://")
|
val sb = StringBuilder("file://")
|
||||||
|
@ -352,7 +352,7 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
||||||
if (flag === flag) {
|
if (flag == flag) {
|
||||||
onLrcLoaded(lrcEntries)
|
onLrcLoaded(lrcEntries)
|
||||||
this@CoverLrcView.flag = null
|
this@CoverLrcView.flag = null
|
||||||
}
|
}
|
||||||
|
@ -376,7 +376,7 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
* @param mainLrcText 第一种语言歌词文本
|
* @param mainLrcText 第一种语言歌词文本
|
||||||
* @param secondLrcText 第二种语言歌词文本
|
* @param secondLrcText 第二种语言歌词文本
|
||||||
*/
|
*/
|
||||||
fun loadLrc(mainLrcText: String?, secondLrcText: String?) {
|
private fun loadLrc(mainLrcText: String?, secondLrcText: String?) {
|
||||||
runOnUi {
|
runOnUi {
|
||||||
reset()
|
reset()
|
||||||
val sb = StringBuilder("file://")
|
val sb = StringBuilder("file://")
|
||||||
|
@ -392,7 +392,7 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
||||||
if (flag === flag) {
|
if (flag == flag) {
|
||||||
onLrcLoaded(lrcEntries)
|
onLrcLoaded(lrcEntries)
|
||||||
this@CoverLrcView.flag = null
|
this@CoverLrcView.flag = null
|
||||||
}
|
}
|
||||||
|
@ -400,12 +400,7 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
}.execute(mainLrcText, secondLrcText)
|
}.execute(mainLrcText, secondLrcText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 加载在线歌词
|
|
||||||
*
|
|
||||||
* @param lrcUrl 歌词文件的网络地址
|
|
||||||
* @param charset 编码格式
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* 加载在线歌词,默认使用 utf-8 编码
|
* 加载在线歌词,默认使用 utf-8 编码
|
||||||
*
|
*
|
||||||
|
@ -421,7 +416,7 @@ class CoverLrcView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPostExecute(lrcText: String) {
|
override fun onPostExecute(lrcText: String) {
|
||||||
if (flag === flag) {
|
if (flag == flag) {
|
||||||
loadLrc(lrcText)
|
loadLrc(lrcText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,189 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.util;
|
|
||||||
|
|
||||||
import android.util.Base64;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by hefuyi on 2016/11/8.
|
|
||||||
*/
|
|
||||||
public class LyricUtil {
|
|
||||||
|
|
||||||
private static final String lrcRootPath =
|
|
||||||
android.os.Environment.getExternalStorageDirectory().toString() + "/RetroMusic/lyrics/";
|
|
||||||
private static final String TAG = "LyricUtil";
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static File writeLrcToLoc(
|
|
||||||
@NonNull String title, @NonNull String artist, @NonNull String lrcContext) {
|
|
||||||
FileWriter writer = null;
|
|
||||||
try {
|
|
||||||
File file = new File(getLrcPath(title, artist));
|
|
||||||
if (!file.getParentFile().exists()) {
|
|
||||||
file.getParentFile().mkdirs();
|
|
||||||
}
|
|
||||||
writer = new FileWriter(getLrcPath(title, artist));
|
|
||||||
writer.write(lrcContext);
|
|
||||||
return file;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (writer != null) writer.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//So in Retro, Lrc file can be same folder as Music File or in RetroMusic Folder
|
|
||||||
// In this case we pass location of the file and Contents to write to file
|
|
||||||
public static void writeLrc(@NonNull Song song, @NonNull String lrcContext) {
|
|
||||||
FileWriter writer = null;
|
|
||||||
File location;
|
|
||||||
try {
|
|
||||||
if (isLrcOriginalFileExist(song.getData())) {
|
|
||||||
location = getLocalLyricOriginalFile(song.getData());
|
|
||||||
} else if (isLrcFileExist(song.getTitle(), song.getArtistName())) {
|
|
||||||
location = getLocalLyricFile(song.getTitle(), song.getArtistName());
|
|
||||||
} else {
|
|
||||||
location = new File(getLrcPath(song.getTitle(), song.getArtistName()));
|
|
||||||
if (!location.getParentFile().exists()) {
|
|
||||||
location.getParentFile().mkdirs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writer = new FileWriter(location);
|
|
||||||
writer.write(lrcContext);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (writer != null) writer.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean deleteLrcFile(@NonNull String title, @NonNull String artist) {
|
|
||||||
File file = new File(getLrcPath(title, artist));
|
|
||||||
return file.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLrcFileExist(@NonNull String title, @NonNull String artist) {
|
|
||||||
File file = new File(getLrcPath(title, artist));
|
|
||||||
return file.exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLrcOriginalFileExist(@NonNull String path) {
|
|
||||||
File file = new File(getLrcOriginalPath(path));
|
|
||||||
return file.exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static File getLocalLyricFile(@NonNull String title, @NonNull String artist) {
|
|
||||||
File file = new File(getLrcPath(title, artist));
|
|
||||||
if (file.exists()) {
|
|
||||||
return file;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static File getLocalLyricOriginalFile(@NonNull String path) {
|
|
||||||
File file = new File(getLrcOriginalPath(path));
|
|
||||||
if (file.exists()) {
|
|
||||||
return file;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getLrcPath(String title, String artist) {
|
|
||||||
return lrcRootPath + title + " - " + artist + ".lrc";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getLrcOriginalPath(String filePath) {
|
|
||||||
return filePath.replace(filePath.substring(filePath.lastIndexOf(".") + 1), "lrc");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String decryptBASE64(@NonNull String str) {
|
|
||||||
if (str == null || str.length() == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
byte[] encode = str.getBytes(StandardCharsets.UTF_8);
|
|
||||||
// base64 解密
|
|
||||||
return new String(
|
|
||||||
Base64.decode(encode, 0, encode.length, Base64.DEFAULT), StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getStringFromFile(@NonNull String title, @NonNull String artist)
|
|
||||||
throws Exception {
|
|
||||||
File file = new File(getLrcPath(title, artist));
|
|
||||||
FileInputStream fin = new FileInputStream(file);
|
|
||||||
String ret = convertStreamToString(fin);
|
|
||||||
fin.close();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String convertStreamToString(InputStream is) throws Exception {
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
sb.append(line).append("\n");
|
|
||||||
}
|
|
||||||
reader.close();
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getStringFromLrc(File file) {
|
|
||||||
try {
|
|
||||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
sb.append(line).append("\n");
|
|
||||||
}
|
|
||||||
reader.close();
|
|
||||||
return sb.toString();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.i("Error", "Error Occurred");
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
188
app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt
Normal file
188
app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Hemanth Savarala.
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License v3
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
package code.name.monkey.retromusic.util
|
||||||
|
|
||||||
|
import android.os.Environment
|
||||||
|
import android.util.Log
|
||||||
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
|
||||||
|
import org.jaudiotagger.audio.AudioFileIO
|
||||||
|
import org.jaudiotagger.tag.FieldKey
|
||||||
|
import java.io.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by hefuyi on 2016/11/8.
|
||||||
|
*/
|
||||||
|
object LyricUtil {
|
||||||
|
private val lrcRootPath =
|
||||||
|
Environment.getExternalStorageDirectory().toString() + "/RetroMusic/lyrics/"
|
||||||
|
private const val TAG = "LyricUtil"
|
||||||
|
fun writeLrcToLoc(
|
||||||
|
title: String, artist: String, lrcContext: String
|
||||||
|
): File? {
|
||||||
|
var writer: FileWriter? = null
|
||||||
|
return try {
|
||||||
|
val file = File(getLrcPath(title, artist))
|
||||||
|
if (file.parentFile?.exists() != true) {
|
||||||
|
file.parentFile?.mkdirs()
|
||||||
|
}
|
||||||
|
writer = FileWriter(getLrcPath(title, artist))
|
||||||
|
writer.write(lrcContext)
|
||||||
|
file
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
writer?.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//So in Retro, Lrc file can be same folder as Music File or in RetroMusic Folder
|
||||||
|
// In this case we pass location of the file and Contents to write to file
|
||||||
|
fun writeLrc(song: Song, lrcContext: String) {
|
||||||
|
var writer: FileWriter? = null
|
||||||
|
val location: File?
|
||||||
|
try {
|
||||||
|
if (isLrcOriginalFileExist(song.data)) {
|
||||||
|
location = getLocalLyricOriginalFile(song.data)
|
||||||
|
} else if (isLrcFileExist(song.title, song.artistName)) {
|
||||||
|
location = getLocalLyricFile(song.title, song.artistName)
|
||||||
|
} else {
|
||||||
|
location = File(getLrcPath(song.title, song.artistName))
|
||||||
|
if (location.parentFile?.exists() != true) {
|
||||||
|
location.parentFile?.mkdirs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer = FileWriter(location)
|
||||||
|
writer.write(lrcContext)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
writer?.close()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteLrcFile(title: String, artist: String): Boolean {
|
||||||
|
val file = File(getLrcPath(title, artist))
|
||||||
|
return file.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isLrcFileExist(title: String, artist: String): Boolean {
|
||||||
|
val file = File(getLrcPath(title, artist))
|
||||||
|
return file.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isLrcOriginalFileExist(path: String): Boolean {
|
||||||
|
val file = File(getLrcOriginalPath(path))
|
||||||
|
return file.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLocalLyricFile(title: String, artist: String): File? {
|
||||||
|
val file = File(getLrcPath(title, artist))
|
||||||
|
return if (file.exists()) {
|
||||||
|
file
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLocalLyricOriginalFile(path: String): File? {
|
||||||
|
val file = File(getLrcOriginalPath(path))
|
||||||
|
return if (file.exists()) {
|
||||||
|
file
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLrcPath(title: String, artist: String): String {
|
||||||
|
return "$lrcRootPath$title - $artist.lrc"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLrcOriginalPath(filePath: String): String {
|
||||||
|
return filePath.replace(filePath.substring(filePath.lastIndexOf(".") + 1), "lrc")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun getStringFromFile(title: String, artist: String): String {
|
||||||
|
val file = File(getLrcPath(title, artist))
|
||||||
|
val fin = FileInputStream(file)
|
||||||
|
val ret = convertStreamToString(fin)
|
||||||
|
fin.close()
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
private fun convertStreamToString(`is`: InputStream): String {
|
||||||
|
val reader = BufferedReader(InputStreamReader(`is`))
|
||||||
|
val sb = StringBuilder()
|
||||||
|
var line: String?
|
||||||
|
while (reader.readLine().also { line = it } != null) {
|
||||||
|
sb.append(line).append("\n")
|
||||||
|
}
|
||||||
|
reader.close()
|
||||||
|
return sb.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStringFromLrc(file: File?): String {
|
||||||
|
try {
|
||||||
|
val reader = BufferedReader(FileReader(file))
|
||||||
|
val sb = StringBuilder()
|
||||||
|
var line: String?
|
||||||
|
while (reader.readLine().also { line = it } != null) {
|
||||||
|
sb.append(line).append("\n")
|
||||||
|
}
|
||||||
|
reader.close()
|
||||||
|
return sb.toString()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.i("Error", "Error Occurred")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSyncedLyricsFile(song: Song): File? {
|
||||||
|
return when {
|
||||||
|
isLrcOriginalFileExist(song.data) -> {
|
||||||
|
getLocalLyricOriginalFile(song.data)
|
||||||
|
}
|
||||||
|
isLrcFileExist(song.title, song.artistName) -> {
|
||||||
|
getLocalLyricFile(song.title, song.artistName)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEmbeddedSyncedLyrics(data: String): String? {
|
||||||
|
val embeddedLyrics = try{
|
||||||
|
AudioFileIO.read(File(data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS)
|
||||||
|
} catch(e: Exception){
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return if (AbsSynchronizedLyrics.isSynchronized(embeddedLyrics)) {
|
||||||
|
embeddedLyrics
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,17 +66,21 @@
|
||||||
android:orderInCategory="10"
|
android:orderInCategory="10"
|
||||||
android:title="@string/action_details" />
|
android:title="@string/action_details" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_sleep_timer"
|
android:id="@+id/action_go_to_lyrics"
|
||||||
android:orderInCategory="11"
|
android:orderInCategory="11"
|
||||||
|
android:title="@string/action_go_to_lyrics" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sleep_timer"
|
||||||
|
android:orderInCategory="12"
|
||||||
android:title="@string/action_sleep_timer"
|
android:title="@string/action_sleep_timer"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_equalizer"
|
android:id="@+id/action_equalizer"
|
||||||
android:orderInCategory="12"
|
android:orderInCategory="13"
|
||||||
android:title="@string/equalizer"
|
android:title="@string/equalizer"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_delete_from_device"
|
android:id="@+id/action_delete_from_device"
|
||||||
android:orderInCategory="13"
|
android:orderInCategory="14"
|
||||||
android:title="@string/action_delete_from_device" />
|
android:title="@string/action_delete_from_device" />
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
<string name="action_go_to_album">Go to album</string>
|
<string name="action_go_to_album">Go to album</string>
|
||||||
<string name="action_go_to_artist">Go to artist</string>
|
<string name="action_go_to_artist">Go to artist</string>
|
||||||
<string name="action_go_to_genre">Go to genre</string>
|
<string name="action_go_to_genre">Go to genre</string>
|
||||||
|
<string name="action_go_to_lyrics">Go to Lyrics</string>
|
||||||
<string name="action_go_to_start_directory">Go to start directory</string>
|
<string name="action_go_to_start_directory">Go to start directory</string>
|
||||||
<string name="action_grant">Grant</string>
|
<string name="action_grant">Grant</string>
|
||||||
<string name="action_grid_size">Grid size</string>
|
<string name="action_grid_size">Grid size</string>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue