From 056a9949d4be801f88997ceed58048dfd2a90180 Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 11 Nov 2024 10:11:57 +0100 Subject: [PATCH] Correctly handle lyrics that contain ] chars --- src/libs/metadata/impl/Lyrics.cpp | 15 ++++++--------- src/libs/metadata/test/Lyrics.cpp | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/libs/metadata/impl/Lyrics.cpp b/src/libs/metadata/impl/Lyrics.cpp index ee283d0e..f2dc67e6 100644 --- a/src/libs/metadata/impl/Lyrics.cpp +++ b/src/libs/metadata/impl/Lyrics.cpp @@ -83,13 +83,14 @@ namespace lms::metadata return true; } - // Parse timestamps from a line and return the associated times in milliseconds - void extractTimestamps(std::string_view line, std::vector& timestamps) + // Parse timestamps from a line, update the associated times in milliseconds and return the remaining line + std::string_view extractTimestamps(std::string_view line, std::vector& timestamps) { timestamps.clear(); static const std::regex timeTagRegex{ R"(\[(?:(\d{1,2}):)?(\d{1,2}):(\d{1,2})(?:\.(\d{1,3}))?\])" }; std::cregex_iterator regexIt(line.begin(), line.end(), timeTagRegex); std::cregex_iterator regexEnd; + std::string_view::size_type offset{}; while (regexIt != regexEnd) { @@ -110,15 +111,12 @@ namespace lms::metadata currentTimestamp += std::chrono::milliseconds{ fractional }; } + offset = match[0].second - line.data(); timestamps.push_back(currentTimestamp); ++regexIt; } - } - // Extract the lyric text from a line, removing any timestamps - std::string_view extractLyricText(std::string_view line) - { - return line.substr(line.find_last_of(']') + 1); + return line.substr(offset); } } // namespace @@ -178,7 +176,7 @@ namespace lms::metadata if (parseTag(trimmedLine, lyrics)) continue; - extractTimestamps(trimmedLine, timestamps); + const std::string_view lyricText{ extractTimestamps(trimmedLine, timestamps) }; // If there are timestamps, add as synchronized lyrics if (!timestamps.empty()) @@ -189,7 +187,6 @@ namespace lms::metadata currentState = State::SynchronizedLyrics; applyAccumulatedLyrics(); - std::string_view lyricText{ extractLyricText(trimmedLine) }; for (std::chrono::milliseconds timestamp : timestamps) lyrics.synchronizedLines.emplace(timestamp, lyricText); diff --git a/src/libs/metadata/test/Lyrics.cpp b/src/libs/metadata/test/Lyrics.cpp index 795391eb..7756fbd6 100644 --- a/src/libs/metadata/test/Lyrics.cpp +++ b/src/libs/metadata/test/Lyrics.cpp @@ -191,6 +191,22 @@ Some unsynchronized lyrics EXPECT_EQ(lyrics.synchronizedLines.find(3s + 300ms)->second, "Ooh, ooh"); } + TEST(Lyrics, synchronized_withTimestampsDelimiters) + { + std::istringstream is{ R"([00:03.30]Ooh, ooh ] [])" }; + + const Lyrics lyrics{ parseLyrics(is) }; + + EXPECT_TRUE(lyrics.displayArtist.empty()); + EXPECT_TRUE(lyrics.displayAlbum.empty()); + EXPECT_TRUE(lyrics.displayTitle.empty()); + EXPECT_EQ(lyrics.offset, std::chrono::milliseconds{ 0 }); + EXPECT_EQ(lyrics.unsynchronizedLines.size(), 0); + ASSERT_EQ(lyrics.synchronizedLines.size(), 1); + ASSERT_TRUE(lyrics.synchronizedLines.contains(3s + 300ms)); + EXPECT_EQ(lyrics.synchronizedLines.find(3s + 300ms)->second, "Ooh, ooh ] []"); + } + TEST(Lyrics, synchronized_timestampFormats) { std::istringstream is{ R"([00:03.30]First line