();
117 | int index = 0;
118 |
119 | // 获取歌词内容
120 | String lrcContents[] = lrcContent.split("\n");
121 | for (int i = 0; i < lrcContents.length; i++) {
122 | String lineInfo = lrcContents[i];
123 |
124 | // 行读取,并解析每行歌词的内容
125 | LyricsLineInfo lyricsLineInfo = parserLineInfos(lyricsTags,
126 | lineInfo);
127 | if (lyricsLineInfo != null) {
128 | lyricsLineInfos.put(index, lyricsLineInfo);
129 | index++;
130 | }
131 | }
132 |
133 | // 设置歌词的标签类
134 | lyricsIfno.setLyricsTags(lyricsTags);
135 | lyricsIfno.setLyricsLineInfoTreeMap(lyricsLineInfos);
136 | }
137 | return lyricsIfno;
138 | }
139 |
140 | /**
141 | * 解析每行的歌词内容
142 | *
143 | * 歌词列表
144 | *
145 | * @param lyricsTags 歌词标签
146 | * @param lineInfo 行歌词内容
147 | * @return
148 | */
149 | private LyricsLineInfo parserLineInfos(Map lyricsTags,
150 | String lineInfo) throws Exception {
151 | LyricsLineInfo lyricsLineInfo = null;
152 | if (lineInfo.startsWith(LEGAL_SONGNAME_PREFIX)) {
153 | String temp[] = lineInfo.split("\'");
154 | if (temp.length > 1) {
155 | lyricsTags.put(LyricsTag.TAG_TITLE, temp[1]);
156 | }
157 | } else if (lineInfo.startsWith(LEGAL_SINGERNAME_PREFIX)) {
158 | String temp[] = lineInfo.split("\'");
159 | if (temp.length > 1) {
160 | lyricsTags.put(LyricsTag.TAG_ARTIST, temp[1]);
161 | }
162 | } else if (lineInfo.startsWith(LEGAL_OFFSET_PREFIX)) {
163 | String temp[] = lineInfo.split("\'");
164 | if (temp.length > 1) {
165 | lyricsTags.put(LyricsTag.TAG_OFFSET, temp[1]);
166 | }
167 | } else if (lineInfo.startsWith(LEGAL_TAG_PREFIX)) {
168 | // 自定义标签
169 | if (lineInfo.contains(":")) {
170 | String temp1[] = lineInfo.split("\'");
171 | if (temp1.length > 1) {
172 | String temp2[] = temp1[1].split(":");
173 | if (temp2.length > 1) {
174 | lyricsTags.put(temp2[0], temp2[1]);
175 | }
176 | }
177 | }
178 | } else if (lineInfo.startsWith(LEGAL_LYRICS_LINE_PREFIX)) {
179 | lyricsLineInfo = new LyricsLineInfo();
180 |
181 | int leftIndex = lineInfo.indexOf('\'');
182 | int rightIndex = lineInfo.lastIndexOf('\'');
183 |
184 | String[] lineComments = lineInfo.substring(leftIndex + 1, rightIndex)
185 | .split("'\\s*,\\s*'", -1);
186 | // 开始时间
187 | String startTimeStr = lineComments[0];
188 | int startTime = TimeUtils.parseInteger(startTimeStr);
189 | lyricsLineInfo.setStartTime(startTime);
190 |
191 | // 结束时间
192 | String endTimeStr = lineComments[1];
193 | int endTime = TimeUtils.parseInteger(endTimeStr);
194 | lyricsLineInfo.setEndTime(endTime);
195 |
196 | // 歌词
197 | String lineLyricsStr = lineComments[2];
198 | List lineLyricsList = getLyricsWords(lineLyricsStr);
199 |
200 | // 歌词分隔
201 | String[] lyricsWords = lineLyricsList
202 | .toArray(new String[lineLyricsList.size()]);
203 | lyricsLineInfo.setLyricsWords(lyricsWords);
204 |
205 | // 获取当行歌词
206 | String lineLyrics = getLineLyrics(lineLyricsStr);
207 | lyricsLineInfo.setLineLyrics(lineLyrics);
208 |
209 | // 获取每个歌词的时间
210 | int wordsDisInterval[] = getWordsDisIntervalString(lineComments[3]);
211 | lyricsLineInfo.setWordsDisInterval(wordsDisInterval);
212 |
213 | //验证
214 | if (lyricsWords.length != wordsDisInterval.length) {
215 | throw new Exception("字标签个数与字时间标签个数不相符");
216 | }
217 | }
218 | return lyricsLineInfo;
219 | }
220 |
221 | /**
222 | * 获取每个歌词的时间
223 | *
224 | * @param wordsDisIntervalString
225 | * @return
226 | */
227 | private int[] getWordsDisIntervalString(String wordsDisIntervalString) throws Exception {
228 | String[] wordsDisIntervalStr = wordsDisIntervalString.split(",");
229 | int wordsDisInterval[] = new int[wordsDisIntervalStr.length];
230 | for (int i = 0; i < wordsDisIntervalStr.length; i++) {
231 | String wordDisIntervalStr = wordsDisIntervalStr[i];
232 | if (StringUtils.isNumeric(wordDisIntervalStr))
233 | wordsDisInterval[i] = Integer.parseInt(wordDisIntervalStr);
234 | else throw new Exception("字时间标签不能含有非数字字符串");
235 | }
236 | return wordsDisInterval;
237 | }
238 |
239 | /**
240 | * 获取当前行歌词,去掉中括号
241 | *
242 | * @param lineLyricsStr
243 | * @return
244 | */
245 | private String getLineLyrics(String lineLyricsStr) throws Exception {
246 | StringBuilder temp = new StringBuilder();
247 | for (int i = 0; i < lineLyricsStr.length(); i++) {
248 | char c = lineLyricsStr.charAt(i);
249 | switch (c) {
250 | case '[':
251 | break;
252 | case ']':
253 | break;
254 | default:
255 | temp.append(c);
256 | break;
257 | }
258 | }
259 | return temp.toString();
260 | }
261 |
262 | /**
263 | * 分隔每个歌词
264 | *
265 | * @param lineLyricsStr
266 | * @return
267 | */
268 | private List getLyricsWords(String lineLyricsStr) throws Exception {
269 | List lineLyricsList = new ArrayList();
270 | StringBuilder temp = new StringBuilder();
271 | boolean isEnterFlag = false;
272 | for (int i = 0; i < lineLyricsStr.length(); i++) {
273 | char c = lineLyricsStr.charAt(i);
274 | if (CharUtils.isChinese(c) || CharUtils.isHangulSyllables(c)
275 | || CharUtils.isHiragana(c)
276 | || (!CharUtils.isWord(c) && c != '[' && c != ']')) {
277 | if (isEnterFlag) {
278 | temp.append(lineLyricsStr.charAt(i));
279 | } else {
280 | lineLyricsList.add(String.valueOf(lineLyricsStr.charAt(i)));
281 | }
282 | } else if (c == '[') {
283 | isEnterFlag = true;
284 | } else if (c == ']') {
285 | isEnterFlag = false;
286 | lineLyricsList.add(temp.toString());
287 |
288 | //清空
289 | temp.delete(0, temp.length());
290 | } else {
291 | temp.append(lineLyricsStr.charAt(i));
292 | }
293 | }
294 | return lineLyricsList;
295 | }
296 |
297 | @Override
298 | public boolean isFileSupported(String ext) {
299 | return ext.equalsIgnoreCase("ksc");
300 | }
301 |
302 | @Override
303 | public String getSupportFileExt() {
304 | return "ksc";
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/formats/ksc/KscLyricsFileWriter.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.formats.ksc;
2 |
3 | import com.zlm.hp.lyrics.formats.LyricsFileWriter;
4 | import com.zlm.hp.lyrics.model.LyricsInfo;
5 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
6 | import com.zlm.hp.lyrics.model.LyricsTag;
7 | import com.zlm.hp.lyrics.utils.TimeUtils;
8 |
9 | import java.nio.charset.Charset;
10 | import java.util.Map;
11 | import java.util.TreeMap;
12 |
13 | /**
14 | * @Description: ksc歌词保存器
15 | * @Param:
16 | * @Return:
17 | * @Author: zhangliangming
18 | * @Date: 2017/12/25 16:45
19 | * @Throws:
20 | */
21 | public class KscLyricsFileWriter extends LyricsFileWriter {
22 |
23 | /**
24 | * 歌曲名 字符串
25 | */
26 | private final static String LEGAL_SONGNAME_PREFIX = "karaoke.songname";
27 | /**
28 | * 歌手名 字符串
29 | */
30 | private final static String LEGAL_SINGERNAME_PREFIX = "karaoke.singer";
31 | /**
32 | * 时间补偿值 字符串
33 | */
34 | private final static String LEGAL_OFFSET_PREFIX = "karaoke.offset";
35 | /**
36 | * 歌词 字符串
37 | */
38 | public final static String LEGAL_LYRICS_LINE_PREFIX = "karaoke.add";
39 |
40 | /**
41 | * 歌词Tag
42 | */
43 | public final static String LEGAL_TAG_PREFIX = "karaoke.tag";
44 |
45 | public KscLyricsFileWriter() {
46 | // 设置编码
47 | setDefaultCharset(Charset.forName("GB2312"));
48 | }
49 |
50 | @Override
51 | public boolean isFileSupported(String ext) {
52 | return ext.equalsIgnoreCase("ksc");
53 | }
54 |
55 | @Override
56 | public String getSupportFileExt() {
57 | return "ksc";
58 | }
59 |
60 | @Override
61 | public boolean writer(LyricsInfo lyricsIfno, String lyricsFilePath) throws Exception {
62 | String lyricsContent = getLyricsContent(lyricsIfno);
63 | return saveLyricsFile(lyricsContent, lyricsFilePath);
64 | }
65 |
66 | @Override
67 | public String getLyricsContent(LyricsInfo lyricsIfno) throws Exception {
68 | StringBuilder lyricsCom = new StringBuilder();
69 | // 先保存所有的标签数据
70 | Map tags = lyricsIfno.getLyricsTags();
71 | for (Map.Entry entry : tags.entrySet()) {
72 | Object val = entry.getValue();
73 | if (entry.getKey().equals(LyricsTag.TAG_TITLE)) {
74 | lyricsCom.append(LEGAL_SONGNAME_PREFIX);
75 | } else if (entry.getKey().equals(LyricsTag.TAG_ARTIST)) {
76 | lyricsCom.append(LEGAL_SINGERNAME_PREFIX);
77 | } else if (entry.getKey().equals(LyricsTag.TAG_OFFSET)) {
78 | lyricsCom.append(LEGAL_OFFSET_PREFIX);
79 | } else {
80 | lyricsCom.append(LEGAL_TAG_PREFIX);
81 | val = entry.getKey() + ":" + val;
82 | }
83 | lyricsCom.append(" := '" + val + "';\n");
84 | }
85 | // 每行歌词内容
86 | TreeMap lyricsLineInfos = lyricsIfno
87 | .getLyricsLineInfoTreeMap();
88 | for (int i = 0; i < lyricsLineInfos.size(); i++) {
89 | LyricsLineInfo lyricsLineInfo = lyricsLineInfos.get(i);
90 |
91 | lyricsCom.append(LEGAL_LYRICS_LINE_PREFIX + "('"
92 | + TimeUtils.parseMMSSFFFString(lyricsLineInfo.getStartTime())
93 | + "',");// 添加开始时间
94 | lyricsCom.append("'"
95 | + TimeUtils.parseMMSSFFFString(lyricsLineInfo.getEndTime()) + "',");// 添加结束时间
96 |
97 | // 获取歌词文本行
98 | String lyricsText = getLineLyrics(lyricsLineInfo.getLyricsWords());
99 | lyricsCom.append("'" + lyricsText + "',");// 解析文本歌词
100 |
101 | // 添加每个歌词的时间
102 | StringBuilder wordsDisIntervalText = new StringBuilder();
103 | int wordsDisInterval[] = lyricsLineInfo.getWordsDisInterval();
104 | for (int j = 0; j < wordsDisInterval.length; j++) {
105 | if (j == 0)
106 | wordsDisIntervalText.append(wordsDisInterval[j] + "");
107 | else
108 | wordsDisIntervalText.append("," + wordsDisInterval[j] + "");
109 | }
110 | lyricsCom.append("'" + wordsDisIntervalText.toString() + "');\n");
111 | }
112 | return lyricsCom.toString();
113 | }
114 |
115 | /**
116 | * 获取当行歌词(每个字添加[]是因为存在部分krc歌词转换成ksc歌词时,一个字时间标签对应几个歌词,这样子在ksc在解析时,会导致字时间标签与字标签的个数不对应,出错的问题,这是ksc歌词格式存在的问题)
117 | *
118 | * @param lyricsWords
119 | * @return
120 | */
121 | private String getLineLyrics(String[] lyricsWords) throws Exception {
122 | StringBuilder lrcText = new StringBuilder();
123 | for (int i = 0; i < lyricsWords.length; i++) {
124 | lrcText.append("[" + lyricsWords[i] + "]");
125 | }
126 | return lrcText.toString();
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/formats/lrc/LrcLyricsFileReader.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.formats.lrc;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.zlm.hp.lyrics.formats.LyricsFileReader;
6 | import com.zlm.hp.lyrics.model.LyricsInfo;
7 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
8 | import com.zlm.hp.lyrics.model.LyricsTag;
9 | import com.zlm.hp.lyrics.utils.TimeUtils;
10 | import com.zlm.hp.lyrics.utils.UnicodeInputStream;
11 |
12 | import java.io.BufferedReader;
13 | import java.io.File;
14 | import java.io.FileInputStream;
15 | import java.io.InputStream;
16 | import java.io.InputStreamReader;
17 | import java.nio.charset.Charset;
18 | import java.util.HashMap;
19 | import java.util.Iterator;
20 | import java.util.Map;
21 | import java.util.SortedMap;
22 | import java.util.TreeMap;
23 | import java.util.regex.Matcher;
24 | import java.util.regex.Pattern;
25 |
26 | /**
27 | * lrc歌词解析器
28 | * Created by zhangliangming on 2018-02-24.
29 | */
30 |
31 | public class LrcLyricsFileReader extends LyricsFileReader {
32 |
33 | /**
34 | * 歌曲名 字符串
35 | */
36 | private final static String LEGAL_SONGNAME_PREFIX = "[ti:";
37 | /**
38 | * 歌手名 字符串
39 | */
40 | private final static String LEGAL_SINGERNAME_PREFIX = "[ar:";
41 | /**
42 | * 时间补偿值 字符串
43 | */
44 | private final static String LEGAL_OFFSET_PREFIX = "[offset:";
45 | /**
46 | * 歌词上传者
47 | */
48 | private final static String LEGAL_BY_PREFIX = "[by:";
49 |
50 | /**
51 | * 专辑
52 | */
53 | private final static String LEGAL_AL_PREFIX = "[al:";
54 |
55 | private final static String LEGAL_TOTAL_PREFIX = "[total:";
56 |
57 | /**
58 | * 读取歌词文件
59 | *
60 | * @param file
61 | * @return
62 | */
63 | @Override
64 | public LyricsInfo readFile(File file) throws Exception {
65 | if (file != null) {
66 | String charsetName = getCharsetName(file);
67 | setDefaultCharset(Charset.forName(charsetName));
68 | InputStream inputStream = new FileInputStream(file);
69 | if (charsetName.toLowerCase().equals("utf-8")) {
70 | inputStream = new UnicodeInputStream(inputStream, charsetName);
71 | }
72 | return readInputStream(inputStream);
73 | }
74 | return null;
75 | }
76 |
77 | @Override
78 | public LyricsInfo readInputStream(InputStream in) throws Exception {
79 | LyricsInfo lyricsIfno = new LyricsInfo();
80 | lyricsIfno.setLyricsFileExt(getSupportFileExt());
81 | lyricsIfno.setLyricsType(LyricsInfo.LRC);
82 |
83 | if (in != null) {
84 | BufferedReader br = new BufferedReader(new InputStreamReader(in,
85 | getDefaultCharset()));
86 |
87 | // 这里面key为该行歌词的开始时间,方便后面排序
88 | SortedMap lyricsLineInfosTemp = new TreeMap();
89 | Map lyricsTags = new HashMap();
90 | String lineInfo = "";
91 | while ((lineInfo = br.readLine()) != null) {
92 |
93 | // 解析歌词
94 | parserLineInfos(lyricsLineInfosTemp,
95 | lyricsTags, lineInfo);
96 |
97 | }
98 | in.close();
99 | in = null;
100 | // 重新封装
101 | TreeMap lyricsLineInfos = new TreeMap();
102 | int index = 0;
103 | Iterator it = lyricsLineInfosTemp.keySet().iterator();
104 | while (it.hasNext()) {
105 | lyricsLineInfos
106 | .put(index++, lyricsLineInfosTemp.get(it.next()));
107 | }
108 | it = null;
109 | // 设置歌词的标签类
110 | lyricsIfno.setLyricsTags(lyricsTags);
111 | //
112 | lyricsIfno.setLyricsLineInfoTreeMap(lyricsLineInfos);
113 | }
114 | return lyricsIfno;
115 | }
116 |
117 | @Override
118 | public LyricsInfo readLrcText(String dynamicContent, String lrcContent, String extraLrcContent, String lyricsFilePath) throws Exception {
119 | LyricsInfo lyricsIfno = new LyricsInfo();
120 | lyricsIfno.setLyricsFileExt(getSupportFileExt());
121 | lyricsIfno.setLyricsType(LyricsInfo.LRC);
122 |
123 | if (!TextUtils.isEmpty(lrcContent)) {
124 |
125 | // 这里面key为该行歌词的开始时间,方便后面排序
126 | SortedMap lyricsLineInfosTemp = new TreeMap();
127 | Map lyricsTags = new HashMap();
128 |
129 | // 获取歌词内容
130 | String lrcContents[] = lrcContent.split("\n");
131 | for (int i = 0; i < lrcContents.length; i++) {
132 | String lineInfo = lrcContents[i];
133 |
134 | // 解析歌词
135 | parserLineInfos(lyricsLineInfosTemp,
136 | lyricsTags, lineInfo);
137 | }
138 |
139 | // 重新封装
140 | TreeMap lyricsLineInfos = new TreeMap();
141 | int index = 0;
142 | Iterator it = lyricsLineInfosTemp.keySet().iterator();
143 | while (it.hasNext()) {
144 | lyricsLineInfos
145 | .put(index++, lyricsLineInfosTemp.get(it.next()));
146 | }
147 | it = null;
148 | // 设置歌词的标签类
149 | lyricsIfno.setLyricsTags(lyricsTags);
150 | //
151 | lyricsIfno.setLyricsLineInfoTreeMap(lyricsLineInfos);
152 | }
153 | return lyricsIfno;
154 |
155 | }
156 |
157 | /**
158 | * 解析行歌词
159 | *
160 | * @param lyricsLineInfosTemp 排序集合
161 | * @param lyricsTags 歌曲标签
162 | * @param lineInfo 行歌词内容
163 | * @throws Exception
164 | */
165 | private void parserLineInfos(SortedMap lyricsLineInfosTemp, Map lyricsTags, String lineInfo) throws Exception {
166 | LyricsLineInfo lyricsLineInfo = null;
167 | if (lineInfo.startsWith(LEGAL_SONGNAME_PREFIX)) {
168 | int startIndex = LEGAL_SONGNAME_PREFIX.length();
169 | int endIndex = lineInfo.lastIndexOf("]");
170 | //
171 | lyricsTags.put(LyricsTag.TAG_TITLE,
172 | lineInfo.substring(startIndex, endIndex));
173 | } else if (lineInfo.startsWith(LEGAL_SINGERNAME_PREFIX)) {
174 | int startIndex = LEGAL_SINGERNAME_PREFIX.length();
175 | int endIndex = lineInfo.lastIndexOf("]");
176 | lyricsTags.put(LyricsTag.TAG_ARTIST,
177 | lineInfo.substring(startIndex, endIndex));
178 | } else if (lineInfo.startsWith(LEGAL_OFFSET_PREFIX)) {
179 | int startIndex = LEGAL_OFFSET_PREFIX.length();
180 | int endIndex = lineInfo.lastIndexOf("]");
181 | lyricsTags.put(LyricsTag.TAG_OFFSET,
182 | lineInfo.substring(startIndex, endIndex));
183 | } else if (lineInfo.startsWith(LEGAL_BY_PREFIX)
184 | || lineInfo.startsWith(LEGAL_TOTAL_PREFIX)
185 | || lineInfo.startsWith(LEGAL_AL_PREFIX)) {
186 |
187 | int startIndex = lineInfo.indexOf("[") + 1;
188 | int endIndex = lineInfo.lastIndexOf("]");
189 | String temp[] = lineInfo.substring(startIndex, endIndex).split(":");
190 | lyricsTags.put(temp[0], temp.length == 1 ? "" : temp[1]);
191 |
192 | } else {
193 | //时间标签
194 | String timeRegex = "\\[\\d+:\\d+.\\d+\\]";
195 | String timeRegexs = "(" + timeRegex + ")+";
196 | // 如果含有时间标签,则是歌词行
197 | Pattern pattern = Pattern.compile(timeRegexs);
198 | Matcher matcher = pattern.matcher(lineInfo);
199 | if (matcher.find()) {
200 | Pattern timePattern = Pattern.compile(timeRegex);
201 | Matcher timeMatcher = timePattern
202 | .matcher(matcher.group());
203 | //遍历时间标签
204 | while (timeMatcher.find()) {
205 | lyricsLineInfo = new LyricsLineInfo();
206 | //获取开始时间
207 | String startTimeString = timeMatcher.group().trim();
208 | int startTime = TimeUtils.parseInteger(startTimeString.substring(startTimeString.indexOf('[') + 1, startTimeString.lastIndexOf(']')));
209 | lyricsLineInfo.setStartTime(startTime);
210 | //获取歌词内容
211 | int timeEndIndex = matcher.end();
212 | String lineLyrics = lineInfo.substring(timeEndIndex,
213 | lineInfo.length()).trim();
214 | lyricsLineInfo.setLineLyrics(lineLyrics);
215 | lyricsLineInfosTemp.put(startTime, lyricsLineInfo);
216 | }
217 | }
218 | }
219 | }
220 |
221 | @Override
222 | public boolean isFileSupported(String ext) {
223 | return ext.equalsIgnoreCase("lrc");
224 | }
225 |
226 | @Override
227 | public String getSupportFileExt() {
228 | return "lrc";
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/formats/lrc/LrcLyricsFileWriter.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.formats.lrc;
2 |
3 | import com.zlm.hp.lyrics.formats.LyricsFileWriter;
4 | import com.zlm.hp.lyrics.model.LyricsInfo;
5 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
6 | import com.zlm.hp.lyrics.model.LyricsTag;
7 | import com.zlm.hp.lyrics.utils.TimeUtils;
8 |
9 | import java.util.ArrayList;
10 | import java.util.LinkedHashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 | import java.util.TreeMap;
14 |
15 | /**
16 | * lrc歌词生成器
17 | * Created by zhangliangming on 2018-02-24.
18 | */
19 |
20 | public class LrcLyricsFileWriter extends LyricsFileWriter {
21 |
22 | /**
23 | * 歌曲名 字符串
24 | */
25 | private final static String LEGAL_SONGNAME_PREFIX = "[ti:";
26 | /**
27 | * 歌手名 字符串
28 | */
29 | private final static String LEGAL_SINGERNAME_PREFIX = "[ar:";
30 | /**
31 | * 时间补偿值 字符串
32 | */
33 | private final static String LEGAL_OFFSET_PREFIX = "[offset:";
34 |
35 | /**
36 | * 歌曲长度
37 | */
38 | private final static String LEGAL_TOTAL_PREFIX = "[total:";
39 |
40 | @Override
41 | public boolean writer(LyricsInfo lyricsIfno, String lyricsFilePath) throws Exception {
42 | String lyricsContent = getLyricsContent(lyricsIfno);
43 | return saveLyricsFile(lyricsContent, lyricsFilePath);
44 | }
45 |
46 | @Override
47 | public String getLyricsContent(LyricsInfo lyricsIfno) throws Exception {
48 | StringBuilder lyricsCom = new StringBuilder();
49 | // 先保存所有的标签数据
50 | Map tags = lyricsIfno.getLyricsTags();
51 | for (Map.Entry entry : tags.entrySet()) {
52 | Object val = entry.getValue();
53 | if (entry.getKey().equals(LyricsTag.TAG_TITLE)) {
54 | lyricsCom.append(LEGAL_SONGNAME_PREFIX);
55 | } else if (entry.getKey().equals(LyricsTag.TAG_ARTIST)) {
56 | lyricsCom.append(LEGAL_SINGERNAME_PREFIX);
57 | } else if (entry.getKey().equals(LyricsTag.TAG_OFFSET)) {
58 | lyricsCom.append(LEGAL_OFFSET_PREFIX);
59 | } else if (entry.getKey().equals(LyricsTag.TAG_TOTAL)) {
60 | lyricsCom.append(LEGAL_TOTAL_PREFIX);
61 | } else {
62 | val = "[" + entry.getKey() + ":" + val;
63 | }
64 | lyricsCom.append(val + "]\n");
65 | }
66 |
67 | TreeMap lyricsLineInfos = lyricsIfno
68 | .getLyricsLineInfoTreeMap();
69 | // 将每行歌词,放到有序的map,判断已重复的歌词
70 | LinkedHashMap> lyricsLineInfoMapResult = new LinkedHashMap>();
71 | for (int i = 0; i < lyricsLineInfos.size(); i++) {
72 | LyricsLineInfo lyricsLineInfo = lyricsLineInfos.get(i);
73 | String saveLineLyrics = lyricsLineInfo.getLineLyrics();
74 | List indexs = null;
75 | // 如果已存在该行歌词,则往里面添加歌词行索引
76 | if (lyricsLineInfoMapResult.containsKey(saveLineLyrics)) {
77 | indexs = lyricsLineInfoMapResult.get(saveLineLyrics);
78 | } else {
79 | indexs = new ArrayList();
80 | }
81 | indexs.add(i);
82 | lyricsLineInfoMapResult.put(saveLineLyrics, indexs);
83 | }
84 | // 遍历
85 | for (Map.Entry> entry : lyricsLineInfoMapResult
86 | .entrySet()) {
87 | List indexs = entry.getValue();
88 | // 当前行歌词文本
89 | String saveLineLyrics = entry.getKey();
90 | StringBuilder timeText = new StringBuilder();// 时间标签内容
91 |
92 | for (int i = 0; i < indexs.size(); i++) {
93 | int key = indexs.get(i);
94 | LyricsLineInfo lyricsLineInfo = lyricsLineInfos.get(key);
95 | // 获取开始时间
96 | timeText.append("[" + TimeUtils.parseMMSSFFString(lyricsLineInfo.getStartTime()) + "]");
97 | }
98 | lyricsCom.append(timeText.toString() + "");
99 | lyricsCom.append("" + saveLineLyrics + "\n");
100 | }
101 | return lyricsCom.toString();
102 | }
103 |
104 | @Override
105 | public boolean isFileSupported(String ext) {
106 | return ext.equalsIgnoreCase("lrc");
107 | }
108 |
109 | @Override
110 | public String getSupportFileExt() {
111 | return "lrc";
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/formats/lrcwy/WYLyricsFileReader.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.formats.lrcwy;
2 |
3 | import android.text.TextUtils;
4 | import android.util.Base64;
5 |
6 | import com.zlm.hp.lyrics.formats.LyricsFileReader;
7 | import com.zlm.hp.lyrics.model.LyricsInfo;
8 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
9 | import com.zlm.hp.lyrics.model.LyricsTag;
10 | import com.zlm.hp.lyrics.model.TranslateLrcLineInfo;
11 | import com.zlm.hp.lyrics.utils.TimeUtils;
12 | import com.zlm.hp.lyrics.utils.UnicodeInputStream;
13 |
14 | import java.io.BufferedReader;
15 | import java.io.File;
16 | import java.io.FileInputStream;
17 | import java.io.InputStream;
18 | import java.io.InputStreamReader;
19 | import java.nio.charset.Charset;
20 | import java.util.ArrayList;
21 | import java.util.HashMap;
22 | import java.util.Iterator;
23 | import java.util.List;
24 | import java.util.Map;
25 | import java.util.SortedMap;
26 | import java.util.TreeMap;
27 | import java.util.regex.Matcher;
28 | import java.util.regex.Pattern;
29 |
30 | /**
31 | * @Description: 网易歌词读取器
32 | * @author: zhangliangming
33 | * @date: 2018-12-27 0:03
34 | **/
35 | public class WYLyricsFileReader extends LyricsFileReader {
36 | /**
37 | * 歌曲名 字符串
38 | */
39 | private final static String LEGAL_SONGNAME_PREFIX = "[ti:";
40 | /**
41 | * 歌手名 字符串
42 | */
43 | private final static String LEGAL_SINGERNAME_PREFIX = "[ar:";
44 | /**
45 | * 时间补偿值 字符串
46 | */
47 | private final static String LEGAL_OFFSET_PREFIX = "[offset:";
48 | /**
49 | * 歌词上传者
50 | */
51 | private final static String LEGAL_BY_PREFIX = "[by:";
52 |
53 | /**
54 | * 专辑
55 | */
56 | private final static String LEGAL_AL_PREFIX = "[al:";
57 |
58 | private final static String LEGAL_TOTAL_PREFIX = "[total:";
59 |
60 | /**
61 | * lrc歌词 字符串
62 | */
63 | public final static String LEGAL_LYRICS_LINE_PREFIX = "wy.lrc";
64 |
65 | /**
66 | * 动感歌词 字符串
67 | */
68 | public final static String LEGAL_DLYRICS_LINE_PREFIX = "wy.dlrc";
69 |
70 | /**
71 | * 额外歌词
72 | */
73 | private final static String LEGAL_EXTRA_LYRICS_PREFIX = "wy.extra.lrc";
74 |
75 | /**
76 | * 读取歌词文件
77 | *
78 | * @param file
79 | * @return
80 | */
81 | @Override
82 | public LyricsInfo readFile(File file) throws Exception {
83 | if (file != null) {
84 | String charsetName = getCharsetName(file);
85 | setDefaultCharset(Charset.forName(charsetName));
86 | InputStream inputStream = new FileInputStream(file);
87 | if (charsetName.toLowerCase().equals("utf-8")) {
88 | inputStream = new UnicodeInputStream(inputStream, charsetName);
89 | }
90 | return readInputStream(inputStream);
91 | }
92 | return null;
93 | }
94 |
95 | @Override
96 | public LyricsInfo readInputStream(InputStream in) throws Exception {
97 | LyricsInfo lyricsIfno = new LyricsInfo();
98 | lyricsIfno.setLyricsFileExt(getSupportFileExt());
99 |
100 | if (in != null) {
101 | BufferedReader br = new BufferedReader(new InputStreamReader(in,
102 | getDefaultCharset()));
103 |
104 | Map lyricsTags = new HashMap();
105 | String lineInfo = "";
106 | while ((lineInfo = br.readLine()) != null) {
107 |
108 | // 解析歌词
109 | parserLineInfos(lyricsIfno,
110 | lyricsTags, lineInfo);
111 |
112 | }
113 | in.close();
114 | in = null;
115 | // 设置歌词的标签类
116 | lyricsIfno.setLyricsTags(lyricsTags);
117 | }
118 | return lyricsIfno;
119 | }
120 |
121 | /**
122 | * 解析歌词文件
123 | *
124 | * @param lyricsIfno
125 | * @param lyricsTags
126 | * @param lineInfo
127 | */
128 | private void parserLineInfos(LyricsInfo lyricsIfno, Map lyricsTags, String lineInfo) throws Exception {
129 | if (lineInfo.startsWith(LEGAL_SONGNAME_PREFIX)) {
130 | int startIndex = LEGAL_SONGNAME_PREFIX.length();
131 | int endIndex = lineInfo.lastIndexOf("]");
132 | //
133 | lyricsTags.put(LyricsTag.TAG_TITLE,
134 | lineInfo.substring(startIndex, endIndex));
135 | } else if (lineInfo.startsWith(LEGAL_SINGERNAME_PREFIX)) {
136 | int startIndex = LEGAL_SINGERNAME_PREFIX.length();
137 | int endIndex = lineInfo.lastIndexOf("]");
138 | lyricsTags.put(LyricsTag.TAG_ARTIST,
139 | lineInfo.substring(startIndex, endIndex));
140 | } else if (lineInfo.startsWith(LEGAL_OFFSET_PREFIX)) {
141 | int startIndex = LEGAL_OFFSET_PREFIX.length();
142 | int endIndex = lineInfo.lastIndexOf("]");
143 | lyricsTags.put(LyricsTag.TAG_OFFSET,
144 | lineInfo.substring(startIndex, endIndex));
145 | } else if (lineInfo.startsWith(LEGAL_BY_PREFIX)
146 | || lineInfo.startsWith(LEGAL_TOTAL_PREFIX)
147 | || lineInfo.startsWith(LEGAL_AL_PREFIX)) {
148 |
149 | int startIndex = lineInfo.indexOf("[") + 1;
150 | int endIndex = lineInfo.lastIndexOf("]");
151 | String temp[] = lineInfo.substring(startIndex, endIndex).split(":");
152 | lyricsTags.put(temp[0], temp.length == 1 ? "" : temp[1]);
153 |
154 | } else {
155 | if (lineInfo.startsWith(LEGAL_LYRICS_LINE_PREFIX)) {
156 | //lrc歌词
157 | lyricsIfno.setLyricsType(LyricsInfo.LRC);
158 | int startIndex = lineInfo.indexOf("(");
159 | int endIndex = lineInfo.lastIndexOf(")");
160 | String lrcContent = lineInfo.substring(startIndex + 1, endIndex);
161 | lrcContent = new String(Base64.decode(lrcContent, Base64.NO_WRAP));
162 | parserLrcCom(lyricsIfno, lrcContent);
163 |
164 | } else if (lineInfo.startsWith(LEGAL_DLYRICS_LINE_PREFIX)) {
165 | lyricsIfno.setLyricsType(LyricsInfo.DYNAMIC);
166 | //动感歌词
167 | int startIndex = lineInfo.indexOf("(");
168 | int endIndex = lineInfo.lastIndexOf(")");
169 | String dynamicContent = lineInfo.substring(startIndex + 1, endIndex);
170 | dynamicContent = new String(Base64.decode(dynamicContent, Base64.NO_WRAP));
171 | parseDynamicLrc(lyricsIfno, dynamicContent);
172 |
173 | } else if (lineInfo.startsWith(LEGAL_EXTRA_LYRICS_PREFIX)) {
174 | //额外歌词
175 | int startIndex = lineInfo.indexOf("(");
176 | int endIndex = lineInfo.lastIndexOf(")");
177 | String extraLrcContent = lineInfo.substring(startIndex + 1, endIndex);
178 | extraLrcContent = new String(Base64.decode(extraLrcContent, Base64.NO_WRAP));
179 | parserExtraLrc(lyricsIfno, extraLrcContent);
180 | }
181 | }
182 |
183 | }
184 |
185 | /**
186 | * 解析额外歌词
187 | *
188 | * @param lyricsIfno
189 | * @param extraLrcContent
190 | */
191 | private void parserExtraLrc(LyricsInfo lyricsIfno, String extraLrcContent) {
192 | // 翻译歌词集合
193 | List translateLrcLineInfos = new ArrayList();
194 |
195 | // 获取歌词内容
196 | String lrcContents[] = extraLrcContent.split("\n");
197 | for (int i = 0; i < lrcContents.length; i++) {
198 | String lineInfo = lrcContents[i];
199 | // 翻译行歌词
200 | TranslateLrcLineInfo translateLrcLineInfo = new TranslateLrcLineInfo();
201 | translateLrcLineInfo.setLineLyrics(lineInfo.trim());
202 | translateLrcLineInfos.add(translateLrcLineInfo);
203 | }
204 | // 添加翻译歌词
205 | if (translateLrcLineInfos.size() > 0) {
206 | lyricsIfno.setTranslateLrcLineInfos(translateLrcLineInfos);
207 | }
208 | }
209 |
210 | @Override
211 | public LyricsInfo readLrcText(String dynamicContent, String lrcContent, String extraLrcContent, String lyricsFilePath) throws Exception {
212 | return parserLrc(dynamicContent, lrcContent, extraLrcContent, lyricsFilePath);
213 | }
214 |
215 |
216 | /**
217 | * 解析歌词,其中动感歌词和lrc歌词只能2个选1个
218 | *
219 | * @param dynamicContent 动感歌词内容
220 | * @param lrcContent lrc歌词内容
221 | * @param extraLrcContent 额外歌词内容(翻译歌词、音译歌词)
222 | * @param lyricsFilePath 歌词文件保存路径
223 | * @return
224 | * @throws Exception
225 | */
226 | private LyricsInfo parserLrc(String dynamicContent, String lrcContent, String extraLrcContent, String lyricsFilePath) throws Exception {
227 | LyricsInfo lyricsInfo = new LyricsInfo();
228 | lyricsInfo.setLyricsFileExt(getSupportFileExt());
229 | if (!TextUtils.isEmpty(dynamicContent)) {
230 | lyricsInfo.setLyricsType(LyricsInfo.DYNAMIC);
231 | //解析动感歌词
232 | parseDynamicLrc(lyricsInfo, dynamicContent);
233 | } else if (!TextUtils.isEmpty(lrcContent)) {
234 | lyricsInfo.setLyricsType(LyricsInfo.LRC);
235 | //解析lrc歌词
236 | parserLrcCom(lyricsInfo, lrcContent);
237 | }
238 | if (!TextUtils.isEmpty(extraLrcContent)) {
239 | //解析额外歌词
240 | parserTranslateLrc(lyricsInfo, extraLrcContent);
241 | }
242 |
243 | if (!TextUtils.isEmpty(lyricsFilePath)) {
244 | //保存歌词
245 | new WYLyricsFileWriter().writer(lyricsInfo, lyricsFilePath);
246 | }
247 | return lyricsInfo;
248 | }
249 |
250 | /**
251 | * 解析翻译歌词
252 | *
253 | * @param lyricsIfno
254 | * @param translateLrcContent
255 | */
256 | private void parserTranslateLrc(LyricsInfo lyricsIfno, String translateLrcContent) {
257 | // 这里面key为该行歌词的开始时间,方便后面排序
258 | SortedMap translateLrcInfosTemp = new TreeMap();
259 | Map lyricsTags = new HashMap();
260 | String lrcContents[] = translateLrcContent.split("\n");
261 | for (int i = 0; i < lrcContents.length; i++) {
262 | String lineInfo = lrcContents[i];
263 | // 解析lrc歌词行
264 | parserLrcLineInfos(translateLrcInfosTemp,
265 | lyricsTags, lineInfo);
266 |
267 | }
268 | // 翻译歌词集合
269 | List translateLrcLineInfos = new ArrayList();
270 | TreeMap lyricsLineInfos = lyricsIfno.getLyricsLineInfoTreeMap();
271 | for (int i = 0; i < lyricsLineInfos.size(); i++) {
272 | TranslateLrcLineInfo translateLrcLineInfo = new TranslateLrcLineInfo();
273 | LyricsLineInfo lyricsLineInfo = lyricsLineInfos.get(i);
274 | if (translateLrcInfosTemp.containsKey(lyricsLineInfo.getStartTime())) {
275 | LyricsLineInfo temp = translateLrcInfosTemp.get(lyricsLineInfo.getStartTime());
276 | translateLrcLineInfo.setLineLyrics(temp.getLineLyrics());
277 | }else{
278 | translateLrcLineInfo.setLineLyrics("");
279 | }
280 | translateLrcLineInfos.add(i, translateLrcLineInfo);
281 | }
282 |
283 | // 添加翻译歌词
284 | if (translateLrcLineInfos.size() > 0) {
285 | lyricsIfno.setTranslateLrcLineInfos(translateLrcLineInfos);
286 | }
287 | }
288 |
289 | /**
290 | * 解析动感歌词
291 | *
292 | * @param lyricsInfo
293 | * @param dynamicContent
294 | */
295 | private void parseDynamicLrc(LyricsInfo lyricsInfo, String dynamicContent) throws Exception {
296 | TreeMap lyricsLineInfos = new TreeMap();
297 | Map lyricsTags = new HashMap();
298 | String lrcContents[] = dynamicContent.split("\n");
299 | int index = 0;
300 | for (int i = 0; i < lrcContents.length; i++) {
301 | String lineInfo = lrcContents[i];
302 | // 解析动感歌词行
303 | LyricsLineInfo lyricsLineInfo = parserDynamicLrcLineInfos(lyricsTags,
304 | lineInfo);
305 | if (lyricsLineInfo != null) {
306 | lyricsLineInfos.put(index, lyricsLineInfo);
307 | index++;
308 | }
309 |
310 | }
311 |
312 | // 设置歌词的标签类
313 | lyricsInfo.setLyricsTags(lyricsTags);
314 | //
315 | lyricsInfo.setLyricsLineInfoTreeMap(lyricsLineInfos);
316 | }
317 |
318 | /**
319 | * 解析动感歌词行
320 | *
321 | * @param lyricsTags 歌曲标签
322 | * @param lineInfo 行歌词内容
323 | */
324 | private LyricsLineInfo parserDynamicLrcLineInfos(Map lyricsTags, String lineInfo) throws Exception {
325 | LyricsLineInfo lyricsLineInfo = null;
326 | if (lineInfo.startsWith(LEGAL_SONGNAME_PREFIX)) {
327 | int startIndex = LEGAL_SONGNAME_PREFIX.length();
328 | int endIndex = lineInfo.lastIndexOf("]");
329 | //
330 | lyricsTags.put(LyricsTag.TAG_TITLE,
331 | lineInfo.substring(startIndex, endIndex));
332 | } else if (lineInfo.startsWith(LEGAL_SINGERNAME_PREFIX)) {
333 | int startIndex = LEGAL_SINGERNAME_PREFIX.length();
334 | int endIndex = lineInfo.lastIndexOf("]");
335 | lyricsTags.put(LyricsTag.TAG_ARTIST,
336 | lineInfo.substring(startIndex, endIndex));
337 | } else if (lineInfo.startsWith(LEGAL_OFFSET_PREFIX)) {
338 | int startIndex = LEGAL_OFFSET_PREFIX.length();
339 | int endIndex = lineInfo.lastIndexOf("]");
340 | lyricsTags.put(LyricsTag.TAG_OFFSET,
341 | lineInfo.substring(startIndex, endIndex));
342 | } else if (lineInfo.startsWith(LEGAL_BY_PREFIX)
343 | || lineInfo.startsWith(LEGAL_TOTAL_PREFIX)
344 | || lineInfo.startsWith(LEGAL_AL_PREFIX)) {
345 |
346 | int startIndex = lineInfo.indexOf("[") + 1;
347 | int endIndex = lineInfo.lastIndexOf("]");
348 | String temp[] = lineInfo.substring(startIndex, endIndex).split(":");
349 | lyricsTags.put(temp[0], temp.length == 1 ? "" : temp[1]);
350 |
351 | } else {
352 | //时间标签
353 | Pattern pattern = Pattern.compile("\\[\\d+,\\d+\\]");
354 | Matcher matcher = pattern.matcher(lineInfo);
355 | if (matcher.find()) {
356 | lyricsLineInfo = new LyricsLineInfo();
357 | // [此行开始时刻距0时刻的毫秒数,此行持续的毫秒数](0,此字持续的毫秒数)歌(0,此字持续的毫秒数)词(0,此字持续的毫秒数)正(0,此字持续的毫秒数)文
358 | // 获取行的出现时间和结束时间
359 | int mStartIndex = matcher.start();
360 | int mEndIndex = matcher.end();
361 | String lineTime[] = lineInfo.substring(mStartIndex + 1,
362 | mEndIndex - 1).split(",");
363 | //
364 |
365 | int startTime = Integer.parseInt(lineTime[0]);
366 | int endTime = startTime + Integer.parseInt(lineTime[1]);
367 | lyricsLineInfo.setEndTime(endTime);
368 | lyricsLineInfo.setStartTime(startTime);
369 | // 获取歌词信息
370 | String lineContent = lineInfo.substring(mEndIndex,
371 | lineInfo.length());
372 |
373 | // 歌词匹配的正则表达式
374 | String regex = "\\(\\d+,\\d+\\)";
375 | Pattern lyricsWordsPattern = Pattern.compile(regex);
376 | Matcher lyricsWordsMatcher = lyricsWordsPattern
377 | .matcher(lineContent);
378 |
379 | // 歌词分隔
380 | String lineLyricsTemp[] = lineContent.split(regex);
381 | String[] lyricsWords = getLyricsWords(lineLyricsTemp);
382 | lyricsLineInfo.setLyricsWords(lyricsWords);
383 |
384 | // 获取每个歌词的时间
385 | int wordsDisInterval[] = new int[lyricsWords.length];
386 | int index = 0;
387 | while (lyricsWordsMatcher.find()) {
388 |
389 | //验证
390 | if (index >= wordsDisInterval.length) {
391 | throw new Exception("字标签个数与字时间标签个数不相符");
392 | }
393 |
394 | //
395 | String wordsDisIntervalStr = lyricsWordsMatcher.group();
396 | String wordsDisIntervalStrTemp = wordsDisIntervalStr
397 | .substring(wordsDisIntervalStr.indexOf('(') + 1, wordsDisIntervalStr.lastIndexOf(')'));
398 | String wordsDisIntervalTemp[] = wordsDisIntervalStrTemp
399 | .split(",");
400 | wordsDisInterval[index++] = Integer
401 | .parseInt(wordsDisIntervalTemp[1]);
402 | }
403 | lyricsLineInfo.setWordsDisInterval(wordsDisInterval);
404 |
405 | // 获取当行歌词
406 | String lineLyrics = lyricsWordsMatcher.replaceAll("");
407 | lyricsLineInfo.setLineLyrics(lineLyrics);
408 |
409 | }
410 | }
411 | return lyricsLineInfo;
412 | }
413 |
414 |
415 | /**
416 | * 分隔每个歌词
417 | *
418 | * @param lineLyricsTemp
419 | * @return
420 | */
421 | private String[] getLyricsWords(String[] lineLyricsTemp) {
422 | String temp[] = null;
423 | if (lineLyricsTemp.length < 2) {
424 | return new String[lineLyricsTemp.length];
425 | }
426 | //
427 | temp = new String[lineLyricsTemp.length - 1];
428 | for (int i = 1; i < lineLyricsTemp.length; i++) {
429 | temp[i - 1] = lineLyricsTemp[i];
430 | }
431 | return temp;
432 | }
433 |
434 |
435 | /**
436 | * 解析lrc歌词
437 | *
438 | * @param lyricsInfo
439 | * @param lrcContent
440 | */
441 | private void parserLrcCom(LyricsInfo lyricsInfo, String lrcContent) {
442 | // 这里面key为该行歌词的开始时间,方便后面排序
443 | SortedMap lyricsLineInfosTemp = new TreeMap();
444 | Map lyricsTags = new HashMap();
445 | String lrcContents[] = lrcContent.split("\n");
446 | for (int i = 0; i < lrcContents.length; i++) {
447 | String lineInfo = lrcContents[i];
448 | // 解析lrc歌词行
449 | parserLrcLineInfos(lyricsLineInfosTemp,
450 | lyricsTags, lineInfo);
451 |
452 | }
453 | // 重新封装
454 | TreeMap lyricsLineInfos = new TreeMap();
455 | int index = 0;
456 | Iterator it = lyricsLineInfosTemp.keySet().iterator();
457 | while (it.hasNext()) {
458 | lyricsLineInfos
459 | .put(index++, lyricsLineInfosTemp.get(it.next()));
460 | }
461 | it = null;
462 | // 设置歌词的标签类
463 | lyricsInfo.setLyricsTags(lyricsTags);
464 | //
465 | lyricsInfo.setLyricsLineInfoTreeMap(lyricsLineInfos);
466 | }
467 |
468 | /**
469 | * 解析行歌词
470 | *
471 | * @param lyricsLineInfosTemp 排序集合
472 | * @param lyricsTags 歌曲标签
473 | * @param lineInfo 行歌词内容
474 | * @throws Exception
475 | */
476 | private void parserLrcLineInfos(SortedMap lyricsLineInfosTemp, Map lyricsTags, String lineInfo) {
477 | LyricsLineInfo lyricsLineInfo = null;
478 | if (lineInfo.startsWith(LEGAL_SONGNAME_PREFIX)) {
479 | int startIndex = LEGAL_SONGNAME_PREFIX.length();
480 | int endIndex = lineInfo.lastIndexOf("]");
481 | //
482 | lyricsTags.put(LyricsTag.TAG_TITLE,
483 | lineInfo.substring(startIndex, endIndex));
484 | } else if (lineInfo.startsWith(LEGAL_SINGERNAME_PREFIX)) {
485 | int startIndex = LEGAL_SINGERNAME_PREFIX.length();
486 | int endIndex = lineInfo.lastIndexOf("]");
487 | lyricsTags.put(LyricsTag.TAG_ARTIST,
488 | lineInfo.substring(startIndex, endIndex));
489 | } else if (lineInfo.startsWith(LEGAL_OFFSET_PREFIX)) {
490 | int startIndex = LEGAL_OFFSET_PREFIX.length();
491 | int endIndex = lineInfo.lastIndexOf("]");
492 | lyricsTags.put(LyricsTag.TAG_OFFSET,
493 | lineInfo.substring(startIndex, endIndex));
494 | } else if (lineInfo.startsWith(LEGAL_BY_PREFIX)
495 | || lineInfo.startsWith(LEGAL_TOTAL_PREFIX)
496 | || lineInfo.startsWith(LEGAL_AL_PREFIX)) {
497 |
498 | int startIndex = lineInfo.indexOf("[") + 1;
499 | int endIndex = lineInfo.lastIndexOf("]");
500 | String temp[] = lineInfo.substring(startIndex, endIndex).split(":");
501 | lyricsTags.put(temp[0], temp.length == 1 ? "" : temp[1]);
502 |
503 | } else {
504 | //时间标签
505 | String timeRegex = "\\[\\d+:\\d+.\\d+\\]";
506 | String timeRegexs = "(" + timeRegex + ")+";
507 | // 如果含有时间标签,则是歌词行
508 | Pattern pattern = Pattern.compile(timeRegexs);
509 | Matcher matcher = pattern.matcher(lineInfo);
510 | if (matcher.find()) {
511 | Pattern timePattern = Pattern.compile(timeRegex);
512 | Matcher timeMatcher = timePattern
513 | .matcher(matcher.group());
514 | //遍历时间标签
515 | while (timeMatcher.find()) {
516 | lyricsLineInfo = new LyricsLineInfo();
517 | //获取开始时间
518 | String startTimeString = timeMatcher.group().trim();
519 | int startTime = TimeUtils.parseInteger(startTimeString.substring(startTimeString.indexOf('[') + 1, startTimeString.lastIndexOf(']')));
520 | lyricsLineInfo.setStartTime(startTime);
521 | //获取歌词内容
522 | int timeEndIndex = matcher.end();
523 | String lineLyrics = lineInfo.substring(timeEndIndex,
524 | lineInfo.length()).trim();
525 | lyricsLineInfo.setLineLyrics(lineLyrics);
526 | lyricsLineInfosTemp.put(startTime, lyricsLineInfo);
527 | }
528 | }
529 | }
530 | }
531 |
532 | @Override
533 | public boolean isFileSupported(String ext) {
534 | return ext.equalsIgnoreCase("lrcwy");
535 | }
536 |
537 | @Override
538 | public String getSupportFileExt() {
539 | return "lrcwy";
540 | }
541 | }
542 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/formats/lrcwy/WYLyricsFileWriter.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.formats.lrcwy;
2 |
3 | import android.text.TextUtils;
4 | import android.util.Base64;
5 |
6 | import com.zlm.hp.lyrics.formats.LyricsFileWriter;
7 | import com.zlm.hp.lyrics.model.LyricsInfo;
8 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
9 | import com.zlm.hp.lyrics.model.LyricsTag;
10 | import com.zlm.hp.lyrics.model.TranslateLrcLineInfo;
11 | import com.zlm.hp.lyrics.utils.TimeUtils;
12 |
13 | import java.util.ArrayList;
14 | import java.util.LinkedHashMap;
15 | import java.util.List;
16 | import java.util.Map;
17 | import java.util.TreeMap;
18 |
19 | /**
20 | * @Description: 网易歌词生成器
21 | * @author: zhangliangming
22 | * @date: 2018-12-27 0:03
23 | **/
24 | public class WYLyricsFileWriter extends LyricsFileWriter {
25 | /**
26 | * 歌曲名 字符串
27 | */
28 | private final static String LEGAL_SONGNAME_PREFIX = "[ti:";
29 | /**
30 | * 歌手名 字符串
31 | */
32 | private final static String LEGAL_SINGERNAME_PREFIX = "[ar:";
33 | /**
34 | * 时间补偿值 字符串
35 | */
36 | private final static String LEGAL_OFFSET_PREFIX = "[offset:";
37 | /**
38 | * 歌词上传者
39 | */
40 | private final static String LEGAL_BY_PREFIX = "[by:";
41 |
42 | /**
43 | * 专辑
44 | */
45 | private final static String LEGAL_AL_PREFIX = "[al:";
46 |
47 | private final static String LEGAL_TOTAL_PREFIX = "[total:";
48 |
49 | /**
50 | * lrc歌词 字符串
51 | */
52 | public final static String LEGAL_LYRICS_LINE_PREFIX = "wy.lrc";
53 |
54 | /**
55 | * 动感歌词 字符串
56 | */
57 | public final static String LEGAL_DLYRICS_LINE_PREFIX = "wy.dlrc";
58 |
59 | /**
60 | * 额外歌词
61 | */
62 | private final static String LEGAL_EXTRA_LYRICS_PREFIX = "wy.extra.lrc";
63 |
64 |
65 | @Override
66 | public boolean writer(LyricsInfo lyricsIfno, String lyricsFilePath) throws Exception {
67 | String lyricsContent = getLyricsContent(lyricsIfno);
68 | return saveLyricsFile(lyricsContent, lyricsFilePath);
69 | }
70 |
71 | @Override
72 | public String getLyricsContent(LyricsInfo lyricsIfno) throws Exception {
73 | StringBuilder lyricsCom = new StringBuilder();
74 | // 先保存所有的标签数据
75 | Map tags = lyricsIfno.getLyricsTags();
76 | for (Map.Entry entry : tags.entrySet()) {
77 | Object val = entry.getValue();
78 | if (entry.getKey().equals(LyricsTag.TAG_TITLE)) {
79 | lyricsCom.append(LEGAL_SONGNAME_PREFIX);
80 | } else if (entry.getKey().equals(LyricsTag.TAG_ARTIST)) {
81 | lyricsCom.append(LEGAL_SINGERNAME_PREFIX);
82 | } else if (entry.getKey().equals(LyricsTag.TAG_OFFSET)) {
83 | lyricsCom.append(LEGAL_OFFSET_PREFIX);
84 | } else if (entry.getKey().equals(LyricsTag.TAG_TOTAL)) {
85 | lyricsCom.append(LEGAL_TOTAL_PREFIX);
86 | } else {
87 | val = "[" + entry.getKey() + ":" + val;
88 | }
89 | lyricsCom.append(val + "]\n");
90 | }
91 | //判断歌词类型
92 | if (lyricsIfno.getLyricsType() == LyricsInfo.DYNAMIC) {
93 | //保存动感歌词
94 | String dynamicContent = getDynamicContent(lyricsIfno);
95 | lyricsCom.append(dynamicContent);
96 | } else {
97 | //保存lrc歌词
98 | String lrcContent = getLrcContent(lyricsIfno);
99 | lyricsCom.append(lrcContent);
100 | }
101 |
102 | //保存额外歌词
103 | String extraLrcContent = getExtraLrcContent(lyricsIfno);
104 | if (!TextUtils.isEmpty(extraLrcContent)) {
105 | lyricsCom.append(extraLrcContent);
106 | }
107 | return lyricsCom.toString();
108 | }
109 |
110 | /**
111 | * 获取额外歌词
112 | *
113 | * @param lyricsIfno
114 | * @return
115 | */
116 | private String getExtraLrcContent(LyricsInfo lyricsIfno) {
117 | String result = "";
118 | List translateLrcLineInfos = lyricsIfno.getTranslateLrcLineInfos();
119 | if (translateLrcLineInfos != null && translateLrcLineInfos.size() > 0) {
120 | StringBuilder lyricsCom = new StringBuilder();
121 | for (int i = 0; i < translateLrcLineInfos.size(); i++) {
122 | TranslateLrcLineInfo translateLrcLineInfo = translateLrcLineInfos.get(i);
123 | lyricsCom.append(translateLrcLineInfo.getLineLyrics() + "\n");
124 | }
125 | result += LEGAL_EXTRA_LYRICS_PREFIX + "(" + Base64.encodeToString(lyricsCom.toString().getBytes(), Base64.NO_WRAP) + ")\n";
126 | }
127 | return result;
128 | }
129 |
130 | /**
131 | * 获取lrc歌词
132 | *
133 | * @param lyricsIfno
134 | * @return
135 | */
136 | private String getLrcContent(LyricsInfo lyricsIfno) {
137 | TreeMap lyricsLineInfos = lyricsIfno
138 | .getLyricsLineInfoTreeMap();
139 | String result = "";
140 | if (lyricsLineInfos != null && lyricsLineInfos.size() > 0) {
141 | StringBuilder lyricsCom = new StringBuilder();
142 | // 将每行歌词,放到有序的map,判断已重复的歌词
143 | LinkedHashMap> lyricsLineInfoMapResult = new LinkedHashMap>();
144 |
145 | for (int i = 0; i < lyricsLineInfos.size(); i++) {
146 | LyricsLineInfo lyricsLineInfo = lyricsLineInfos.get(i);
147 | String saveLineLyrics = lyricsLineInfo.getLineLyrics();
148 | List indexs = null;
149 | // 如果已存在该行歌词,则往里面添加歌词行索引
150 | if (lyricsLineInfoMapResult.containsKey(saveLineLyrics)) {
151 | indexs = lyricsLineInfoMapResult.get(saveLineLyrics);
152 | } else {
153 | indexs = new ArrayList();
154 | }
155 | indexs.add(i);
156 | lyricsLineInfoMapResult.put(saveLineLyrics, indexs);
157 | }
158 | // 遍历
159 | for (Map.Entry> entry : lyricsLineInfoMapResult
160 | .entrySet()) {
161 | List indexs = entry.getValue();
162 | // 当前行歌词文本
163 | String saveLineLyrics = entry.getKey();
164 | StringBuilder timeText = new StringBuilder();// 时间标签内容
165 |
166 | for (int i = 0; i < indexs.size(); i++) {
167 | int key = indexs.get(i);
168 | LyricsLineInfo lyricsLineInfo = lyricsLineInfos.get(key);
169 | // 获取开始时间
170 | timeText.append("[" + TimeUtils.parseMMSSFFString(lyricsLineInfo.getStartTime()) + "]");
171 | }
172 | lyricsCom.append(timeText.toString() + "");
173 | lyricsCom.append("" + saveLineLyrics + "\n");
174 | }
175 | result += LEGAL_LYRICS_LINE_PREFIX + "(" + Base64.encodeToString(lyricsCom.toString().getBytes(), Base64.NO_WRAP) + ")\n";
176 | }
177 | return result;
178 | }
179 |
180 | /**
181 | * 获取动感歌词
182 | *
183 | * @param lyricsIfno
184 | * @return
185 | */
186 | private String getDynamicContent(LyricsInfo lyricsIfno) {
187 | String result = "";
188 | TreeMap lyricsLineInfoTreeMap = lyricsIfno.getLyricsLineInfoTreeMap();
189 | if (lyricsLineInfoTreeMap != null && lyricsLineInfoTreeMap.size() > 0) {
190 | StringBuilder lyricsCom = new StringBuilder();
191 | for (int i = 0; i < lyricsLineInfoTreeMap.size(); i++) {
192 | LyricsLineInfo lyricsLineInfo = lyricsLineInfoTreeMap.get(i);
193 | lyricsCom.append("[" + lyricsLineInfo.getStartTime() + "," + (lyricsLineInfo.getEndTime() - lyricsLineInfo.getStartTime()) + "]");
194 | String[] lyricsWords = lyricsLineInfo.getLyricsWords();
195 | int[] wordsDisInterval = lyricsLineInfo.getWordsDisInterval();
196 | for (int j = 0; j < lyricsWords.length; j++) {
197 | lyricsCom.append("(0" + "," + wordsDisInterval[j] + ")" + lyricsWords[j]);
198 | }
199 | lyricsCom.append("\n");
200 | }
201 | result += LEGAL_DLYRICS_LINE_PREFIX + "(" + Base64.encodeToString(lyricsCom.toString().getBytes(), Base64.NO_WRAP) + ")\n";
202 | }
203 | return result;
204 | }
205 |
206 | @Override
207 | public boolean isFileSupported(String ext) {
208 | return ext.equalsIgnoreCase("lrcwy");
209 | }
210 |
211 | @Override
212 | public String getSupportFileExt() {
213 | return "lrcwy";
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/formats/trc/TrcLyricsFileReader.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.formats.trc;
2 |
3 | import com.zlm.hp.lyrics.formats.LyricsFileReader;
4 | import com.zlm.hp.lyrics.model.LyricsInfo;
5 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
6 | import com.zlm.hp.lyrics.model.LyricsTag;
7 | import com.zlm.hp.lyrics.utils.TimeUtils;
8 |
9 | import java.io.BufferedReader;
10 | import java.io.InputStream;
11 | import java.io.InputStreamReader;
12 | import java.util.HashMap;
13 | import java.util.Map;
14 | import java.util.TreeMap;
15 | import java.util.regex.Matcher;
16 | import java.util.regex.Pattern;
17 |
18 | /**
19 | * @Description: trc歌词
20 | * @author: zhangliangming
21 | * @date: 2020-02-26 19:53
22 | **/
23 | public class TrcLyricsFileReader extends LyricsFileReader {
24 |
25 | /**
26 | * 歌曲名 字符串
27 | */
28 | private final static String LEGAL_SONGNAME_PREFIX = "[ti:";
29 | /**
30 | * 歌手名 字符串
31 | */
32 | private final static String LEGAL_SINGERNAME_PREFIX = "[ar:";
33 | /**
34 | * 时间补偿值 字符串
35 | */
36 | private final static String LEGAL_OFFSET_PREFIX = "[offset:";
37 | /**
38 | * 歌词上传者
39 | */
40 | private final static String LEGAL_BY_PREFIX = "[by:";
41 |
42 | /**
43 | * 专辑
44 | */
45 | private final static String LEGAL_AL_PREFIX = "[al:";
46 |
47 | private final static String LEGAL_TOTAL_PREFIX = "[total:";
48 |
49 | @Override
50 | public LyricsInfo readLrcText(String dynamicContent, String lrcContent, String extraLrcContent, String lyricsFilePath) throws Exception {
51 | return null;
52 | }
53 |
54 | @Override
55 | public LyricsInfo readInputStream(InputStream in) throws Exception {
56 | LyricsInfo lyricsIfno = new LyricsInfo();
57 | lyricsIfno.setLyricsFileExt(getSupportFileExt());
58 | if (in != null) {
59 | BufferedReader br = new BufferedReader(new InputStreamReader(in,
60 | getDefaultCharset()));
61 |
62 | TreeMap lyricsLineInfos = new TreeMap();
63 | Map lyricsTags = new HashMap();
64 | int index = 0;
65 | String lineInfo = "";
66 | while ((lineInfo = br.readLine()) != null) {
67 |
68 | // 行读取,并解析每行歌词的内容
69 | LyricsLineInfo lyricsLineInfo = parserLineInfos(lyricsTags,
70 | lineInfo);
71 | if (lyricsLineInfo != null) {
72 | lyricsLineInfos.put(index, lyricsLineInfo);
73 | index++;
74 | }
75 | }
76 | in.close();
77 | in = null;
78 | // 设置歌词的标签类
79 | lyricsIfno.setLyricsTags(lyricsTags);
80 | //
81 | lyricsIfno.setLyricsLineInfoTreeMap(lyricsLineInfos);
82 | }
83 | return lyricsIfno;
84 | }
85 |
86 | /**
87 | * 解析每行的歌词内容
88 | *
89 | * 歌词列表
90 | *
91 | * @param lyricsTags 歌词标签
92 | * @param lineInfo 行歌词内容
93 | * @return
94 | */
95 | private LyricsLineInfo parserLineInfos(Map lyricsTags,
96 | String lineInfo) throws Exception {
97 | LyricsLineInfo lyricsLineInfo = null;
98 | if (lineInfo.startsWith(LEGAL_SONGNAME_PREFIX)) {
99 | int startIndex = LEGAL_SONGNAME_PREFIX.length();
100 | int endIndex = lineInfo.lastIndexOf("]");
101 | //
102 | lyricsTags.put(LyricsTag.TAG_TITLE,
103 | lineInfo.substring(startIndex, endIndex));
104 | } else if (lineInfo.startsWith(LEGAL_SINGERNAME_PREFIX)) {
105 | int startIndex = LEGAL_SINGERNAME_PREFIX.length();
106 | int endIndex = lineInfo.lastIndexOf("]");
107 | lyricsTags.put(LyricsTag.TAG_ARTIST,
108 | lineInfo.substring(startIndex, endIndex));
109 | } else if (lineInfo.startsWith(LEGAL_OFFSET_PREFIX)) {
110 | int startIndex = LEGAL_OFFSET_PREFIX.length();
111 | int endIndex = lineInfo.lastIndexOf("]");
112 | lyricsTags.put(LyricsTag.TAG_OFFSET,
113 | lineInfo.substring(startIndex, endIndex));
114 | } else if (lineInfo.startsWith(LEGAL_BY_PREFIX)
115 | || lineInfo.startsWith(LEGAL_TOTAL_PREFIX)
116 | || lineInfo.startsWith(LEGAL_AL_PREFIX)) {
117 |
118 | int startIndex = lineInfo.indexOf("[") + 1;
119 | int endIndex = lineInfo.lastIndexOf("]");
120 | String temp[] = lineInfo.substring(startIndex, endIndex).split(":");
121 | lyricsTags.put(temp[0], temp.length == 1 ? "" : temp[1]);
122 |
123 | } else {
124 | //时间标签
125 | String timeRegex = "\\[\\d+:\\d+.\\d+\\]";
126 | String timeRegexs = "(" + timeRegex + ")+";
127 | // 如果含有时间标签,则是歌词行
128 | Pattern pattern = Pattern.compile(timeRegexs);
129 | Matcher matcher = pattern.matcher(lineInfo);
130 | if (matcher.find()) {
131 | lyricsLineInfo = new LyricsLineInfo();
132 | // [此行开始时刻距0时刻的毫秒数]<此字持续的毫秒数>歌<此字持续的毫秒数>词<此字持续的毫秒数>正<此字持续的毫秒数>文
133 | // 获取行的出现时间和结束时间
134 | int startIndex = matcher.start();
135 | int endIndex = matcher.end();
136 | int startTime = TimeUtils.parseInteger(lineInfo.substring(startIndex + 1,
137 | endIndex - 1));
138 | lyricsLineInfo.setStartTime(startTime);
139 | // 获取歌词信息
140 | String lineContent = lineInfo.substring(endIndex,
141 | lineInfo.length());
142 |
143 | // 歌词匹配的正则表达式
144 | String regex = "\\<\\d+\\>";
145 | Pattern lyricsWordsPattern = Pattern.compile(regex);
146 | Matcher lyricsWordsMatcher = lyricsWordsPattern
147 | .matcher(lineContent);
148 |
149 | if (lyricsWordsMatcher == null) {
150 | return null;
151 | }
152 |
153 | // 歌词分隔
154 | String lineLyricsTemp[] = lineContent.split(regex);
155 | String[] lyricsWords = getLyricsWords(lineLyricsTemp);
156 | lyricsLineInfo.setLyricsWords(lyricsWords);
157 |
158 | // 获取每个歌词的时间
159 | int wordsDisInterval[] = new int[lyricsWords.length];
160 | int index = 0;
161 | int endTime = startTime;
162 | while (lyricsWordsMatcher.find()) {
163 |
164 | //验证
165 | if (index >= wordsDisInterval.length) {
166 | throw new Exception("字标签个数与字时间标签个数不相符");
167 | }
168 |
169 | //
170 | String wordsDisIntervalStr = lyricsWordsMatcher.group();
171 | String wordsDisIntervalStrTemp = wordsDisIntervalStr
172 | .substring(wordsDisIntervalStr.indexOf('<') + 1, wordsDisIntervalStr.lastIndexOf('>'));
173 |
174 | int wordsTime = Integer
175 | .parseInt(wordsDisIntervalStrTemp);
176 | wordsDisInterval[index++] = wordsTime;
177 |
178 | endTime += wordsTime;
179 | }
180 | lyricsLineInfo.setWordsDisInterval(wordsDisInterval);
181 | lyricsLineInfo.setEndTime(endTime);
182 | // 获取当行歌词
183 | String lineLyrics = lyricsWordsMatcher.replaceAll("");
184 | lyricsLineInfo.setLineLyrics(lineLyrics);
185 | }
186 |
187 | }
188 | return lyricsLineInfo;
189 | }
190 |
191 | /**
192 | * 分隔每个歌词
193 | *
194 | * @param lineLyricsTemp
195 | * @return
196 | */
197 | private String[] getLyricsWords(String[] lineLyricsTemp) throws Exception {
198 | String temp[] = null;
199 | if (lineLyricsTemp.length < 2) {
200 | return new String[lineLyricsTemp.length];
201 | }
202 | //
203 | temp = new String[lineLyricsTemp.length - 1];
204 | for (int i = 1; i < lineLyricsTemp.length; i++) {
205 | temp[i - 1] = lineLyricsTemp[i];
206 | }
207 | return temp;
208 | }
209 |
210 | @Override
211 | public boolean isFileSupported(String ext) {
212 | return ext.equalsIgnoreCase("trc");
213 | }
214 |
215 | @Override
216 | public String getSupportFileExt() {
217 | return "trc";
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/formats/trc/TrcLyricsFileWriter.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.formats.trc;
2 |
3 | import com.zlm.hp.lyrics.formats.LyricsFileWriter;
4 | import com.zlm.hp.lyrics.model.LyricsInfo;
5 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
6 | import com.zlm.hp.lyrics.model.LyricsTag;
7 | import com.zlm.hp.lyrics.utils.TimeUtils;
8 |
9 | import java.util.Map;
10 | import java.util.TreeMap;
11 |
12 | /**
13 | * @Description: trc歌词生成器
14 | * @author: zhangliangming
15 | * @date: 2020-02-26 20:35
16 | **/
17 |
18 | public class TrcLyricsFileWriter extends LyricsFileWriter {
19 |
20 | /**
21 | * 歌曲名 字符串
22 | */
23 | private final static String LEGAL_SONGNAME_PREFIX = "[ti:";
24 | /**
25 | * 歌手名 字符串
26 | */
27 | private final static String LEGAL_SINGERNAME_PREFIX = "[ar:";
28 | /**
29 | * 时间补偿值 字符串
30 | */
31 | private final static String LEGAL_OFFSET_PREFIX = "[offset:";
32 |
33 | /**
34 | * 歌曲长度
35 | */
36 | private final static String LEGAL_TOTAL_PREFIX = "[total:";
37 |
38 | @Override
39 | public boolean writer(LyricsInfo lyricsIfno, String lyricsFilePath) throws Exception {
40 | String lyricsContent = getLyricsContent(lyricsIfno);
41 | return saveLyricsFile(lyricsContent, lyricsFilePath);
42 | }
43 |
44 | @Override
45 | public String getLyricsContent(LyricsInfo lyricsIfno) throws Exception {
46 | StringBuilder lyricsCom = new StringBuilder();
47 | // 先保存所有的标签数据
48 | Map tags = lyricsIfno.getLyricsTags();
49 | for (Map.Entry entry : tags.entrySet()) {
50 | Object val = entry.getValue();
51 | if (entry.getKey().equals(LyricsTag.TAG_TITLE)) {
52 | lyricsCom.append(LEGAL_SONGNAME_PREFIX);
53 | } else if (entry.getKey().equals(LyricsTag.TAG_ARTIST)) {
54 | lyricsCom.append(LEGAL_SINGERNAME_PREFIX);
55 | } else if (entry.getKey().equals(LyricsTag.TAG_OFFSET)) {
56 | lyricsCom.append(LEGAL_OFFSET_PREFIX);
57 | } else if (entry.getKey().equals(LyricsTag.TAG_TOTAL)) {
58 | lyricsCom.append(LEGAL_TOTAL_PREFIX);
59 | } else {
60 | val = "[" + entry.getKey() + ":" + val;
61 | }
62 | lyricsCom.append(val + "]\n");
63 | }
64 |
65 | // 每行歌词内容
66 | TreeMap lyricsLineInfos = lyricsIfno
67 | .getLyricsLineInfoTreeMap();
68 | for (int i = 0; i < lyricsLineInfos.size(); i++) {
69 | LyricsLineInfo lyricsLineInfo = lyricsLineInfos.get(i);
70 |
71 | lyricsCom.append("["
72 | + TimeUtils.parseMMSSFFString(lyricsLineInfo.getStartTime())
73 | + "]");// 添加开始时间
74 |
75 | String[] lyricsWords = lyricsLineInfo.getLyricsWords();
76 | // 添加每个歌词的时间
77 | StringBuilder wordsText = new StringBuilder();
78 | int wordsDisInterval[] = lyricsLineInfo.getWordsDisInterval();
79 | for (int j = 0; j < wordsDisInterval.length; j++) {
80 | wordsText.append("<" + wordsDisInterval[j] + ">" + lyricsWords[j]);
81 | }
82 | lyricsCom.append(wordsText);
83 | lyricsCom.append("\n");
84 | }
85 | return lyricsCom.toString();
86 | }
87 |
88 | @Override
89 | public boolean isFileSupported(String ext) {
90 | return ext.equalsIgnoreCase("trc");
91 | }
92 |
93 | @Override
94 | public String getSupportFileExt() {
95 | return "trc";
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/model/LyricsInfo.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.model;
2 |
3 | import java.util.HashMap;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.TreeMap;
7 |
8 | /**
9 | * 歌词数据
10 | *
11 | * @author zhangliangming
12 | */
13 | public class LyricsInfo {
14 | /**
15 | * lrc类型
16 | */
17 | public static final int LRC = 0;
18 | /**
19 | * 动感歌词类型
20 | */
21 | public static final int DYNAMIC = 1;
22 | /**
23 | * 默认歌词类型是:动感歌词类型
24 | */
25 | private int mLyricsType = DYNAMIC;
26 |
27 | /**
28 | * 歌词格式
29 | */
30 | private String mLyricsFileExt;
31 | /**
32 | * 所有的歌词行数据
33 | */
34 | private TreeMap mLyricsLineInfoTreeMap;
35 | /**
36 | * 翻译行歌词
37 | */
38 | private List mTranslateLrcLineInfos;
39 | /**
40 | * 音译歌词行
41 | */
42 | private List mTransliterationLrcLineInfos;
43 | /**
44 | * 歌词标签
45 | */
46 | private Map mLyricsTags = new HashMap();
47 |
48 | public Map getLyricsTags() {
49 | return mLyricsTags;
50 | }
51 |
52 | public void setLyricsTags(Map lyricsTags) {
53 | this.mLyricsTags = lyricsTags;
54 | }
55 |
56 | public List getTranslateLrcLineInfos() {
57 | return mTranslateLrcLineInfos;
58 | }
59 |
60 | public void setTranslateLrcLineInfos(List translateLrcLineInfos) {
61 | this.mTranslateLrcLineInfos = translateLrcLineInfos;
62 | }
63 |
64 | public List getTransliterationLrcLineInfos() {
65 | return mTransliterationLrcLineInfos;
66 | }
67 |
68 | public void setTransliterationLrcLineInfos(List transliterationLrcLineInfos) {
69 | this.mTransliterationLrcLineInfos = transliterationLrcLineInfos;
70 | }
71 |
72 | public String getLyricsFileExt() {
73 | return mLyricsFileExt;
74 | }
75 |
76 | public void setLyricsFileExt(String lyricsFileExt) {
77 | this.mLyricsFileExt = lyricsFileExt;
78 | }
79 |
80 | public TreeMap getLyricsLineInfoTreeMap() {
81 | return mLyricsLineInfoTreeMap;
82 | }
83 |
84 | public void setLyricsLineInfoTreeMap(
85 | TreeMap lyricsLineInfoTreeMap) {
86 | this.mLyricsLineInfoTreeMap = lyricsLineInfoTreeMap;
87 | }
88 |
89 | public void setTitle(String title) {
90 |
91 | if (mLyricsTags == null) {
92 | mLyricsTags = new HashMap();
93 | }
94 | mLyricsTags.put(LyricsTag.TAG_TITLE, title);
95 |
96 | }
97 |
98 | public String getTitle() {
99 |
100 | String title = "";
101 | if (mLyricsTags != null && !mLyricsTags.isEmpty()
102 | && mLyricsTags.containsKey(LyricsTag.TAG_TITLE)) {
103 | title = (String) mLyricsTags.get(LyricsTag.TAG_TITLE);
104 | }
105 | return title;
106 |
107 | }
108 |
109 | public void setArtist(String artist) {
110 | if (mLyricsTags == null) {
111 | mLyricsTags = new HashMap();
112 | }
113 | mLyricsTags.put(LyricsTag.TAG_ARTIST, artist);
114 | }
115 |
116 | public String getArtist() {
117 |
118 | String artist = "";
119 | if (mLyricsTags != null && !mLyricsTags.isEmpty()
120 | && mLyricsTags.containsKey(LyricsTag.TAG_ARTIST)) {
121 | artist = (String) mLyricsTags.get(LyricsTag.TAG_ARTIST);
122 | }
123 | return artist;
124 |
125 | }
126 |
127 | public void setOffset(long offset) {
128 | if (mLyricsTags == null) {
129 | mLyricsTags = new HashMap();
130 | }
131 | mLyricsTags.put(LyricsTag.TAG_OFFSET, offset);
132 | }
133 |
134 | public long getOffset() {
135 |
136 | long offset = 0;
137 | if (mLyricsTags != null && !mLyricsTags.isEmpty()
138 | && mLyricsTags.containsKey(LyricsTag.TAG_OFFSET)) {
139 | try {
140 | offset = Long.parseLong((String) mLyricsTags
141 | .get(LyricsTag.TAG_OFFSET));
142 | } catch (Exception e) {
143 | e.printStackTrace();
144 | }
145 | }
146 | return offset;
147 |
148 | }
149 |
150 | public void setBy(String by) {
151 | if (mLyricsTags == null) {
152 | mLyricsTags = new HashMap();
153 | }
154 | mLyricsTags.put(LyricsTag.TAG_BY, by);
155 | }
156 |
157 | public String getBy() {
158 |
159 | String by = "";
160 | if (mLyricsTags != null && !mLyricsTags.isEmpty()
161 | && mLyricsTags.containsKey(LyricsTag.TAG_BY)) {
162 | by = (String) mLyricsTags.get(LyricsTag.TAG_BY);
163 | }
164 | return by;
165 |
166 | }
167 |
168 | public void setTotal(long total) {
169 | if (mLyricsTags == null) {
170 | mLyricsTags = new HashMap();
171 | }
172 | mLyricsTags.put(LyricsTag.TAG_TOTAL, total);
173 | }
174 |
175 | public long getTotal() {
176 |
177 | long total = 0;
178 | if (mLyricsTags != null && !mLyricsTags.isEmpty()
179 | && mLyricsTags.containsKey(LyricsTag.TAG_TOTAL)) {
180 | try {
181 | total = Long.parseLong((String) mLyricsTags
182 | .get(LyricsTag.TAG_TOTAL));
183 | } catch (Exception e) {
184 | e.printStackTrace();
185 | }
186 | }
187 | return total;
188 |
189 | }
190 |
191 | public void setLyricsType(int mLyricsType) {
192 | this.mLyricsType = mLyricsType;
193 | }
194 |
195 | public int getLyricsType() {
196 | return mLyricsType;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/model/LyricsLineInfo.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.model;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * 歌词实体类
9 | *
10 | * @author zhangliangming
11 | */
12 | public class LyricsLineInfo {
13 |
14 | /**
15 | * 歌词开始时间
16 | */
17 | private int mStartTime;
18 | /**
19 | * 歌词结束时间
20 | */
21 | private int mEndTime;
22 | /**
23 | * 该行歌词
24 | */
25 | private String mLineLyrics = "";
26 |
27 | /**
28 | * 歌词数组,用来分隔每个歌词
29 | */
30 | private String[] mLyricsWords;
31 | /**
32 | * 数组,用来存放每个歌词的时间
33 | */
34 | private int[] mWordsDisInterval;
35 |
36 | /**
37 | * 分割歌词行歌词
38 | */
39 | private List mSplitDynamicLrcLineInfos;
40 |
41 | public List getSplitLyricsLineInfos() {
42 | return mSplitDynamicLrcLineInfos;
43 | }
44 |
45 | public void setSplitLyricsLineInfos(
46 | List splitDynamicLrcLineInfos) {
47 | this.mSplitDynamicLrcLineInfos = splitDynamicLrcLineInfos;
48 | }
49 |
50 | public String[] getLyricsWords() {
51 | return mLyricsWords;
52 | }
53 |
54 | public void setLyricsWords(String[] lyricsWords) {
55 | if (lyricsWords == null) return;
56 | String[] tempArray = new String[lyricsWords.length];
57 | for (int i = 0; i < lyricsWords.length; i++) {
58 | String temp = lyricsWords[i];
59 | if (TextUtils.isEmpty(temp)) {
60 | tempArray[i] = "";
61 | } else {
62 | tempArray[i] = temp.replaceAll("\r|\n", "");
63 | }
64 | }
65 | this.mLyricsWords = tempArray;
66 | }
67 |
68 | public int[] getWordsDisInterval() {
69 | return mWordsDisInterval;
70 | }
71 |
72 | public void setWordsDisInterval(int[] wordsDisInterval) {
73 | this.mWordsDisInterval = wordsDisInterval;
74 | }
75 |
76 | public int getStartTime() {
77 | return mStartTime;
78 | }
79 |
80 | public void setStartTime(int mStartTime) {
81 | this.mStartTime = mStartTime;
82 | }
83 |
84 | public int getEndTime() {
85 | return mEndTime;
86 | }
87 |
88 | public void setEndTime(int mEndTime) {
89 | this.mEndTime = mEndTime;
90 | }
91 |
92 | public String getLineLyrics() {
93 | return mLineLyrics;
94 | }
95 |
96 | public void setLineLyrics(String mLineLyrics) {
97 | if (!TextUtils.isEmpty(mLineLyrics)) {
98 | this.mLineLyrics = mLineLyrics.replaceAll("\r|\n", "");
99 | }
100 | }
101 |
102 | /**
103 | * 复制
104 | *
105 | * @param dist 要复制的实体类
106 | * @param orig 原始实体类
107 | */
108 | public void copy(LyricsLineInfo dist, LyricsLineInfo orig) {
109 | if (orig.getWordsDisInterval() != null) {
110 | dist.setWordsDisInterval(orig.getWordsDisInterval());
111 | }
112 | dist.setStartTime(orig.getStartTime());
113 | dist.setEndTime(orig.getEndTime());
114 |
115 | if (orig.getLyricsWords() != null) {
116 | dist.setLyricsWords(orig.getLyricsWords());
117 | }
118 |
119 | dist.setLineLyrics(orig.getLineLyrics());
120 |
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/model/LyricsTag.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.model;
2 |
3 | /**
4 | * 歌词标签
5 | *
6 | * @author zhangliangming
7 | *
8 | */
9 | public class LyricsTag {
10 | /**
11 | * 歌曲名称
12 | */
13 | public static String TAG_TITLE = "lyrics.tag.title";
14 | /**
15 | * 歌手
16 | */
17 | public static String TAG_ARTIST = "lyrics.tag.artist";
18 | /**
19 | * 时间补偿值
20 | */
21 | public static String TAG_OFFSET = "lyrics.tag.offset";
22 | /**
23 | * 上传者
24 | */
25 | public static String TAG_BY = "lyrics.tag.by";
26 | /**
27 | * 歌词总时长
28 | */
29 | public static String TAG_TOTAL = "lyrics.tag.total";
30 | }
31 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/model/TranslateLrcLineInfo.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.model;
2 |
3 | import android.text.TextUtils;
4 |
5 | /**
6 | * 翻译行歌词
7 | * Created by zhangliangming on 2017/9/11.
8 | */
9 |
10 | public class TranslateLrcLineInfo {
11 |
12 | /**
13 | * 该行歌词
14 | */
15 | private String mLineLyrics = "";
16 |
17 | public String getLineLyrics() {
18 | return mLineLyrics;
19 | }
20 |
21 | public void setLineLyrics(String lineLyrics) {
22 | if (!TextUtils.isEmpty(lineLyrics))
23 | this.mLineLyrics = lineLyrics.replaceAll("\r|\n", "");
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/model/make/MakeExtraLrcLineInfo.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.model.make;
2 |
3 |
4 | /**
5 | * 制作额外歌词行数据
6 | * Created by zhangliangming on 2018-03-29.
7 | */
8 |
9 | public class MakeExtraLrcLineInfo extends MakeLrcInfo {
10 | /**
11 | * 该行额外歌词
12 | */
13 | private String mExtraLineLyrics;
14 |
15 | public String getExtraLineLyrics() {
16 | return mExtraLineLyrics;
17 | }
18 |
19 | public void setExtraLineLyrics(String mExtraLineLyrics) {
20 | this.mExtraLineLyrics = mExtraLineLyrics;
21 | }
22 |
23 | @Override
24 | public void reset() {
25 | super.reset();
26 | mExtraLineLyrics = "";
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/model/make/MakeLrcInfo.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.model.make;
2 |
3 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
4 |
5 | /**
6 | * 制作歌词信息
7 | * Created by zhangliangming on 2018-04-01.
8 | */
9 |
10 | public class MakeLrcInfo {
11 |
12 | /**
13 | * 初始
14 | */
15 | public static final int STATUS_NONE = 0;
16 |
17 | /**
18 | * 完成
19 | */
20 | public static final int STATUS_FINISH = 1;
21 | /**
22 | * 状态
23 | */
24 | private int status = STATUS_NONE;
25 |
26 | /**
27 | * 歌词索引,-1是未读,-2是已经完成
28 | */
29 | private int lrcIndex = -1;
30 | /**
31 | * 行歌词
32 | */
33 | private LyricsLineInfo lyricsLineInfo;
34 |
35 |
36 | /**
37 | * 重置
38 | */
39 | public void reset() {
40 | status = STATUS_NONE;
41 | lrcIndex = -1;
42 | }
43 |
44 | public int getStatus() {
45 | return status;
46 | }
47 |
48 | public void setStatus(int status) {
49 | if (this.status != STATUS_FINISH) {
50 | this.status = status;
51 | }
52 | }
53 |
54 | public int getLrcIndex() {
55 | return lrcIndex;
56 | }
57 |
58 | public void setLrcIndex(int lrcIndex) {
59 | this.lrcIndex = lrcIndex;
60 | }
61 |
62 | public LyricsLineInfo getLyricsLineInfo() {
63 | return lyricsLineInfo;
64 | }
65 |
66 | public void setLyricsLineInfo(LyricsLineInfo lyricsLineInfo) {
67 | this.lyricsLineInfo = lyricsLineInfo;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/model/make/MakeLrcLineInfo.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.model.make;
2 |
3 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
4 |
5 | import java.util.TreeMap;
6 |
7 | /**
8 | * 制作歌词行数据
9 | * Created by zhangliangming on 2018-03-29.
10 | */
11 |
12 | public class MakeLrcLineInfo extends MakeLrcInfo {
13 |
14 | /**
15 | * 每个字时间集合
16 | */
17 | private TreeMap mWordDisIntervals = new TreeMap();
18 |
19 | private byte[] lock = new byte[0];
20 |
21 | /**
22 | * 设置当前歌曲索引
23 | *
24 | * @param curPlayingTime
25 | */
26 | public boolean play(long curPlayingTime) {
27 | synchronized (lock) {
28 |
29 | int lrcIndex = getLrcIndex();
30 | lrcIndex++;
31 | setLrcIndex(lrcIndex);
32 | int preLrcIndex = lrcIndex - 1;
33 | if (mWordDisIntervals.containsKey(preLrcIndex)) {
34 | //设置前一个字的结束时间
35 | WordDisInterval wordDisInterval = mWordDisIntervals.get(preLrcIndex);
36 | wordDisInterval.setEndTime((int) curPlayingTime);
37 | mWordDisIntervals.put(preLrcIndex, wordDisInterval);
38 | }
39 |
40 | LyricsLineInfo lyricsLineInfo = getLyricsLineInfo();
41 | //判断是否完成
42 | if (lrcIndex == lyricsLineInfo.getLyricsWords().length) {
43 |
44 | lrcIndex = lyricsLineInfo.getLyricsWords().length - 1;
45 |
46 | //设置结束时间
47 | WordDisInterval wordDisInterval = mWordDisIntervals.get(lrcIndex);
48 | lyricsLineInfo.setEndTime(wordDisInterval.getEndTime());
49 |
50 | setStatus(STATUS_FINISH);
51 | setLrcIndex(lrcIndex);
52 |
53 | return true;
54 | }
55 |
56 | //设置当前字的开始时间
57 | WordDisInterval wordDisInterval = new WordDisInterval();
58 | wordDisInterval.setStartTime((int) curPlayingTime);
59 | mWordDisIntervals.put(lrcIndex, wordDisInterval);
60 |
61 | return false;
62 | }
63 | }
64 |
65 |
66 | /**
67 | * 行设置
68 | *
69 | * @param preLineEndTime 上一行结束时间
70 | * @param curPlayingTime 当前播放时间
71 | */
72 | public void playLine(long preLineEndTime, long curPlayingTime) {
73 | synchronized (lock) {
74 | mWordDisIntervals.clear();
75 | LyricsLineInfo lyricsLineInfo = getLyricsLineInfo();
76 | lyricsLineInfo.setStartTime((int) preLineEndTime);
77 | lyricsLineInfo.setEndTime((int) curPlayingTime);
78 | long dTime = 0;
79 | if (preLineEndTime < curPlayingTime) {
80 | dTime = curPlayingTime - preLineEndTime;
81 | }
82 | String[] lyricsWords = lyricsLineInfo.getLyricsWords();
83 | if (lyricsWords != null && lyricsWords.length > 0) {
84 | long aveTime = dTime / lyricsWords.length;
85 | for (int i = 0; i < lyricsWords.length; i++) {
86 | //设置当前字的开始时间/结束时间
87 | long startTime = lyricsLineInfo.getStartTime() + i * aveTime;
88 | WordDisInterval wordDisInterval = new WordDisInterval();
89 | wordDisInterval.setStartTime((int) startTime);
90 | wordDisInterval.setEndTime((int) (startTime + aveTime));
91 | mWordDisIntervals.put(i, wordDisInterval);
92 | }
93 | setStatus(STATUS_FINISH);
94 | setLrcIndex(lyricsWords.length - 1);
95 | }
96 | }
97 | }
98 |
99 | /**
100 | * 设置回滚
101 | */
102 | public void back() {
103 | synchronized (lock) {
104 |
105 | int lrcIndex = getLrcIndex();
106 | lrcIndex--;
107 | if (lrcIndex < -1) {
108 | lrcIndex = -1;
109 | }
110 | setLrcIndex(lrcIndex);
111 | //后退时,删除当前的歌词字时间
112 | int nextLrcIndex = lrcIndex + 1;
113 | if (mWordDisIntervals.containsKey(nextLrcIndex)) {
114 | mWordDisIntervals.remove(nextLrcIndex);
115 | }
116 | //
117 | if (mWordDisIntervals.containsKey(lrcIndex)) {
118 | WordDisInterval wordDisInterval = mWordDisIntervals.get(lrcIndex);
119 | wordDisInterval.setEndTime(0);
120 | mWordDisIntervals.put(lrcIndex, wordDisInterval);
121 | }
122 | }
123 | }
124 |
125 | @Override
126 | public void reset() {
127 | synchronized (lock) {
128 | super.reset();
129 | mWordDisIntervals.clear();
130 | }
131 | }
132 |
133 | /**
134 | * 获取该行完成后的歌词数据
135 | *
136 | * @return
137 | */
138 | public LyricsLineInfo getFinishLrcLineInfo() {
139 | synchronized (lock) {
140 | if (getStatus() == STATUS_FINISH) {
141 | int startTime = 0;
142 | int endTime = 0;
143 | int[] wDisIntervals = new int[mWordDisIntervals.size()];
144 | for (int j = 0; j < mWordDisIntervals.size(); j++) {
145 | WordDisInterval wordDisInterval = mWordDisIntervals.get(j);
146 | if (j == 0) {
147 | startTime = wordDisInterval.getStartTime();
148 | }
149 | if (j == mWordDisIntervals.size() - 1) {
150 | endTime = wordDisInterval.getEndTime();
151 |
152 | }
153 | int time = wordDisInterval.getEndTime()
154 | - wordDisInterval.getStartTime();
155 | wDisIntervals[j] = time;
156 | }
157 | LyricsLineInfo lyricsLineInfo = getLyricsLineInfo();
158 | lyricsLineInfo.setStartTime(startTime);
159 | lyricsLineInfo.setEndTime(endTime);
160 | lyricsLineInfo.setWordsDisInterval(wDisIntervals);
161 | return lyricsLineInfo;
162 | }
163 | return null;
164 | }
165 | }
166 |
167 |
168 | /**
169 | * 单个歌词字时间实体类
170 | *
171 | * @author zhangliangming
172 | */
173 | class WordDisInterval {
174 | /**
175 | * 开始时间
176 | */
177 | int startTime;
178 | /**
179 | * 结束时间
180 | */
181 | int endTime;
182 |
183 | public int getStartTime() {
184 | return startTime;
185 | }
186 |
187 | public void setStartTime(int startTime) {
188 | this.startTime = startTime;
189 | }
190 |
191 | public int getEndTime() {
192 | return endTime;
193 | }
194 |
195 | public void setEndTime(int endTime) {
196 | this.endTime = endTime;
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/CharUtils.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 | /**
4 | *
5 | * @author zhangliangming
6 | *
7 | */
8 | public class CharUtils {
9 | /**
10 | * 判断字符是不是中文,中文字符标点都可以判断
11 | *
12 | * @param c
13 | * 字符
14 | * @return
15 | */
16 | public static boolean isChinese(char c) {
17 | Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
18 | if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
19 | || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
20 | || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
21 | || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
22 | || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
23 | || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
24 | return true;
25 | }
26 | return false;
27 | }
28 |
29 | /**
30 | * 是否是日语平假名
31 | *
32 | * @param c
33 | * @return
34 | */
35 | public static boolean isHiragana(char c) {
36 | Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
37 | if (ub == Character.UnicodeBlock.HIRAGANA) {
38 | return true;
39 | }
40 | return false;
41 | }
42 |
43 | /**
44 | * 是否是韩语
45 | *
46 | * @return
47 | */
48 | public static boolean isHangulSyllables(char c) {
49 | Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
50 | if (ub == Character.UnicodeBlock.HANGUL_SYLLABLES) {
51 | return true;
52 | }
53 | return false;
54 | }
55 |
56 | /**
57 | * 判断该歌词是不是字母
58 | *
59 | * @param c
60 | * @return
61 | */
62 | public static boolean isWord(char c) {
63 | if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
64 | return true;
65 | }
66 | return false;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/ColorUtils.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 | import android.graphics.Color;
4 |
5 | /**
6 | * 颜色处理类
7 | *
8 | * @author zhangliangming
9 | */
10 | public class ColorUtils {
11 | /**
12 | * 解析颜色
13 | *
14 | * @param colorStr #ffffff 颜色字符串
15 | * @param alpha 0-255 透明度
16 | * @return
17 | */
18 | public static int parserColor(String colorStr, int alpha) {
19 | int color = Color.parseColor(colorStr);
20 | int red = (color & 0xff0000) >> 16;
21 | int green = (color & 0x00ff00) >> 8;
22 | int blue = (color & 0x0000ff);
23 | return Color.argb(alpha, red, green, blue);
24 | }
25 |
26 | /**
27 | * 解析颜色
28 | *
29 | * @param color Color.WHITE
30 | * @param alpha 0-255 透明度
31 | * @return
32 | */
33 | public static int parserColor(int color, int alpha) {
34 | int red = (color & 0xff0000) >> 16;
35 | int green = (color & 0x00ff00) >> 8;
36 | int blue = (color & 0x0000ff);
37 | return Color.argb(alpha, red, green, blue);
38 | }
39 |
40 | public static int parserColor(int color) {
41 | int red = (color & 0xff0000) >> 16;
42 | int green = (color & 0x00ff00) >> 8;
43 | int blue = (color & 0x0000ff);
44 | return Color.argb(255, red, green, blue);
45 | }
46 |
47 |
48 | /**
49 | * 解析颜色
50 | *
51 | * @param colorStr #ffffff 颜色字符串
52 | * @return
53 | */
54 | public static int parserColor(String colorStr) {
55 | return Color.parseColor(colorStr);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 | import java.io.File;
4 | import java.text.DecimalFormat;
5 |
6 | /**
7 | *
8 | * @author zhangliangming
9 | *
10 | */
11 | public class FileUtils {
12 | public static String getFileExt(File file) {
13 | return getFileExt(file.getName());
14 | }
15 |
16 | public static String removeExt(String s) {
17 | int index = s.lastIndexOf(".");
18 | if (index == -1)
19 | index = s.length();
20 | return s.substring(0, index);
21 | }
22 |
23 | public static String getFileExt(String fileName) {
24 | int pos = fileName.lastIndexOf(".");
25 | if (pos == -1)
26 | return "";
27 | return fileName.substring(pos + 1).toLowerCase();
28 | }
29 |
30 | /**
31 | * 计算文件的大小,返回相关的m字符串
32 | *
33 | * @param fileS
34 | * @return
35 | */
36 | public static String getFileSize(long fileS) {// 转换文件大小
37 | DecimalFormat df = new DecimalFormat("#.00");
38 | String fileSizeString = "";
39 | if (fileS < 1024) {
40 | fileSizeString = df.format((double) fileS) + "B";
41 | } else if (fileS < 1048576) {
42 | fileSizeString = df.format((double) fileS / 1024) + "K";
43 | } else if (fileS < 1073741824) {
44 | fileSizeString = df.format((double) fileS / 1048576) + "M";
45 | } else {
46 | fileSizeString = df.format((double) fileS / 1073741824) + "G";
47 | }
48 | return fileSizeString;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/LyricsIOUtils.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 |
4 | import com.zlm.hp.lyrics.formats.LyricsFileReader;
5 | import com.zlm.hp.lyrics.formats.LyricsFileWriter;
6 | import com.zlm.hp.lyrics.formats.hrc.HrcLyricsFileReader;
7 | import com.zlm.hp.lyrics.formats.hrc.HrcLyricsFileWriter;
8 | import com.zlm.hp.lyrics.formats.krc.KrcLyricsFileReader;
9 | import com.zlm.hp.lyrics.formats.krc.KrcLyricsFileWriter;
10 | import com.zlm.hp.lyrics.formats.ksc.KscLyricsFileReader;
11 | import com.zlm.hp.lyrics.formats.ksc.KscLyricsFileWriter;
12 | import com.zlm.hp.lyrics.formats.lrc.LrcLyricsFileReader;
13 | import com.zlm.hp.lyrics.formats.lrc.LrcLyricsFileWriter;
14 | import com.zlm.hp.lyrics.formats.lrcwy.WYLyricsFileReader;
15 | import com.zlm.hp.lyrics.formats.lrcwy.WYLyricsFileWriter;
16 | import com.zlm.hp.lyrics.formats.trc.TrcLyricsFileReader;
17 | import com.zlm.hp.lyrics.formats.trc.TrcLyricsFileWriter;
18 |
19 | import java.io.File;
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * 歌词io操作
25 | * @author zhangliangming
26 | *
27 | */
28 | public class LyricsIOUtils {
29 | private static ArrayList readers;
30 | private static ArrayList writers;
31 |
32 | static {
33 | readers = new ArrayList();
34 | readers.add(new HrcLyricsFileReader());
35 | readers.add(new KscLyricsFileReader());
36 | readers.add(new KrcLyricsFileReader());
37 | readers.add(new TrcLyricsFileReader());
38 | readers.add(new WYLyricsFileReader());
39 | readers.add(new LrcLyricsFileReader());
40 | //
41 | writers = new ArrayList();
42 | writers.add(new HrcLyricsFileWriter());
43 | writers.add(new KscLyricsFileWriter());
44 | writers.add(new KrcLyricsFileWriter());
45 | writers.add(new TrcLyricsFileWriter());
46 | writers.add(new WYLyricsFileWriter());
47 | writers.add(new LrcLyricsFileWriter());
48 | }
49 |
50 | /**
51 | * 获取支持的歌词文件格式
52 | *
53 | * @return
54 | */
55 | public static List getSupportLyricsExts() {
56 | List lrcExts = new ArrayList();
57 | for (LyricsFileReader lyricsFileReader : readers) {
58 | lrcExts.add(lyricsFileReader.getSupportFileExt());
59 | }
60 | return lrcExts;
61 | }
62 |
63 | /**
64 | * 获取歌词文件读取器
65 | *
66 | * @param file
67 | * @return
68 | */
69 | public static LyricsFileReader getLyricsFileReader(File file) {
70 | return getLyricsFileReader(file.getName());
71 | }
72 |
73 | /**
74 | * 获取歌词文件读取器
75 | *
76 | * @param fileName
77 | * @return
78 | */
79 | public static LyricsFileReader getLyricsFileReader(String fileName) {
80 | String ext = FileUtils.getFileExt(fileName);
81 | for (LyricsFileReader lyricsFileReader : readers) {
82 | if (lyricsFileReader.isFileSupported(ext)) {
83 | return lyricsFileReader;
84 | }
85 | }
86 | return null;
87 | }
88 |
89 | /**
90 | * 获取歌词保存器
91 | *
92 | * @param file
93 | * @return
94 | */
95 | public static LyricsFileWriter getLyricsFileWriter(File file) {
96 | return getLyricsFileWriter(file.getName());
97 | }
98 |
99 | /**
100 | * 获取歌词保存器
101 | *
102 | * @param fileName
103 | * @return
104 | */
105 | public static LyricsFileWriter getLyricsFileWriter(String fileName) {
106 | String ext = FileUtils.getFileExt(fileName);
107 | for (LyricsFileWriter lyricsFileWriter : writers) {
108 | if (lyricsFileWriter.isFileSupported(ext)) {
109 | return lyricsFileWriter;
110 | }
111 | }
112 | return null;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/StringCompressUtils.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.nio.charset.Charset;
8 | import java.util.zip.DeflaterOutputStream;
9 | import java.util.zip.InflaterInputStream;
10 |
11 | /**
12 | * 字符串解压和压缩
13 | *
14 | * @author zhangliangming
15 | */
16 | public class StringCompressUtils {
17 |
18 | /**
19 | * 压缩
20 | *
21 | * @param text
22 | * @param charset
23 | * @return
24 | */
25 | public static byte[] compress(String text, Charset charset) throws Exception {
26 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
27 |
28 | OutputStream out = new DeflaterOutputStream(baos);
29 | out.write(text.getBytes(charset));
30 | out.close();
31 |
32 | return baos.toByteArray();
33 | }
34 |
35 | /**
36 | * @param input
37 | * @param charset
38 | * @return
39 | * @throws Exception
40 | */
41 | public static String decompress(InputStream input, Charset charset)
42 | throws Exception {
43 | return decompress(toByteArray(input), charset);
44 | }
45 |
46 | /**
47 | * 解压
48 | *
49 | * @param bytes
50 | * @param charset
51 | * @return
52 | */
53 | public static String decompress(byte[] bytes, Charset charset) throws Exception {
54 | InputStream in = new InflaterInputStream(
55 | new ByteArrayInputStream(bytes));
56 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
57 |
58 | byte[] buffer = new byte[8192];
59 | int len;
60 | while ((len = in.read(buffer)) > 0)
61 | baos.write(buffer, 0, len);
62 | return new String(baos.toByteArray(), charset);
63 |
64 | }
65 |
66 | /**
67 | * @param input
68 | * @return
69 | */
70 | private static byte[] toByteArray(InputStream input) throws Exception {
71 | ByteArrayOutputStream output = new ByteArrayOutputStream();
72 | copy(input, output);
73 | return output.toByteArray();
74 | }
75 |
76 | private static int copy(InputStream input, OutputStream output)
77 | throws Exception {
78 | long count = copyLarge(input, output);
79 | if (count > 2147483647L) {
80 | return -1;
81 | }
82 | return (int) count;
83 | }
84 |
85 | private static long copyLarge(InputStream input, OutputStream output)
86 | throws Exception {
87 | byte[] buffer = new byte[4096];
88 | long count = 0L;
89 | int n = 0;
90 | while (-1 != (n = input.read(buffer))) {
91 | output.write(buffer, 0, n);
92 | count += n;
93 | }
94 | return count;
95 | }
96 | }
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 | /**
4 | * Created by zhangliangming on 2018-02-23.
5 | */
6 |
7 | public class StringUtils {
8 |
9 |
10 | /**
11 | *
12 | * Checks if a String is whitespace, empty ("") or null.
13 | *
14 | *
15 | *
16 | * StringUtils.isBlank(null) = true
17 | * StringUtils.isBlank("") = true
18 | * StringUtils.isBlank(" ") = true
19 | * StringUtils.isBlank("bob") = false
20 | * StringUtils.isBlank(" bob ") = false
21 | *
22 | *
23 | * @param str
24 | * the String to check, may be null
25 | * @return true
if the String is null, empty or whitespace
26 | * @since 2.0
27 | */
28 | public static boolean isBlank(String str) {
29 | int strLen;
30 | if (str == null || (strLen = str.length()) == 0) {
31 | return true;
32 | }
33 | for (int i = 0; i < strLen; i++) {
34 | if ((Character.isWhitespace(str.charAt(i)) == false)) {
35 | return false;
36 | }
37 | }
38 | return true;
39 | }
40 |
41 | /**
42 | *
43 | * Checks if a String is not empty (""), not null and not whitespace only.
44 | *
45 | *
46 | *
47 | * StringUtils.isNotBlank(null) = false
48 | * StringUtils.isNotBlank("") = false
49 | * StringUtils.isNotBlank(" ") = false
50 | * StringUtils.isNotBlank("bob") = true
51 | * StringUtils.isNotBlank(" bob ") = true
52 | *
53 | *
54 | * @param str
55 | * the String to check, may be null
56 | * @return true
if the String is not empty and not null and not
57 | * whitespace
58 | * @since 2.0
59 | */
60 | public static boolean isNotBlank(String str) {
61 | int strLen;
62 | if (str == null || (strLen = str.length()) == 0) {
63 | return false;
64 | }
65 | for (int i = 0; i < strLen; i++) {
66 | if ((Character.isWhitespace(str.charAt(i)) == false)) {
67 | return true;
68 | }
69 | }
70 | return false;
71 | }
72 |
73 | /**
74 | *
75 | * Checks if the String contains only unicode digits. A decimal point is not
76 | * a unicode digit and returns false.
77 | *
78 | *
79 | *
80 | * null
will return false
. An empty String ("")
81 | * will return true
.
82 | *
83 | *
84 | *
85 | * StringUtils.isNumeric(null) = false
86 | * StringUtils.isNumeric("") = true
87 | * StringUtils.isNumeric(" ") = false
88 | * StringUtils.isNumeric("123") = true
89 | * StringUtils.isNumeric("12 3") = false
90 | * StringUtils.isNumeric("ab2c") = false
91 | * StringUtils.isNumeric("12-3") = false
92 | * StringUtils.isNumeric("12.3") = false
93 | *
94 | *
95 | * @param str
96 | * the String to check, may be null
97 | * @return true
if only contains digits, and is non-null
98 | */
99 | public static boolean isNumeric(String str) {
100 | if (str == null) {
101 | return false;
102 | }
103 | int sz = str.length();
104 | for (int i = 0; i < sz; i++) {
105 | if (Character.isDigit(str.charAt(i)) == false) {
106 | return false;
107 | }
108 | }
109 | return true;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/TimeUtils.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 | /**
4 | * @author zhangliangming
5 | */
6 | public class TimeUtils {
7 | /**
8 | * @param timeString 时间字符串 00:00.00/00:00.000
9 | * @return
10 | * @功能 将时间字符串转换成整数
11 | */
12 | public static int parseInteger(String timeString) {
13 | timeString = timeString.replace(":", ".");
14 | timeString = timeString.replace(".", "@");
15 | String timedata[] = timeString.split("@");
16 | if (timedata.length == 3) {
17 | int m = Integer.parseInt(timedata[0]); // 分
18 | int s = Integer.parseInt(timedata[1]); // 秒
19 | int ms = 0;
20 | //部分lrc歌词,只精确到10倍毫秒
21 | if (timedata[2].length() == 3) {
22 | ms = Integer.parseInt(timedata[2]); // 毫秒
23 | } else {
24 | ms = Integer.parseInt(timedata[2]) * 10; // 毫秒
25 | }
26 |
27 | int currTime = (m * 60 + s) * 1000 + ms;
28 | return currTime;
29 | } else if (timedata.length == 2) {
30 | int m = Integer.parseInt(timedata[0]); // 分
31 | int s = Integer.parseInt(timedata[1]); // 秒
32 | int currTime = (m * 60 + s) * 1000;
33 | return currTime;
34 | }
35 | return 0;
36 | }
37 |
38 | /**
39 | * 毫秒转时间字符串
40 | *
41 | * @param msecTotal
42 | * @return 00:00.000
43 | */
44 | public static String parseMMSSFFFString(int msecTotal) {
45 | int msec = msecTotal % 1000;
46 | msecTotal /= 1000;
47 | int minute = msecTotal / 60;
48 | int second = msecTotal % 60;
49 | minute %= 60;
50 | return String.format("%02d:%02d.%03d", minute, second, msec);
51 | }
52 |
53 | /**
54 | * 毫秒转时间字符串
55 | *
56 | * @param msecTotal
57 | * @return 00:00.00
58 | */
59 | public static String parseMMSSFFString(int msecTotal) {
60 | int msec = msecTotal % 1000 / 10;
61 | msecTotal /= 1000;
62 | int minute = msecTotal / 60;
63 | int second = msecTotal % 60;
64 | minute %= 60;
65 | return String.format("%02d:%02d.%02d", minute, second, msec);
66 | }
67 |
68 | /**
69 | * 毫秒转时间字符串
70 | *
71 | * @param msecTotal
72 | * @return 00:00
73 | */
74 | public static String parseMMSSString(int msecTotal) {
75 | msecTotal /= 1000;
76 | int minute = msecTotal / 60;
77 | int second = msecTotal % 60;
78 | minute %= 60;
79 | return String.format("%02d:%02d", minute, second);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/utils/UnicodeInputStream.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.utils;
2 |
3 | import java.io.*;
4 |
5 | /**
6 | * This inputstream will recognize unicode BOM marks and will skip bytes if
7 | * getEncoding() method is called before any of the read(...) methods.
8 | *
9 | * Usage pattern: String enc = "ISO-8859-1"; // or NULL to use systemdefault
10 | * FileInputStream fis = new FileInputStream(file); UnicodeInputStream uin = new
11 | * UnicodeInputStream(fis, enc); enc = uin.getEncoding(); // check and skip
12 | * possible BOM bytes InputStreamReader in; if (enc == null) in = new
13 | * InputStreamReader(uin); else in = new InputStreamReader(uin, enc);
14 | */
15 | public class UnicodeInputStream extends InputStream {
16 | PushbackInputStream internalIn;
17 | boolean isInited = false;
18 | String defaultEnc;
19 | String encoding;
20 |
21 | private static final int BOM_SIZE = 4;
22 |
23 | public UnicodeInputStream(InputStream in, String defaultEnc) {
24 | internalIn = new PushbackInputStream(in, BOM_SIZE);
25 | this.defaultEnc = defaultEnc;
26 | }
27 |
28 | public String getDefaultEncoding() {
29 | return defaultEnc;
30 | }
31 |
32 | public String getEncoding() {
33 | if (!isInited) {
34 | try {
35 | init();
36 | } catch (IOException ex) {
37 | IllegalStateException ise = new IllegalStateException(
38 | "Init method failed.");
39 | ise.initCause(ise);
40 | throw ise;
41 | }
42 | }
43 | return encoding;
44 | }
45 |
46 | /**
47 | * Read-ahead four bytes and check for BOM marks. Extra bytes are unread
48 | * back to the stream, only BOM bytes are skipped.
49 | */
50 | protected void init() throws IOException {
51 | if (isInited)
52 | return;
53 |
54 | byte bom[] = new byte[BOM_SIZE];
55 | int n, unread;
56 | n = internalIn.read(bom, 0, bom.length);
57 |
58 | if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00)
59 | && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) {
60 | encoding = "UTF-32BE";
61 | unread = n - 4;
62 | } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)
63 | && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) {
64 | encoding = "UTF-32LE";
65 | unread = n - 4;
66 | } else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB)
67 | && (bom[2] == (byte) 0xBF)) {
68 | encoding = "UTF-8";
69 | unread = n - 3;
70 | } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
71 | encoding = "UTF-16BE";
72 | unread = n - 2;
73 | } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
74 | encoding = "UTF-16LE";
75 | unread = n - 2;
76 | } else {
77 | // Unicode BOM mark not found, unread all bytes
78 | encoding = defaultEnc;
79 | unread = n;
80 | }
81 | // System.out.println("read=" + n + ", unread=" + unread);
82 |
83 | if (unread > 0)
84 | internalIn.unread(bom, (n - unread), unread);
85 |
86 | isInited = true;
87 | }
88 |
89 | public void close() throws IOException {
90 | // init();
91 | isInited = true;
92 | internalIn.close();
93 | }
94 |
95 | public int read() throws IOException {
96 | // init();
97 | isInited = true;
98 | return internalIn.read();
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/widget/FloatLyricsView.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.widget;
2 |
3 |
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Typeface;
8 | import android.util.AttributeSet;
9 | import android.util.DisplayMetrics;
10 | import android.view.Display;
11 | import android.view.WindowManager;
12 |
13 | import com.zlm.hp.lyrics.LyricsReader;
14 | import com.zlm.hp.lyrics.model.LyricsInfo;
15 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
16 | import com.zlm.hp.lyrics.utils.LyricsUtils;
17 |
18 | import java.util.List;
19 | import java.util.TreeMap;
20 |
21 | /**
22 | * @Description: 双行歌词,支持翻译(该歌词在这里只以动感歌词的形式显示)和音译歌词(注:不支持lrc歌词的显示)
23 | * @author: zhangliangming
24 | * @date: 2018-04-21 11:43
25 | **/
26 | public class FloatLyricsView extends AbstractLrcView {
27 |
28 | /**
29 | * 歌词居左
30 | */
31 | public static final int ORIENTATION_LEFT = 0;
32 | /**
33 | * 歌词居中
34 | */
35 | public static final int ORIENTATION_CENTER = 1;
36 | /**
37 | *
38 | */
39 | private int mOrientation = ORIENTATION_LEFT;
40 |
41 | public FloatLyricsView(Context context) {
42 | super(context);
43 | init(context);
44 | }
45 |
46 | public FloatLyricsView(Context context, AttributeSet attrs) {
47 | super(context, attrs);
48 | init(context);
49 | }
50 |
51 | /**
52 | * @throws
53 | * @Description: 初始
54 | * @param:
55 | * @return:
56 | * @author: zhangliangming
57 | * @date: 2018-04-21 9:08
58 | */
59 | private void init(Context context) {
60 |
61 | //获取屏幕宽度
62 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
63 | Display display = wm.getDefaultDisplay();
64 | DisplayMetrics displayMetrics = new DisplayMetrics();
65 | display.getMetrics(displayMetrics);
66 | int screensWidth = displayMetrics.widthPixels;
67 |
68 | //设置歌词的最大宽度
69 | int textMaxWidth = screensWidth / 3 * 2;
70 | setTextMaxWidth(textMaxWidth);
71 |
72 | }
73 |
74 | @Override
75 | protected void onDrawLrcView(Canvas canvas) {
76 | drawFloatLrcView(canvas);
77 | }
78 |
79 | @Override
80 | protected void updateView(long playProgress) {
81 | updateFloatLrcView(playProgress);
82 | }
83 |
84 |
85 | /**
86 | * 绘画歌词
87 | *
88 | * @param canvas
89 | */
90 | private void drawFloatLrcView(Canvas canvas) {
91 | int extraLrcStatus = getExtraLrcStatus();
92 | //绘画歌词
93 | if (extraLrcStatus == AbstractLrcView.EXTRALRCSTATUS_NOSHOWEXTRALRC) {
94 | LyricsReader lyricsReader = getLyricsReader();
95 | if (lyricsReader.getLyricsType() == LyricsInfo.LRC) {
96 | //绘画lrc歌词
97 | drawLyrics(canvas);
98 | } else {
99 | //只显示默认歌词
100 | drawDynamicLyrics(canvas);
101 | }
102 | } else {
103 | //显示翻译歌词 OR 音译歌词
104 | drawDynamiAndExtraLyrics(canvas);
105 | }
106 |
107 | }
108 |
109 | /**
110 | * 绘画lrc歌词
111 | *
112 | * @param canvas
113 | */
114 | private void drawLyrics(Canvas canvas) {
115 | //获取数据
116 | TreeMap lrcLineInfos = getLrcLineInfos();
117 | int lyricsLineNum = getLyricsLineNum();
118 | float lyricsWordHLTime = getLyricsWordHLTime();
119 | Paint paint = getPaint();
120 | Paint paintHL = getPaintHL();
121 | Paint paintOutline = getPaintOutline();
122 | int[] paintColors = getPaintColors();
123 | int[] paintHLColors = getPaintHLColors();
124 | float spaceLineHeight = getSpaceLineHeight();
125 | float paddingLeftOrRight = getPaddingLeftOrRight();
126 |
127 | LyricsLineInfo lyricsLineInfo = lrcLineInfos.get(lyricsLineNum);
128 | // 当行歌词
129 | String curLyrics = lyricsLineInfo.getLineLyrics();
130 | float curLrcTextWidth = LyricsUtils.getTextWidth(paint, curLyrics);
131 | // 当前歌词行的x坐标
132 | float textX = 0;
133 | // 当前歌词行的y坐标
134 | float textY = 0;
135 |
136 | float lineLyricsHLWidth = LyricsUtils.getLrcHLWidth(paint, lrcLineInfos, lyricsLineInfo, lyricsLineNum, lyricsWordHLTime);
137 | float topPadding = (getHeight() - spaceLineHeight - 2 * LyricsUtils.getTextHeight(paint)) / 2;
138 | if (lyricsLineNum % 2 == 0) {
139 | textY = topPadding + LyricsUtils.getTextHeight(paint);
140 |
141 | if (mOrientation == ORIENTATION_LEFT || curLrcTextWidth > getWidth()) {
142 | textX = LyricsUtils.getFristLrcMoveTextX(curLrcTextWidth, lineLyricsHLWidth, getWidth(), paddingLeftOrRight);
143 | } else {
144 | textX = LyricsUtils.getHLMoveTextX(curLrcTextWidth, lineLyricsHLWidth, getWidth(), paddingLeftOrRight);
145 | }
146 |
147 |
148 | if (lyricsLineNum + 1 < lrcLineInfos.size()) {
149 | float nextLrcTextY = textY + spaceLineHeight + LyricsUtils.getTextHeight(paint);
150 |
151 | String lrcRightText = lrcLineInfos.get(
152 | lyricsLineNum + 1).getLineLyrics();
153 | float lrcRightTextWidth = LyricsUtils.getTextWidth(paint, lrcRightText);
154 | float textRightX = 0;
155 |
156 | if (mOrientation == ORIENTATION_LEFT || lrcRightTextWidth > getWidth()) {
157 | textRightX = getWidth() - lrcRightTextWidth - paddingLeftOrRight;
158 | } else {
159 | textRightX = (getWidth() - lrcRightTextWidth) / 2;
160 | }
161 |
162 |
163 | LyricsUtils.drawOutline(canvas, paintOutline, lrcRightText, textRightX, nextLrcTextY);
164 | LyricsUtils.drawText(canvas, paint, paintColors, lrcRightText, textRightX,
165 | nextLrcTextY);
166 | }
167 |
168 | } else {
169 |
170 | float preLrcTextY = topPadding + LyricsUtils.getTextHeight(paint);
171 | textY = preLrcTextY + spaceLineHeight + LyricsUtils.getTextHeight(paint);
172 |
173 |
174 | if (mOrientation == ORIENTATION_LEFT || curLrcTextWidth > getWidth()) {
175 | textX = LyricsUtils.getSecondLrcMoveTextX(curLrcTextWidth, lineLyricsHLWidth, getWidth(), paddingLeftOrRight);
176 | } else {
177 | textX = (getWidth() - curLrcTextWidth) / 2;
178 | }
179 |
180 |
181 |
182 | if (lyricsLineNum + 1 < lrcLineInfos.size()) {
183 | String lrcLeftText = lrcLineInfos.get(
184 | lyricsLineNum + 1).getLineLyrics();
185 | float textLeftX = 0;
186 | float lrcLeftTextWidth = LyricsUtils.getTextWidth(paint, lrcLeftText);
187 | if (mOrientation == ORIENTATION_LEFT || lrcLeftTextWidth > getWidth()) {
188 | textLeftX = paddingLeftOrRight;
189 | } else {
190 | textLeftX = (getWidth() - lrcLeftTextWidth) / 2;
191 | }
192 |
193 | LyricsUtils.drawOutline(canvas, paintOutline, lrcLeftText, textLeftX,
194 | preLrcTextY);
195 | LyricsUtils.drawText(canvas, paint, paintColors, lrcLeftText, textLeftX,
196 | preLrcTextY);
197 | }
198 | }
199 |
200 | //画歌词
201 | LyricsUtils.drawOutline(canvas, paintOutline, curLyrics, textX, textY);
202 | LyricsUtils.drawText(canvas, paintHL, paintHLColors, curLyrics, textX, textY);
203 | }
204 |
205 | /**
206 | * 绘画歌词
207 | *
208 | * @param canvas
209 | */
210 | private void drawDynamicLyrics(Canvas canvas) {
211 | //获取数据
212 | LyricsReader lyricsReader = getLyricsReader();
213 | TreeMap lrcLineInfos = getLrcLineInfos();
214 | int lyricsLineNum = getLyricsLineNum();
215 | int splitLyricsLineNum = getSplitLyricsLineNum();
216 | int splitLyricsWordIndex = getSplitLyricsWordIndex();
217 | float lyricsWordHLTime = getLyricsWordHLTime();
218 | Paint paint = getPaint();
219 | Paint paintHL = getPaintHL();
220 | Paint paintOutline = getPaintOutline();
221 | int[] paintColors = getPaintColors();
222 | int[] paintHLColors = getPaintHLColors();
223 | float spaceLineHeight = getSpaceLineHeight();
224 | float paddingLeftOrRight = getPaddingLeftOrRight();
225 |
226 |
227 | // 先设置当前歌词,之后再根据索引判断是否放在左边还是右边
228 | List splitLyricsLineInfos = lrcLineInfos.get(lyricsLineNum).getSplitLyricsLineInfos();
229 | LyricsLineInfo lyricsLineInfo = splitLyricsLineInfos.get(splitLyricsLineNum);
230 | //获取行歌词高亮宽度
231 | float lineLyricsHLWidth = LyricsUtils.getLineLyricsHLWidth(lyricsReader.getLyricsType(), paint, lyricsLineInfo, splitLyricsWordIndex, lyricsWordHLTime);
232 | // 当行歌词
233 | String curLyrics = lyricsLineInfo.getLineLyrics();
234 | float curLrcTextWidth = LyricsUtils.getTextWidth(paint, curLyrics);
235 | // 当前歌词行的x坐标
236 | float textX = 0;
237 | // 当前歌词行的y坐标
238 | float textY = 0;
239 | int splitLyricsRealLineNum = LyricsUtils.getSplitLyricsRealLineNum(lrcLineInfos, lyricsLineNum, splitLyricsLineNum);
240 | float topPadding = (getHeight() - spaceLineHeight - 2 * LyricsUtils.getTextHeight(paint)) / 2;
241 | if (splitLyricsRealLineNum % 2 == 0) {
242 | if (mOrientation == ORIENTATION_LEFT || curLrcTextWidth > getWidth()) {
243 | textX = paddingLeftOrRight;
244 | } else {
245 | textX = (getWidth() - curLrcTextWidth) / 2;
246 | }
247 | textY = topPadding + LyricsUtils.getTextHeight(paint);
248 | float nextLrcTextY = textY + spaceLineHeight + LyricsUtils.getTextHeight(paint);
249 |
250 | // 画下一句的歌词,该下一句还在该行的分割集合里面
251 | if (splitLyricsLineNum + 1 < splitLyricsLineInfos.size()) {
252 | String lrcRightText = splitLyricsLineInfos.get(
253 | splitLyricsLineNum + 1).getLineLyrics();
254 | float lrcRightTextWidth = LyricsUtils.getTextWidth(paint, lrcRightText);
255 | float textRightX = 0;
256 |
257 | if (mOrientation == ORIENTATION_LEFT || lrcRightTextWidth > getWidth()) {
258 | textRightX = getWidth() - lrcRightTextWidth - paddingLeftOrRight;
259 | } else {
260 | textRightX = (getWidth() - lrcRightTextWidth) / 2;
261 | }
262 |
263 | LyricsUtils.drawOutline(canvas, paintOutline, lrcRightText, textRightX, nextLrcTextY);
264 |
265 | LyricsUtils.drawText(canvas, paint, paintColors, lrcRightText, textRightX,
266 | nextLrcTextY);
267 |
268 | } else if (lyricsLineNum + 1 < lrcLineInfos.size()) {
269 | // 画下一句的歌词,该下一句不在该行分割歌词里面,需要从原始下一行的歌词里面找
270 | List nextSplitLyricsLineInfos = lrcLineInfos.get(lyricsLineNum + 1).getSplitLyricsLineInfos();
271 | String lrcRightText = nextSplitLyricsLineInfos.get(0).getLineLyrics();
272 | float lrcRightTextWidth = LyricsUtils.getTextWidth(paint, lrcRightText);
273 | float textRightX = 0;
274 |
275 | if (mOrientation == ORIENTATION_LEFT || lrcRightTextWidth > getWidth()) {
276 | textRightX = getWidth() - lrcRightTextWidth - paddingLeftOrRight;
277 | } else {
278 | textRightX = (getWidth() - lrcRightTextWidth) / 2;
279 | }
280 |
281 | LyricsUtils.drawOutline(canvas, paintOutline, lrcRightText, textRightX,
282 | nextLrcTextY);
283 |
284 | LyricsUtils.drawText(canvas, paint, paintColors, lrcRightText, textRightX, nextLrcTextY);
285 | }
286 |
287 | } else {
288 | if (mOrientation == ORIENTATION_LEFT || curLrcTextWidth > getWidth()) {
289 | textX = getWidth() - curLrcTextWidth - paddingLeftOrRight;
290 | } else {
291 | textX = (getWidth() - curLrcTextWidth) / 2;
292 | }
293 | float preLrcTextY = topPadding + LyricsUtils.getTextHeight(paint);
294 | textY = preLrcTextY + spaceLineHeight + LyricsUtils.getTextHeight(paint);
295 |
296 | // 画下一句的歌词,该下一句还在该行的分割集合里面
297 | if (splitLyricsLineNum + 1 < splitLyricsLineInfos.size()) {
298 | String lrcLeftText = splitLyricsLineInfos.get(
299 | splitLyricsLineNum + 1).getLineLyrics();
300 | float lrcLeftTextWidth = LyricsUtils.getTextWidth(paint, lrcLeftText);
301 |
302 | float textLeftX = 0;
303 | if (mOrientation == ORIENTATION_LEFT || lrcLeftTextWidth > getWidth()) {
304 | textLeftX = paddingLeftOrRight;
305 | } else {
306 | textLeftX = (getWidth() - lrcLeftTextWidth) / 2;
307 | }
308 |
309 | LyricsUtils.drawOutline(canvas, paintOutline, lrcLeftText, textLeftX,
310 | preLrcTextY);
311 | LyricsUtils.drawText(canvas, paint, paintColors, lrcLeftText, textLeftX,
312 | preLrcTextY);
313 |
314 | } else if (lyricsLineNum + 1 < lrcLineInfos.size()) {
315 | // 画下一句的歌词,该下一句不在该行分割歌词里面,需要从原始下一行的歌词里面找
316 | List nextSplitLyricsLineInfos = lrcLineInfos.get(lyricsLineNum + 1).getSplitLyricsLineInfos();
317 | String lrcLeftText = nextSplitLyricsLineInfos.get(0).getLineLyrics();
318 | float lrcLeftTextWidth = LyricsUtils.getTextWidth(paint, lrcLeftText);
319 |
320 | float textLeftX = 0;
321 | if (mOrientation == ORIENTATION_LEFT || lrcLeftTextWidth > getWidth()) {
322 | textLeftX = paddingLeftOrRight;
323 | } else {
324 | textLeftX = (getWidth() - lrcLeftTextWidth) / 2;
325 | }
326 |
327 | LyricsUtils.drawOutline(canvas, paintOutline, lrcLeftText, textLeftX,
328 | preLrcTextY);
329 | LyricsUtils.drawText(canvas, paint, paintColors, lrcLeftText, textLeftX,
330 | preLrcTextY);
331 | }
332 | }
333 | //画歌词
334 | LyricsUtils.drawOutline(canvas, paintOutline, curLyrics, textX, textY);
335 | LyricsUtils.drawDynamicText(canvas, paint, paintHL, paintColors, paintHLColors, curLyrics, lineLyricsHLWidth, textX, textY);
336 | }
337 |
338 |
339 | /**
340 | * 绘画歌词和额外歌词
341 | *
342 | * @param canvas
343 | */
344 | private void drawDynamiAndExtraLyrics(Canvas canvas) {
345 | //获取数据
346 | LyricsReader lyricsReader = getLyricsReader();
347 | Paint paint = getPaint();
348 | Paint paintHL = getPaintHL();
349 | Paint paintOutline = getPaintOutline();
350 | Paint extraLrcPaint = getExtraLrcPaint();
351 | Paint extraLrcPaintHL = getExtraLrcPaintHL();
352 | Paint extraLrcPaintOutline = getExtraLrcPaintOutline();
353 | int[] paintColors = getPaintColors();
354 | int[] paintHLColors = getPaintHLColors();
355 | int extraLrcStatus = getExtraLrcStatus();
356 | TreeMap lrcLineInfos = getLrcLineInfos();
357 | int lyricsLineNum = getLyricsLineNum();
358 | int lyricsWordIndex = getLyricsWordIndex();
359 | int extraLyricsWordIndex = getExtraLyricsWordIndex();
360 | float lyricsWordHLTime = getLyricsWordHLTime();
361 | float translateLyricsWordHLTime = getTranslateLyricsWordHLTime();
362 | float extraLrcSpaceLineHeight = getExtraLrcSpaceLineHeight();
363 | float paddingLeftOrRight = getPaddingLeftOrRight();
364 | int translateDrawType = getTranslateDrawType();
365 | List translateLrcLineInfos = getTranslateLrcLineInfos();
366 | List transliterationLrcLineInfos = getTransliterationLrcLineInfos();
367 |
368 | //
369 | float topPadding = (getHeight() - extraLrcSpaceLineHeight - LyricsUtils.getTextHeight(paint) - LyricsUtils.getTextHeight(extraLrcPaint)) / 2;
370 | // 当前歌词行的y坐标
371 | float lrcTextY = topPadding + LyricsUtils.getTextHeight(paint);
372 | //额外歌词行的y坐标
373 | float extraLrcTextY = lrcTextY + extraLrcSpaceLineHeight + LyricsUtils.getTextHeight(extraLrcPaint);
374 |
375 | LyricsLineInfo lyricsLineInfo = lrcLineInfos.get(lyricsLineNum);
376 | //获取行歌词高亮宽度
377 | float lineLyricsHLWidth = LyricsUtils.getLineLyricsHLWidth(lyricsReader.getLyricsType(), paint, lyricsLineInfo, lyricsWordIndex, lyricsWordHLTime);
378 | //画默认歌词
379 | LyricsUtils.drawDynamiLyrics(canvas, lyricsReader.getLyricsType(), paint, paintHL, paintOutline, lyricsLineInfo, lineLyricsHLWidth, getWidth(), lyricsWordIndex, lyricsWordHLTime, lrcTextY, paddingLeftOrRight, paintColors, paintHLColors);
380 |
381 | //显示翻译歌词
382 | if (lyricsReader.getLyricsType() == LyricsInfo.DYNAMIC && extraLrcStatus == AbstractLrcView.EXTRALRCSTATUS_SHOWTRANSLATELRC && translateDrawType == AbstractLrcView.TRANSLATE_DRAW_TYPE_DYNAMIC) {
383 |
384 | LyricsLineInfo translateLyricsLineInfo = translateLrcLineInfos.get(lyricsLineNum);
385 | float extraLyricsLineHLWidth = LyricsUtils.getLineLyricsHLWidth(lyricsReader.getLyricsType(), extraLrcPaint, translateLyricsLineInfo, extraLyricsWordIndex, translateLyricsWordHLTime);
386 | //画翻译歌词
387 | LyricsUtils.drawDynamiLyrics(canvas, lyricsReader.getLyricsType(), extraLrcPaint, extraLrcPaintHL, extraLrcPaintOutline, translateLyricsLineInfo, extraLyricsLineHLWidth, getWidth(), extraLyricsWordIndex, translateLyricsWordHLTime, extraLrcTextY, paddingLeftOrRight, paintColors, paintHLColors);
388 |
389 | } else {
390 | LyricsLineInfo transliterationLineInfo = transliterationLrcLineInfos.get(lyricsLineNum);
391 | float extraLyricsLineHLWidth = LyricsUtils.getLineLyricsHLWidth(lyricsReader.getLyricsType(), extraLrcPaint, transliterationLineInfo, extraLyricsWordIndex, lyricsWordHLTime);
392 | //画音译歌词
393 | LyricsUtils.drawDynamiLyrics(canvas, lyricsReader.getLyricsType(), extraLrcPaint, extraLrcPaintHL, extraLrcPaintOutline, transliterationLineInfo, extraLyricsLineHLWidth, getWidth(), extraLyricsWordIndex, lyricsWordHLTime, extraLrcTextY, paddingLeftOrRight, paintColors, paintHLColors);
394 |
395 | }
396 |
397 | }
398 |
399 |
400 | /**
401 | * 更新歌词视图
402 | *
403 | * @param playProgress
404 | */
405 | private void updateFloatLrcView(long playProgress) {
406 |
407 | LyricsReader lyricsReader = getLyricsReader();
408 | TreeMap lrcLineInfos = getLrcLineInfos();
409 | int lyricsLineNum = LyricsUtils.getLineNumber(lyricsReader.getLyricsType(), lrcLineInfos, playProgress, lyricsReader.getPlayOffset());
410 | setLyricsLineNum(lyricsLineNum);
411 | if (lyricsReader.getLyricsType() == LyricsInfo.DYNAMIC) {
412 | updateSplitData(playProgress);
413 | } else {
414 | long lyricsWordHLTime = LyricsUtils.getLrcLenTime(lrcLineInfos, lyricsLineNum, playProgress, lyricsReader.getPlayOffset());
415 | setLyricsWordHLTime(lyricsWordHLTime);
416 | }
417 | }
418 |
419 |
420 | /**
421 | * 设置默认颜色
422 | *
423 | * @param paintColor
424 | */
425 | public void setPaintColor(int[] paintColor) {
426 | setPaintColor(paintColor, false);
427 | }
428 |
429 |
430 | /**
431 | * 设置高亮颜色
432 | *
433 | * @param paintHLColor
434 | */
435 | public void setPaintHLColor(int[] paintHLColor) {
436 | setPaintHLColor(paintHLColor, false);
437 | }
438 |
439 |
440 | /**
441 | * 设置字体文件
442 | *
443 | * @param typeFace
444 | */
445 | public void setTypeFace(Typeface typeFace) {
446 | setTypeFace(typeFace, false);
447 | }
448 |
449 | /**
450 | * 设置空行高度
451 | *
452 | * @param spaceLineHeight
453 | */
454 | public void setSpaceLineHeight(float spaceLineHeight) {
455 | setSpaceLineHeight(spaceLineHeight, false);
456 | }
457 |
458 |
459 | /**
460 | * 设置额外空行高度
461 | *
462 | * @param extraLrcSpaceLineHeight
463 | */
464 | public void setExtraLrcSpaceLineHeight(float extraLrcSpaceLineHeight) {
465 | setExtraLrcSpaceLineHeight(extraLrcSpaceLineHeight, false);
466 | }
467 |
468 |
469 | /**
470 | * 设置歌词解析器
471 | *
472 | * @param lyricsReader
473 | */
474 | public void setLyricsReader(LyricsReader lyricsReader) {
475 | super.setLyricsReader(lyricsReader);
476 | if (lyricsReader != null) {
477 | if (lyricsReader.getLyricsType() == LyricsInfo.DYNAMIC) {
478 | int extraLrcType = getExtraLrcType();
479 | //翻译歌词以动感歌词形式显示
480 | if (extraLrcType == AbstractLrcView.EXTRALRCTYPE_BOTH || extraLrcType == AbstractLrcView.EXTRALRCTYPE_TRANSLATELRC) {
481 | setTranslateDrawType(AbstractLrcView.TRANSLATE_DRAW_TYPE_DYNAMIC);
482 | }
483 | }
484 | } else {
485 | setLrcStatus(AbstractLrcView.LRCSTATUS_NONSUPPORT);
486 | }
487 | }
488 |
489 | /**
490 | * 设置字体大小
491 | *
492 | * @param fontSize
493 | * @param extraFontSize 额外歌词字体
494 | */
495 | public void setSize(int fontSize, int extraFontSize) {
496 | setSize(fontSize, extraFontSize, false);
497 | }
498 |
499 | /**
500 | * 设置字体大小
501 | *
502 | * @param fontSize
503 | */
504 | public void setFontSize(float fontSize) {
505 | setFontSize(fontSize, false);
506 | }
507 |
508 |
509 | /**
510 | * 设置额外字体大小
511 | *
512 | * @param extraLrcFontSize
513 | */
514 | public void setExtraLrcFontSize(float extraLrcFontSize) {
515 | setExtraLrcFontSize(extraLrcFontSize, false);
516 | }
517 |
518 | public void setOrientation(int orientation) {
519 | this.mOrientation = orientation;
520 | }
521 |
522 | }
523 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/java/com/zlm/hp/lyrics/widget/make/MakeLrcPreView.java:
--------------------------------------------------------------------------------
1 | package com.zlm.hp.lyrics.widget.make;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 |
10 | import com.zlm.hp.lyrics.model.LyricsLineInfo;
11 | import com.zlm.hp.lyrics.model.make.MakeLrcInfo;
12 | import com.zlm.hp.lyrics.utils.LyricsUtils;
13 |
14 | /**
15 | * 歌词制作预览视图
16 | * Created by zhangliangming on 2018-03-25.
17 | */
18 |
19 | public class MakeLrcPreView extends View {
20 | /**
21 | * 默认歌词画笔
22 | */
23 | private Paint mPaint;
24 | /**
25 | * 默认颜色
26 | */
27 | private int mPaintColor = Color.BLACK;
28 | /**
29 | * 高亮歌词画笔
30 | */
31 | private Paint mPaintHL;
32 | /**
33 | * 高亮画笔颜色
34 | */
35 | private int mPaintHLColor = Color.BLUE;
36 |
37 | /**
38 | * 歌词字体大小
39 | */
40 | private float mFontSize = 35;
41 | /**
42 | * 左右间隔距离
43 | */
44 | private float mPaddingLeftOrRight = 15;
45 | /**
46 | * 制作歌词
47 | */
48 | private MakeLrcInfo mMakeLrcInfo;
49 |
50 | public MakeLrcPreView(Context context) {
51 | super(context);
52 | init(context);
53 | }
54 |
55 | public MakeLrcPreView(Context context, AttributeSet attrs) {
56 | super(context, attrs);
57 | init(context);
58 | }
59 |
60 | /**
61 | * @param context
62 | */
63 | protected void init(Context context) {
64 | //默认画笔
65 | mPaint = new Paint();
66 | mPaint.setDither(true);
67 | mPaint.setAntiAlias(true);
68 | mPaint.setTextSize(mFontSize);
69 | setPaintColor(mPaintColor);
70 |
71 | //高亮画笔
72 | mPaintHL = new Paint();
73 | mPaintHL.setDither(true);
74 | mPaintHL.setAntiAlias(true);
75 | mPaintHL.setTextSize(mFontSize);
76 | setPaintHLColor(mPaintHLColor);
77 |
78 | }
79 |
80 |
81 | @Override
82 | protected void onDraw(Canvas canvas) {
83 | if (mMakeLrcInfo == null) return;
84 | LyricsLineInfo lyricsLineInfo = mMakeLrcInfo.getLyricsLineInfo();
85 | if (lyricsLineInfo == null) return;
86 | int viewHeight = getHeight();
87 | int viewWidth = getWidth();
88 | int textHeight = LyricsUtils.getTextHeight(mPaint);
89 | float textY = (viewHeight + textHeight) / 2;
90 |
91 | int lrcIndex = mMakeLrcInfo.getLrcIndex();
92 | int status = mMakeLrcInfo.getStatus();
93 |
94 | //歌词字集合
95 | String[] lyricsWords = lyricsLineInfo.getLyricsWords();
96 | String lineLyrics = lyricsLineInfo.getLineLyrics();
97 | float textWidth = LyricsUtils.getTextWidth(mPaint, lineLyrics);
98 | float textHLWidth = 0;
99 | //计算高亮宽度
100 | if (lrcIndex == -1) {
101 | //未读
102 | textHLWidth = 0;
103 | } else if (lrcIndex == -2) {
104 | textHLWidth = textWidth;
105 | } else {
106 | if (lrcIndex < lyricsWords.length) {
107 | StringBuilder temp = new StringBuilder();
108 | for (int i = 0; i <= lrcIndex; i++) {
109 | temp.append(lyricsWords[i]);
110 | }
111 | textHLWidth = LyricsUtils.getTextWidth(mPaint, temp.toString());
112 |
113 | } else {
114 | textHLWidth = textWidth;
115 | }
116 | }
117 | //画歌词
118 | float textX = LyricsUtils.getHLMoveTextX(textWidth, textHLWidth, viewWidth, mPaddingLeftOrRight);
119 | LyricsUtils.drawDynamicText(canvas, mPaint, mPaintHL, lineLyrics, textHLWidth, textX, textY);
120 |
121 | }
122 |
123 | public void setPaintColor(int mPaintColor) {
124 | this.mPaintColor = mPaintColor;
125 | mPaint.setColor(mPaintColor);
126 | }
127 |
128 | public void setPaintHLColor(int mPaintHLColor) {
129 | this.mPaintHLColor = mPaintHLColor;
130 | mPaintHL.setColor(mPaintHLColor);
131 | }
132 |
133 | public void setFontSize(float mFontSize) {
134 | this.mFontSize = mFontSize;
135 | mPaint.setTextSize(mFontSize);
136 | mPaintHL.setTextSize(mFontSize);
137 | }
138 |
139 | public void setMakeLrcInfo(MakeLrcInfo mMakeLrcInfo) {
140 | this.mMakeLrcInfo = mMakeLrcInfo;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/hplyricslibrary/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 乐乐歌词库
3 | 乐乐音乐 就是任性
4 | 正在获取歌词...
5 | 搜索歌词
6 | 加载歌词出错
7 | 不支持该格式歌词文件显示
8 |
9 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # 简介 #
2 | 该开源依赖库是乐乐音乐播放器里的一个歌词模块功能,现在把该功能模块独立出来进行优化,并弄成了一个开源依赖库,其它音乐播放器项目只要引用该库并调用接口,便可轻松实现与乐乐音乐播放器一样的动感歌词显示效果,注:其默认歌词格式的编码都是utf-8,使用过程中请注意编码一致的问题,其项目地址如下:[乐乐音乐播放器](https://github.com/zhangliangming/HappyPlayer5.git)。
3 |
4 |
5 | # 使用注意 #
6 |
7 | - 1.x版本,只要是使用自定义view来实现,每次都使用handler去刷新view,但是如果handler队列中有很多任务执行,那就无法保证歌词每次都在100ms内刷新一次。
8 | - 2.x版本,主要是使用surfaceview来实现,每次刷新时间为40ms,歌词渐变相对会流畅。
9 | - 3.x版本,主要是使用TextureView来实现,每次刷新时间修改为50ms,TextureView支持view的相关动画属性
10 |
11 | # 2.x版本使用注意 #
12 | - 主题:我主要是使用Theme.AppCompat.Light.NoActionBar的主题,我试过其它的主题,会导致surfaceview背景为黑色,并且不能透明的问题。
13 | - surfaceview存在的问题,没有view相关的旋转,位移等动画和touch事件,所以我乐乐音乐的旋转界面会出现问题,如果有相关动画需求的,慎用。
14 |
15 | # 3.x版本使用注意 #
16 | - 设置硬件加速:android:hardwareAccelerated="true"
17 | - android4.0以上
18 | - 存在的问题,没有touch事件
19 |
20 | # 网易云API歌词调用方式 #
21 |
22 | 
23 | 注:该歌词只适用于通过api获取歌词,文件保存格式为:lrcwy。其中动感歌词和lrc歌词只能选其中一种,支持翻译歌词,
24 |
25 | # 日志 #
26 |
27 | ## 2020-04-05 ##
28 | - 添加setRefreshTime接口来设置动感歌词行歌词中字刷新时间
29 | - 添加setDuration接口来设置多行歌词y轴的移动时间
30 |
31 | ## 2020-02-26 ##
32 | - 添加trc歌词支持
33 |
34 | ## 2019-01-18 ##
35 | - 添加读取歌词api接口
36 |
37 | ## 2018-12-30 ##
38 | - 修复制作歌词问题,添加多行歌词指示器回调接口
39 |
40 | ## 2018-12-29 ##
41 | - 添加制作歌词功能
42 | - 添加网易云API歌词支持
43 | - 修复网易云API歌词支持、翻译歌词支持高亮显示、修复歌词上滑动时有时不绘画的问题
44 |
45 | ## v3.2 ##
46 | - 2018-05-05
47 | - 添加混淆
48 | - 添加刷新时间
49 |
50 | ## v3.0 ##
51 | - 2018-04-22
52 | - surfaceview替换成TextureView
53 |
54 | ## v2.6 ##
55 | - 2018-04-22
56 | - 修复后台回到前台时,歌词视图内容为空的问题
57 | - 修复初始歌词数据时,OffsetY值没还原的问题
58 |
59 | ## v2.4 ##
60 | - 2018-04-21
61 | - 自定义view替换成surfaceview
62 | - 添加获取歌词参数方法
63 |
64 | ## v1.46 ##
65 | - 2018-10-02
66 | - 获取歌词最大的宽度默认为获取屏幕的大小的2/3。
67 | - 考虑到在设置歌词数据时,视图并没有显示,导致歌词的最大宽度获取为0,所以分隔歌词时出现了问题,最终出现竖直歌词的问题。
68 |
69 | ## v1.44 ##
70 | - 2018-08-11
71 | - 添加HandlerThread
72 | - 修复歌词类型切换
73 |
74 | ## v1.40 ##
75 | - 2018-06-02
76 | - minSdkVersion 修改为19
77 |
78 | ## v1.36 ##
79 | - 2018-05-12
80 | - 双行歌词的默认歌词添加居左显示和居中显示模式
81 | - 双行歌词不回手动设置字体大小标记
82 |
83 | ## v1.34 ##
84 | - 2018-05-07
85 | - 修复歌词快进点击按钮事件
86 | - 2018-05-06
87 | - 修复自定义view歌词
88 |
89 | ## v1.x ##
90 |
91 | - 修复制作歌词无法完成的问题
92 | - 修改音译歌词显示
93 | - 添加制作音译歌词实体
94 | - 修改制作翻译歌词实体
95 | - 添加制作翻译歌词实体
96 | - 添加修改绘画指示器颜色接口
97 | - 修复制作歌词问题
98 | - LyricsReader添加设置歌词数据
99 | - 添加制作歌词实体
100 | - 添加获取制作歌词状态接口
101 | - 添加获取制作后的歌词接口
102 | - 添加制作歌词预览视图
103 | - 添加额外歌词生成图片视图预览和生成额外歌词图片功能
104 | - 修复歌词生成图片问题
105 | - 修复歌词生成图片问题
106 | - 修复歌词生成图片视图的字体
107 | - 修改部分int变量的类型为long
108 | - 修改部分int变量的类型为float
109 | - 添加歌词生成图片文件接口
110 | - 添加歌词生成图片预览视图
111 | - 修复通过歌曲文件名获取歌词文件问题
112 | - 修复多行歌词未读时渐变的问题
113 | - 修复最后一个字渐变出错的问题
114 | - 修改歌词每次刷新的间隔最少为100ms
115 | - 修改歌词每次刷新的间隔最少为20ms
116 | - 修复未读到下一行歌词时,上一行歌词渐变宽度为0的问题
117 | - 修复设置歌词读取器的问题
118 | - 2018-03-04
119 | - 修复双行歌词加载歌词完成后,显示额外歌词渐变出错的问题
120 | - 修改了多行歌词,滑动时的指示器渐变颜色
121 | ## v1.2 ##
122 |
123 | - 添加歌词view获取歌词读取器方法
124 | ## v1.1 ##
125 |
126 | - 添加歌词读取器获取歌词实体类方法
127 | ## v1.0 ##
128 |
129 | - 实现lrc、ksc、krc和hrc歌词格式的显示
130 | - 实现双多行歌词的显示、字体大小、颜色、歌词换行
131 | - 多行歌词的快进、平滑移动、颜色渐变
132 |
133 | # 预览图 #
134 |
135 | ## 制作歌词界面 ##
136 | 
137 |
138 | ## 主界面 ##
139 |
140 | 
141 |
142 | ## 歌词文件读取并预览 ##
143 |
144 | 
145 |
146 | ## 双行歌词-动感歌词 ##
147 |
148 | 
149 |
150 | ## 双行歌词-音译歌词 ##
151 |
152 | 
153 |
154 | ## 双行歌词-翻译歌词 ##
155 |
156 | 
157 |
158 | ## 多行歌词-lrc歌词 ##
159 |
160 | 
161 |
162 | ## 多行歌词-动感歌词 ##
163 |
164 | 
165 |
166 | ## 多行歌词-音译歌词 ##
167 |
168 | 
169 |
170 | ## 多行歌词-翻译歌词 ##
171 |
172 | 
173 |
174 | ## 多行歌词-快进 ##
175 |
176 | 
177 |
178 |
179 | # Gradle #
180 | 1.root build.gradle
181 |
182 | `allprojects {
183 | repositories {
184 | ...
185 | maven { url 'https://jitpack.io' }
186 | }
187 | }`
188 |
189 | 2.app build.gradle
190 |
191 | `dependencies {
192 | compile 'com.github.zhangliangming:HPLyrics:v1.66'
193 | }`
194 |
195 |
196 | # 混淆注意 #
197 | -keep class com.zlm.hp.lyrics.** { *; }
198 |
199 | # 调用Demo #
200 |
201 | 链接: https://pan.baidu.com/s/1j-4wbtiNIfRhypb4uEnX6g 提取码: t8dj
202 |
203 | # 调用用法 #
204 |
205 | 
206 |
207 | 
208 |
209 | # 部分API #
210 | - setPaintColor:设置默认画笔颜色
211 | - setPaintHLColor:设置高亮画笔颜色
212 | - setExtraLyricsListener:设置额外歌词回调方法,多用于加载歌词完成后,根据额外歌词的状态来判断是否需要显示翻译、音译歌词按钮
213 | - setSearchLyricsListener:无歌词时,搜索歌词接口
214 | - setOnLrcClickListener:多行歌词中歌词快进时,点击播放按钮时,调用。
215 | - setFontSize:设置默认画笔的字体大小,可根据参数来设置是否要刷新view
216 | - setExtraLrcStatus:设置额外歌词状态
217 | - setLyricsReader:设置歌词读取器
218 | - play:设置歌词当前的播放进度(播放歌曲时调用一次即可)
219 | - pause:暂停歌词
220 | - seekto:快进歌词
221 | - resume:唤醒
222 | - initLrcData:初始化歌词内容
223 | - setTranslateDrawLrcColorType:设置翻译歌词绘画颜色类型
224 | - setTranslateDrawType:设置翻译歌词绘画类型
225 |
226 | # 声明 #
227 | 由于该项目涉及到酷狗的动感歌词的版权问题,所以该项目的代码和内容仅用于学习用途
228 |
229 | # 捐赠 #
230 | 如果该项目对您有所帮助,欢迎您的赞赏
231 |
232 | - 微信
233 |
234 | 
235 |
236 | - 支付宝
237 |
238 | 
239 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':hplyricslibrary'
2 |
--------------------------------------------------------------------------------