Skip to content

Conversation

@mikooomich
Copy link
Contributor

Some lyrics providers have lyrics that use duplicated timestamps for formatting reasons, causing the blank line to be parsed as the main lyric, and the second (actual line) to be parsed as a translation. After this change, blank lines will not be eligible for translation.

See the following for an example without translations:

[00:23.73]I see the world through eyes covered in ink and bleach [00:29.70]Cross out the ones who heard my cries and watched me weep [00:35.64]
[00:35.64]I love everything
[00:38.51]Fire's spreading all around my room
[00:43.13]My world's so bright
[00:44.42]It's hard to breathe but that's alright
[00:47.32]Hush
[00:59.22]
[00:59.22]Shh
[01:11.46]
[01:11.46]Tape my eyes open to force reality (oh no, no) [01:17.99]Why can't you just let me eat my weight in glee?
Before After
Screenshot_20250816_143258 Screenshot_20250816_143348

Lmk if you want me to write tests for this

?: Long.MAX_VALUE.toULong()
lyric.isTranslated = lyric.start == previousTimestamp
previousTimestamp = lyric.start
lyric.isTranslated = lyric.start == previousLyric?.start && previousLyric.text.isNotBlank()
Copy link
Member

@nift4 nift4 Aug 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's a good start, but that fix is too simple. This breaks a few other parts of the app coded under the assumption translation means duplicate timestamp and lyric lines otherwise being unique:

  1. The code in new lyric view to determine current y offset of active lyric line:
  2. code used by meizu lyric and widget for getting active lyric line (at least possibly broken):
    fun getCurrentLyricIndex(withTranslation: Boolean) =

and please also do add a minimalistic test to avoid regressions of this behaviour

and this breaks "copy-paste translations", where two identical lyc files but changed text are copy-pasted, consider:

[00:44.42]Es ist hart zu atmen aber egal
[00:47.32]Hhhhh 
[00:56.44] 
[00:59.22]Sei leise 
[01:09.32] 
[01:11.46]Klebeband meine Augen öffnen zum erzwingen realität (oh nein, nööö)
[01:17.99]Warum kann ich nicht mein Gewicht essen in Gelee?

[00:44.42]It's hard to breathe but that's alright 
[00:47.32]Hush 
[00:56.44] 
[00:59.22]Shh 
[01:09.32] 
[01:11.46]Tape my eyes open to force reality (oh no, no)
[01:17.99]Why can't you just let me eat my weight in glee?

the empty lines would be marked as translation before, but not anymore. should be fixed otherwise they are too big.

@nift4
Copy link
Member

nift4 commented Aug 26, 2025

just fyi "The code in new lyric view to determine current y offset of active lyric line" is still pending

@nift4
Copy link
Member

nift4 commented Aug 31, 2025

@copilot review this pr

@nift4 nift4 requested a review from Copilot August 31, 2025 20:42
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Fixes lyrics parsing issue where blank lyric lines were incorrectly being paired with actual lyrics as translations due to duplicate timestamps.

  • Updates translation detection logic to prevent blank lines from being eligible for translation with non-blank lines
  • Adds comprehensive test coverage for the empty lyric scenario
  • Updates existing test data to reflect the corrected parsing behavior

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
SemanticLyrics.kt Modified translation detection logic to handle blank lines correctly
LrcUtilsTest.kt Added new test case to verify empty lyrics are not treated as translations
LrcTestData.kt Updated test data to reflect corrected parsing of blank lyric lines

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

lyric.isTranslated = lyric.start == previousTimestamp
previousTimestamp = lyric.start
lyric.isTranslated = lyric.start == previousLyric?.start
&& (previousLyric.text.isNotBlank() || previousLyric.text.isBlank() && lyric.text.isBlank())
Copy link

Copilot AI Aug 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition (previousLyric.text.isNotBlank() || previousLyric.text.isBlank() && lyric.text.isBlank()) is overly complex and confusing. This can be simplified to previousLyric.text.isNotBlank() || lyric.text.isBlank() which has the same logical meaning but is much clearer.

Suggested change
&& (previousLyric.text.isNotBlank() || previousLyric.text.isBlank() && lyric.text.isBlank())
&& (previousLyric.text.isNotBlank() || lyric.text.isBlank())

Copilot uses AI. Check for mistakes.
@nift4
Copy link
Member

nift4 commented Oct 5, 2025

  1. why are you removing blank translations generally? also testTemplateLrcTranslationType1 fails
  2. meizu status bar lyric can only display one lyric line at a time and right now it will make it display blank one while lyric with actual content is hidden because it takes first lyric at timestamp, maybe filter blank lines out in that method?
    fun getCurrentLyricIndex(withTranslation: Boolean) =
    syncedLyrics?.text?.mapIndexed { i, it -> i to it }?.filter {
    it.second.start <= (controller?.currentPosition ?: 0).toULong()
    && (!it.second.isTranslated || withTranslation)
    }?.maxByOrNull { it.second.start }?.first

@mikooomich
Copy link
Contributor Author

  1. I removed it because extra spacing looks a bit odd. I can revert it nonetheless
  2. I'll look into it

Some lyrics providers have lyrics that use duplicated timestamps for formatting reasons, causing the blank line to be parsed as the main lyric, and the second (actual line) to be parsed as a translation. After this change, blank lines will not be eligible for translation.

See the following for an example:

[00:23.73]I see the world through eyes covered in ink and bleach
[00:29.70]Cross out the ones who heard my cries and watched me weep
[00:35.64]
[00:35.64]I love everything
[00:38.51]Fire's spreading all around my room
[00:43.13]My world's so bright
[00:44.42]It's hard to breathe but that's alright
[00:47.32]Hush
[00:59.22]
[00:59.22]Shh
[01:11.46]
[01:11.46]Tape my eyes open to force reality (oh no, no)
[01:17.99]Why can't you just let me eat my weight in glee?
getCurrentLyricIndex() is updated to return the first non-blank item
with the highest timestamp. Single blank lines are assumed to be
intentional. Multiple blank lines without a non-blank line will
follow the previous behaviour
@mikooomich mikooomich force-pushed the fix-blank-lyrics-tranlation branch from 9b79448 to ad668e7 Compare November 6, 2025 01:00
@mikooomich mikooomich closed this Nov 6, 2025
@mikooomich mikooomich deleted the fix-blank-lyrics-tranlation branch November 6, 2025 01:01
@mikooomich mikooomich restored the fix-blank-lyrics-tranlation branch November 6, 2025 01:01
@mikooomich mikooomich reopened this Nov 6, 2025
@mikooomich
Copy link
Contributor Author

I can't verify Meizu status bar lyrics, but did verify the indexes that were sent to the widget. They seemed to match up with what should be displayed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants