PlayerAndroid/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcUtils.java

233 lines
7.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (C) 2017 wangchenyan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package code.name.monkey.retromusic.lyrics;
import android.animation.ValueAnimator;
import android.text.TextUtils;
import android.text.format.DateUtils;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 工具类
*/
class LrcUtils {
private static final Pattern PATTERN_LINE = Pattern.compile("((\\[\\d\\d:\\d\\d\\.\\d{2,3}\\])+)(.+)");
private static final Pattern PATTERN_TIME = Pattern.compile("\\[(\\d\\d):(\\d\\d)\\.(\\d{2,3})\\]");
/**
* 从文件解析双语歌词
*/
static List<LrcEntry> parseLrc(File[] lrcFiles) {
if (lrcFiles == null || lrcFiles.length != 2 || lrcFiles[0] == null) {
return null;
}
File mainLrcFile = lrcFiles[0];
File secondLrcFile = lrcFiles[1];
List<LrcEntry> mainEntryList = parseLrc(mainLrcFile);
List<LrcEntry> secondEntryList = parseLrc(secondLrcFile);
if (mainEntryList != null && secondEntryList != null) {
for (LrcEntry mainEntry : mainEntryList) {
for (LrcEntry secondEntry : secondEntryList) {
if (mainEntry.getTime() == secondEntry.getTime()) {
mainEntry.setSecondText(secondEntry.getText());
}
}
}
}
return mainEntryList;
}
/**
* 从文件解析歌词
*/
private static List<LrcEntry> parseLrc(File lrcFile) {
if (lrcFile == null || !lrcFile.exists()) {
return null;
}
List<LrcEntry> entryList = new ArrayList<>();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(lrcFile), StandardCharsets.UTF_8));
String line;
while ((line = br.readLine()) != null) {
List<LrcEntry> list = parseLine(line);
if (list != null && !list.isEmpty()) {
entryList.addAll(list);
}
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
Collections.sort(entryList);
return entryList;
}
/**
* 从文本解析双语歌词
*/
static List<LrcEntry> parseLrc(String[] lrcTexts) {
if (lrcTexts == null || lrcTexts.length != 2 || TextUtils.isEmpty(lrcTexts[0])) {
return null;
}
String mainLrcText = lrcTexts[0];
String secondLrcText = lrcTexts[1];
List<LrcEntry> mainEntryList = parseLrc(mainLrcText);
List<LrcEntry> secondEntryList = parseLrc(secondLrcText);
if (mainEntryList != null && secondEntryList != null) {
for (LrcEntry mainEntry : mainEntryList) {
for (LrcEntry secondEntry : secondEntryList) {
if (mainEntry.getTime() == secondEntry.getTime()) {
mainEntry.setSecondText(secondEntry.getText());
}
}
}
}
return mainEntryList;
}
/**
* 从文本解析歌词
*/
private static List<LrcEntry> parseLrc(String lrcText) {
if (TextUtils.isEmpty(lrcText)) {
return null;
}
if (lrcText.startsWith("\uFEFF")) {
lrcText = lrcText.replace("\uFEFF", "");
}
List<LrcEntry> entryList = new ArrayList<>();
String[] array = lrcText.split("\\n");
for (String line : array) {
List<LrcEntry> list = parseLine(line);
if (list != null && !list.isEmpty()) {
entryList.addAll(list);
}
}
Collections.sort(entryList);
return entryList;
}
/**
* 获取网络文本,需要在工作线程中执行
*/
static String getContentFromNetwork(String url, String charset) {
String lrcText = null;
try {
URL _url = new URL(url);
HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
is.close();
bos.close();
lrcText = bos.toString(charset);
}
} catch (Exception e) {
e.printStackTrace();
}
return lrcText;
}
/**
* 解析一行歌词
*/
private static List<LrcEntry> parseLine(String line) {
if (TextUtils.isEmpty(line)) {
return null;
}
line = line.trim();
// [00:17.65]让我掉下眼泪的
Matcher lineMatcher = PATTERN_LINE.matcher(line);
if (!lineMatcher.matches()) {
return null;
}
String times = lineMatcher.group(1);
String text = lineMatcher.group(3);
List<LrcEntry> entryList = new ArrayList<>();
// [00:17.65]
Matcher timeMatcher = PATTERN_TIME.matcher(times);
while (timeMatcher.find()) {
long min = Long.parseLong(timeMatcher.group(1));
long sec = Long.parseLong(timeMatcher.group(2));
String milString = timeMatcher.group(3);
long mil = Long.parseLong(milString);
// 如果毫秒是两位数需要乘以10
if (milString.length() == 2) {
mil = mil * 10;
}
long time = min * DateUtils.MINUTE_IN_MILLIS + sec * DateUtils.SECOND_IN_MILLIS + mil;
entryList.add(new LrcEntry(time, text));
}
return entryList;
}
/**
* 转为[分:秒]
*/
static String formatTime(long milli) {
int m = (int) (milli / DateUtils.MINUTE_IN_MILLIS);
int s = (int) ((milli / DateUtils.SECOND_IN_MILLIS) % 60);
String mm = String.format(Locale.getDefault(), "%02d", m);
String ss = String.format(Locale.getDefault(), "%02d", s);
return mm + ":" + ss;
}
static void resetDurationScale() {
try {
Field mField = ValueAnimator.class.getDeclaredField("sDurationScale");
mField.setAccessible(true);
mField.setFloat(null, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
}