Skip to content

Commit

Permalink
还原歌词控件;优化本地歌词搜索与翻译解析
Browse files Browse the repository at this point in the history
  • Loading branch information
rRemix committed Mar 15, 2019
1 parent 5035ec3 commit 8906225
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 158 deletions.
14 changes: 7 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ android {
applicationId "remix.myplayer"
minSdkVersion 17
targetSdkVersion 26
versionCode 1510
versionName "1.5.1.0"
versionCode 1511
versionName "1.5.1.1-debug"

flavorDimensions "default"
vectorDrawables.useSupportLibrary = true
ndk {
abiFilters 'armeabi-v7a'
// abiFilters 'armeabi-v7a', 'x86'
// abiFilters 'armeabi-v7a'
abiFilters 'armeabi-v7a', 'x86'
}
externalNativeBuild {
cmake {
Expand Down Expand Up @@ -184,7 +184,7 @@ dependencies {

//rx
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.5'
implementation 'io.reactivex.rxjava2:rxjava:2.2.6'

//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
Expand All @@ -204,8 +204,8 @@ dependencies {
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'

//butterKnife
implementation 'com.jakewharton:butterknife:8.8.1'
kapt 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.jakewharton:butterknife:9.0.0'
kapt 'com.jakewharton:butterknife-compiler:9.0.0'

//bugly
implementation 'com.tencent.bugly:crashreport:2.8.6.0'
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/remix/myplayer/bean/mp3/Song.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.MediaStore;
import java.io.File;
import remix.myplayer.App;
import remix.myplayer.util.SPUtil;
import timber.log.Timber;
Expand Down Expand Up @@ -204,6 +205,10 @@ public long getDuration() {
if (Duration <= 0) {
IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
try {
File file = new File(Url);
if(!file.exists()){
return Duration;
}
ijkMediaPlayer.setDataSource(Url);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
ijkMediaPlayer.prepareAsync();
Expand All @@ -220,7 +225,6 @@ public long getDuration() {
}
} catch (Exception e) {
Timber.v(e);
e.printStackTrace();
}
}
return Duration;
Expand Down
16 changes: 9 additions & 7 deletions app/src/main/java/remix/myplayer/lyric/DefaultLrcParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,27 @@ class DefaultLrcParser : ILrcParser {
//合并翻译
val combineLrcRows = ArrayList<LrcRow>()
var index = 0
while (index < lrcRows.size - 1){
//判断下一句歌词和当前歌词的时间是否一致,一致则认为下一句是当前歌词的翻译
while (index < lrcRows.size - 1) {
// 判断下一句歌词和当前歌词的时间是否一致,一致则认为下一句是当前歌词的翻译
val currentRow = lrcRows[index]
val nextRow = lrcRows[index + 1]
if(currentRow.time == nextRow.time){
if (currentRow.time == nextRow.time) { // 带翻译的歌词
val tmp = LrcRow()
tmp.content = currentRow.content
tmp.time = currentRow.time
tmp.timeStr = currentRow.timeStr
tmp.translate = nextRow.content
combineLrcRows.add(tmp)
index++
} else { // 普通歌词
combineLrcRows.add(currentRow)
}
index++
}
if(combineLrcRows.size.toFloat() / lrcRows.size >= THRESHOLD_PROPORTION){
lrcRows.clear()
lrcRows.addAll(combineLrcRows)
}
// if(combineLrcRows.size.toFloat() / lrcRows.size >= THRESHOLD_PROPORTION){
lrcRows.clear()
lrcRows.addAll(combineLrcRows)
// }


if (lrcRows.size == 0)
Expand Down
42 changes: 3 additions & 39 deletions app/src/main/java/remix/myplayer/lyric/LrcView.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.provider.CalendarContract.CalendarAlerts;
import android.support.annotation.ColorInt;
import android.support.annotation.StringRes;
import android.text.Layout;
Expand Down Expand Up @@ -283,34 +282,14 @@ protected void onDraw(Canvas canvas) {
* 分割绘制歌词
*/
private void drawLrcRow(Canvas canvas, TextPaint textPaint, int availableWidth, LrcRow lrcRow) {
drawText(canvas, textPaint, availableWidth, lrcRow.getContent());
if (lrcRow.hasTranslate()) {
drawTextWithTranslate(canvas, textPaint, availableWidth, lrcRow.getContent());
if (lrcRow.hasTranslate()) {
drawTextWithTranslate(canvas, textPaint, availableWidth, lrcRow.getTranslate());
}
} else {
drawText(canvas, textPaint, availableWidth, lrcRow.getContent());
// mRowY += DEFAULT_SPACING_PADDING;
drawText(canvas, textPaint, availableWidth, lrcRow.getTranslate());
}

mRowY += mLinePadding;
}

/**
* 分割绘制歌词
*/
private void drawTextTemp(Canvas canvas, TextPaint textPaint, int availableWidth, String text) {
StaticLayout staticLayout = new StaticLayout(text, textPaint, availableWidth,
Layout.Alignment.ALIGN_CENTER,
DEFAULT_SPACING_MULTI, 0, true);
final int extra = staticLayout.getLineCount() > 1 ? DensityUtil.dip2px(getContext(), 10) : 0;
canvas.save();
canvas.translate(getPaddingLeft(), mRowY - staticLayout.getHeight() / 2 + extra);
staticLayout.draw(canvas);
canvas.restore();
mRowY += staticLayout.getHeight();
}


/**
* 分割绘制歌词
*/
Expand All @@ -326,21 +305,6 @@ private void drawText(Canvas canvas, TextPaint textPaint, int availableWidth, St
mRowY += staticLayout.getHeight();
}

/**
* 分割绘制歌词
*/
private void drawTextWithTranslate(Canvas canvas, TextPaint textPaint, int availableWidth, String text) {
StaticLayout staticLayout = new StaticLayout(text, textPaint, availableWidth,
Layout.Alignment.ALIGN_CENTER,
DEFAULT_SPACING_MULTI, 0, true);
final int extra = staticLayout.getLineCount() > 1 ? DensityUtil.dip2px(getContext(), 10) : 0;
canvas.save();
canvas.translate(getPaddingLeft(), mRowY - staticLayout.getHeight() + extra);
staticLayout.draw(canvas);
canvas.restore();
mRowY += staticLayout.getHeight();
}

/**
* 是否可拖动歌词
**/
Expand Down
145 changes: 41 additions & 104 deletions app/src/main/java/remix/myplayer/lyric/LyricSearcher.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.util.Base64
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.functions.Function
import org.jaudiotagger.tag.FieldKey
import remix.myplayer.App
Expand Down Expand Up @@ -42,7 +43,6 @@ class LyricSearcher {
private var displayName: String? = null
private var cacheKey: String? = null
private var searchKey: String? = null
private var localLyricPath: String = ""

init {
lrcParser = DefaultLrcParser()
Expand Down Expand Up @@ -80,8 +80,8 @@ class LyricSearcher {

val observable = when (type) {
SPUtil.LYRIC_KEY.LYRIC_IGNORE -> {
Timber.v("Ignore Lyric")
Observable.error(Throwable("Ignore Lyric"))
Timber.v("ignore lyric")
Observable.error(Throwable("ignore lyric"))
}
SPUtil.LYRIC_KEY.LYRIC_EMBEDDED -> {
getEmbeddedObservable()
Expand Down Expand Up @@ -115,15 +115,14 @@ class LyricSearcher {
Observable.concat(observables).firstOrError().toObservable()
}
else -> {
Observable.error<List<LrcRow>>(Throwable("Not support type"))
Observable.error<List<LrcRow>>(Throwable("unknown type"))
}
}

return if (isTypeAvailable(type)) Observable.concat(getCacheObservable(), observable)
.firstOrError()
.toObservable()
.doOnSubscribe { disposable ->
localLyricPath = ""
cacheKey = Util.hashKeyForDisk(song.id.toString() + "-" +
(if (!TextUtils.isEmpty(song.artist)) song.artist else "") + "-" +
if (!TextUtils.isEmpty(song.title)) song.title else "")
Expand Down Expand Up @@ -160,7 +159,8 @@ class LyricSearcher {
return Observable.create { e ->
val lyric = tagEditor.getFieldValueSingle(FieldKey.LYRICS).blockingGet()
if (!lyric.isNullOrEmpty()) {
e.onNext(lrcParser.getLrcRows(getBufferReader(lyric!!.toByteArray(UTF_8)), true, cacheKey, searchKey))
e.onNext(lrcParser.getLrcRows(getBufferReader(lyric?.toByteArray(UTF_8) ?: return@create),
true, cacheKey, searchKey))
Timber.v("EmbeddedLyric")
}
e.onComplete()
Expand Down Expand Up @@ -190,59 +190,28 @@ class LyricSearcher {
/**
* 搜索本地所有歌词文件
*/
private val allLocalLrcPath: List<String>
get() {
val results = ArrayList<String>()
// val searchPath = SPUtil.getValue(App.getContext(), SPUtil.SETTING_KEY.NAME, SPUtil.SETTING_KEY.LOCAL_LYRIC_SEARCH_DIR, "")
//没有设置歌词路径 搜索所有可能的歌词文件
App.getContext().contentResolver.query(MediaStore.Files.getContentUri("external"), null,
MediaStore.Files.FileColumns.DATA + " like ? or " +
MediaStore.Files.FileColumns.DATA + " like ? or " +
MediaStore.Files.FileColumns.DATA + " like ? or " +
MediaStore.Files.FileColumns.DATA + " like ? ",
getLocalSearchKey(),
null)
.use { filesCursor ->
while (filesCursor.moveToNext()) {
val file = File(filesCursor.getString(filesCursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)))
Timber.v("file: %s", file.absolutePath)
if (file.exists() && file.isFile && file.canRead()) {
//非翻译文件只保留一个
if (results.isEmpty() || (results.size >= 1 && file.absolutePath.contains("translate")))
results.add(file.absolutePath)
}
if (results.size == 2)
break
private fun getLocalLyricPath(): String? {
var path = ""
//没有设置歌词路径 搜索所有可能的歌词文件
App.getContext().contentResolver.query(MediaStore.Files.getContentUri("external"), null,
MediaStore.Files.FileColumns.DATA + " like ? or " +
MediaStore.Files.FileColumns.DATA + " like ? or " +
MediaStore.Files.FileColumns.DATA + " like ? or " +
MediaStore.Files.FileColumns.DATA + " like ? ",
getLocalSearchKey(),
null)
.use { filesCursor ->
while (filesCursor.moveToNext()) {
val file = File(filesCursor.getString(filesCursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)))
Timber.v("file: %s", file.absolutePath)
if (file.exists() && file.isFile && file.canRead()) {
path = file.absolutePath
}
return results
}
// if (!TextUtils.isEmpty(searchPath)) {//已设置歌词搜索路径
// localLyricPath = LyricUtil.searchLyric(displayName, song.title, song.artist, File(searchPath))
// if (!TextUtils.isEmpty(localLyricPath))
// results.add(localLyricPath)
// return results
// } else {
// //没有设置歌词路径 搜索所有可能的歌词文件
// App.getContext().contentResolver.query(MediaStore.Files.getContentUri("external"), null,
// MediaStore.Files.FileColumns.DATA + " like ? or " +
// MediaStore.Files.FileColumns.DATA + " like ? or " +
// MediaStore.Files.FileColumns.DATA + " like ? or " +
// MediaStore.Files.FileColumns.DATA + " like ? ",
// getLocalSearchKey(),
// null)
// .use { filesCursor ->
// while (filesCursor.moveToNext()) {
// val file = File(filesCursor.getString(filesCursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)))
// LogUtil.d(TAG,"file: " + file.absolutePath)
// if (file.exists() && file.isFile && file.canRead()) {
// results.add(file.absolutePath)
// }
// }
// return results
// }
// }

}
}
return path
}
}

/**
* @param searchPath 设置的本地歌词搜索路径
Expand All @@ -253,10 +222,10 @@ class LyricSearcher {
* aritst-displayName.lrc
*/
private fun getLocalSearchKey(searchPath: String? = null): Array<String> {
return arrayOf("%$displayName%$SUFFIX_LYRIC",
"%" + song.title + "%" + SUFFIX_LYRIC,
"%" + song.Artist + "%" + song.Title + "%" + SUFFIX_LYRIC,
"%" + song.Artist + "%" + displayName + "%" + SUFFIX_LYRIC)
return arrayOf("%$displayName$SUFFIX_LYRIC",
"%${song.title}$SUFFIX_LYRIC",
"%${song.artist}%${song.title}$SUFFIX_LYRIC",
"%${song.artist}$displayName$SUFFIX_LYRIC")
}

/**
Expand Down Expand Up @@ -295,47 +264,15 @@ class LyricSearcher {
* @return
*/
private fun getLocalObservable(): Observable<List<LrcRow>> {
return Observable.create { e ->
val localPaths = ArrayList<String>(allLocalLrcPath)
if (localPaths.isEmpty()) {
e.onComplete()
return@create
}
if (localPaths.size > 1 && isCN) {
var localPath = ""
var translatePath: String? = null
for (path in localPaths) {
if (path.contains("translate") && path != localPath) {
translatePath = path
} else {
localPath = path
return Observable
.create<List<LrcRow>> { emitter ->
val path = getLocalLyricPath()
if (path != null && path.isNotEmpty()) {
Timber.v("LocalLyric")
emitter.onNext(lrcParser.getLrcRows(getBufferReader(path), true, cacheKey, searchKey))
}
emitter.onComplete()
}
Timber.v("LocalLyric")
if (translatePath == null) {
e.onNext(lrcParser.getLrcRows(getBufferReader(localPath), true, cacheKey, searchKey))
} else {
//合并歌词
val source = lrcParser.getLrcRows(getBufferReader(localPath), false, cacheKey, searchKey)
val translate = lrcParser.getLrcRows(getBufferReader(translatePath), false, cacheKey, searchKey)
if (translate != null && translate.size > 0) {
for (i in translate.indices) {
for (j in source.indices) {
if (isTranslateCanUse(translate[i].content) && translate[i].time == source[j].time) {
source[j].translate = translate[i].content
break
}
}
}
lrcParser.saveLrcRows(source, cacheKey, searchKey)
e.onNext(source)
}
}
} else {
e.onNext(lrcParser.getLrcRows(getBufferReader(localPaths[0]), true, cacheKey, searchKey))
}
e.onComplete()
}
}

/**
Expand All @@ -344,7 +281,7 @@ class LyricSearcher {
private fun getNeteaseObservable(): Observable<List<LrcRow>> {
return HttpClient.getNeteaseApiservice()
.getNeteaseSearch(searchKey, 0, 1, 1)
.flatMap { it ->
.flatMap {
HttpClient.getInstance()
.getNeteaseLyric(Gson().fromJson(it.string(), NSongSearchResponse::class.java).result.songs[0].id)
.map {
Expand Down Expand Up @@ -409,12 +346,12 @@ class LyricSearcher {
}
if (newType == SPUtil.LYRIC_KEY.LYRIC_DEFAULT)
newType = SPUtil.LYRIC_KEY.LYRIC_NETEASE
if (newType == SPUtil.LYRIC_KEY.LYRIC_KUGOU) {
return if (newType == SPUtil.LYRIC_KEY.LYRIC_KUGOU) {
//酷狗歌词
return getKuGouObservable()
getKuGouObservable()
} else {
//网易歌词
return getNeteaseObservable()
getNeteaseObservable()
}
}

Expand Down

0 comments on commit 8906225

Please sign in to comment.