fix: preserve input order for equal-timestamp lyrics in normalize and to_plain
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lrx-cli"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
description = "Fetch line-synced lyrics for your music player."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
|
||||
+12
-2
@@ -378,7 +378,12 @@ class LRCData:
|
||||
shifted = max(0, time_ms + offset_ms)
|
||||
lyric_entries.append((shifted, lyric_text))
|
||||
|
||||
lyric_entries.sort(key=lambda item: item[0])
|
||||
# Sort by timestamp; original index as tiebreaker so equal-time entries
|
||||
# retain the order they appeared in the input.
|
||||
lyric_entries = [
|
||||
e
|
||||
for _, e in sorted(enumerate(lyric_entries), key=lambda x: (x[1][0], x[0]))
|
||||
]
|
||||
|
||||
out_lyrics: list[LyricLine] = [
|
||||
LyricLine(line_times_ms=[time_ms], words=[LrcWordSegment(text=text)])
|
||||
@@ -413,7 +418,12 @@ class LRCData:
|
||||
for line in self._lines:
|
||||
tagged_lines.extend(line.timed_plain_entries())
|
||||
|
||||
sorted_lines = [lyric for _, lyric in sorted(tagged_lines, key=lambda x: x[0])]
|
||||
sorted_lines = [
|
||||
lyric
|
||||
for _, (_, lyric) in sorted(
|
||||
enumerate(tagged_lines), key=lambda x: (x[1][0], x[0])
|
||||
)
|
||||
]
|
||||
|
||||
if deduplicate:
|
||||
# Remove consecutive duplicates
|
||||
|
||||
@@ -185,6 +185,23 @@ def test_normalize_expands_multi_time_tags_and_sorts_lyrics() -> None:
|
||||
assert normalized == "\n".join(["[00:01.00]x", "[00:02.00]x", "[00:03.00]c"])
|
||||
|
||||
|
||||
def test_normalize_preserves_input_order_for_equal_timestamps() -> None:
|
||||
text = "\n".join(
|
||||
[
|
||||
"[00:00.00]first",
|
||||
"[00:00.00]second",
|
||||
"[00:00.00]third",
|
||||
"[00:01.00]later",
|
||||
]
|
||||
)
|
||||
|
||||
normalized = LRCData(text).to_normalized_text()
|
||||
|
||||
assert normalized == "\n".join(
|
||||
["[00:00.00]first", "[00:00.00]second", "[00:00.00]third", "[00:01.00]later"]
|
||||
)
|
||||
|
||||
|
||||
def test_normalize_converts_unsynced_lines_and_removes_word_sync_tags() -> None:
|
||||
text = "\n".join(
|
||||
[
|
||||
@@ -257,6 +274,21 @@ def test_to_plain_sorts_lines_by_timestamp_across_lines() -> None:
|
||||
assert plain == "\n".join(["early", "middle", "late"])
|
||||
|
||||
|
||||
def test_to_plain_preserves_input_order_for_equal_timestamps() -> None:
|
||||
text = "\n".join(
|
||||
[
|
||||
"[00:00.00]first",
|
||||
"[00:00.00]second",
|
||||
"[00:00.00]third",
|
||||
"[00:01.00]later",
|
||||
]
|
||||
)
|
||||
|
||||
plain = LRCData(text).to_plain()
|
||||
|
||||
assert plain == "\n".join(["first", "second", "third", "later"])
|
||||
|
||||
|
||||
def test_to_plain_deduplicate_collapses_only_consecutive_equals() -> None:
|
||||
text = "\n".join(
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user