diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java index 93daf296..e1c95bd4 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/AbsSynchronizedLyrics.java @@ -3,9 +3,17 @@ package com.kabouzeid.gramophone.model.lyrics; import android.util.SparseArray; public abstract class AbsSynchronizedLyrics { + private static final int TIME_OFFSET_MS = 500; // time adjustment to display line before it actually starts + public final SparseArray lines = new SparseArray<>(); public boolean isValid = false; + public int offset = 0; + /** + * @param data Lyrics string + * @param justCheck Set isValid = true and stop parsing if lyrics appears to be valid + * and has at least 1 line + */ public static AbsSynchronizedLyrics parse(String data, boolean justCheck) { return new SynchronizedLyricsLRC(data, justCheck); // no another formats at the moment } @@ -20,7 +28,7 @@ public abstract class AbsSynchronizedLyrics { } public String getLine(int time) { - time += 500; // small time adjustment to display line before it actually starts + time += offset + AbsSynchronizedLyrics.TIME_OFFSET_MS; int lastLineTime = lines.keyAt(0); diff --git a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java index 92a979aa..8536cb53 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java +++ b/app/src/main/java/com/kabouzeid/gramophone/model/lyrics/SynchronizedLyricsLRC.java @@ -4,9 +4,18 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { - private static Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); - private static Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d+):(\\d{2}(?:\\.\\d+)?)\\]"); + private static final Pattern LRC_LINE_PATTERN = Pattern.compile("((?:\\[.*?\\])+)(.*)"); + private static final Pattern LRC_TIME_PATTERN = Pattern.compile("\\[(\\d+):(\\d{2}(?:\\.\\d+)?)\\]"); + private static final Pattern LRC_ATTRIBUTE_PATTERN = Pattern.compile("\\[(\\D+):(.+)\\]"); + private static final float LRC_SECONDS_TO_MS_MULTIPLIER = 1000f; + private static final int LRC_MINUTES_TO_MS_MULTIPLIER = 60000; + + /** + * @param data Lyrics string + * @param justCheck Set isValid = true and stop parsing if lyrics appears to be valid + * and has at least 1 line + */ public SynchronizedLyricsLRC(String data, boolean justCheck) { if (data == null || data.isEmpty()) { return; @@ -20,27 +29,42 @@ public class SynchronizedLyricsLRC extends AbsSynchronizedLyrics { continue; } - Matcher matcher = SynchronizedLyricsLRC.LRC_LINE_PATTERN.matcher(line); - if (matcher.find()) { - String time = matcher.group(1); - String text = matcher.group(2); - - Matcher timeMatcher = SynchronizedLyricsLRC.LRC_TIME_PATTERN.matcher(time); - while (timeMatcher.find()) { - int m = 0; - float s = 0f; - try { - m = Integer.parseInt(timeMatcher.group(1)); - s = Float.parseFloat(timeMatcher.group(2)); - } catch (NumberFormatException ex) { - ex.printStackTrace(); + Matcher attrMatcher = SynchronizedLyricsLRC.LRC_ATTRIBUTE_PATTERN.matcher(line); + if (attrMatcher.find()) { + try { + String attr = attrMatcher.group(1).toLowerCase().trim(); + String value = attrMatcher.group(2).toLowerCase().trim(); + switch (attr) { + case "offset": + this.offset = Integer.parseInt(value); + break; } - int ms = (int) (s * 1000f) + m * 60000; + } catch (Exception ex) { + ex.printStackTrace(); + } + } else { + Matcher matcher = SynchronizedLyricsLRC.LRC_LINE_PATTERN.matcher(line); + if (matcher.find()) { + String time = matcher.group(1); + String text = matcher.group(2); - this.isValid = true; - if (justCheck) return; + Matcher timeMatcher = SynchronizedLyricsLRC.LRC_TIME_PATTERN.matcher(time); + while (timeMatcher.find()) { + int m = 0; + float s = 0f; + try { + m = Integer.parseInt(timeMatcher.group(1)); + s = Float.parseFloat(timeMatcher.group(2)); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + } + int ms = (int) (s * LRC_SECONDS_TO_MS_MULTIPLIER) + m * LRC_MINUTES_TO_MS_MULTIPLIER; - this.lines.append(ms, text); + this.isValid = true; + if (justCheck) return; + + this.lines.append(ms, text); + } } } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java index 8e5c957d..816114d9 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/PlayerAlbumCoverFragment.java @@ -41,7 +41,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @BindView(R.id.player_favorite_icon) ImageView favoriteIcon; - @BindView(R.id.player_lyrics) + @BindView(R.id.player_lyrics) FrameLayout lyrics; @BindView(R.id.player_lyrics_line1) TextView lyricsLine1; @@ -91,8 +91,8 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements public void onDestroyView() { super.onDestroyView(); viewPager.removeOnPageChangeListener(this); - unbinder.unbind(); progressViewUpdateHelper.stop(); + unbinder.unbind(); } @Override @@ -181,10 +181,8 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements .start(); } - public void setSynchronizedLyrics(AbsSynchronizedLyrics sLyrics) - { - if(sLyrics == null || sLyrics.lines.size() == 0) - { + public void setSynchronizedLyrics(AbsSynchronizedLyrics sLyrics) { + if (sLyrics == null || sLyrics.lines.size() == 0) { synchronizedLyrics = null; lyrics.setVisibility(View.GONE); lyricsLine1.setText(null); @@ -207,7 +205,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements @Override public void onUpdateProgressViews(int progress, int total) { - if(synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0 || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { + if (synchronizedLyrics == null || synchronizedLyrics.lines.size() == 0 || !PreferenceUtil.getInstance(getActivity()).synchronizedLyricsShow()) { lyrics.setVisibility(View.GONE); lyricsLine1.setText(null); lyricsLine2.setText(null); @@ -219,8 +217,7 @@ public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements String oldLine = lyricsLine2.getText().toString(); String line = synchronizedLyrics.getLine(progress); - if(!oldLine.equals(line) || oldLine.isEmpty()) - { + if (!oldLine.equals(line) || oldLine.isEmpty()) { lyricsLine1.setText(oldLine); lyricsLine2.setText(line);