From dc46f7a49b5bd0fdd2b3b181ece88a3fb8482dc5 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 7 Feb 2024 14:28:26 +0100 Subject: [PATCH 01/29] Fix compilation with taglib 2.0 --- src/tags.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tags.cpp b/src/tags.cpp index 6cd6a8c2..6395807a 100644 --- a/src/tags.cpp +++ b/src/tags.cpp @@ -123,12 +123,12 @@ void writeCommonTags(const MPD::MutableSong &s, TagLib::Tag *tag) tag->setArtist(ToWString(s.getArtist())); tag->setAlbum(ToWString(s.getAlbum())); try { - tag->setYear(boost::lexical_cast(s.getDate())); + tag->setYear(boost::lexical_cast(s.getDate())); } catch (boost::bad_lexical_cast &) { std::cerr << "writeCommonTags: couldn't write 'year' tag to '" << s.getURI() << "' as it's not a positive integer\n"; } try { - tag->setTrack(boost::lexical_cast(s.getTrack())); + tag->setTrack(boost::lexical_cast(s.getTrack())); } catch (boost::bad_lexical_cast &) { std::cerr << "writeCommonTags: couldn't write 'track' tag to '" << s.getURI() << "' as it's not a positive integer\n"; } @@ -261,7 +261,7 @@ void read(mpd_song *s) if (f.isNull()) return; - setAttribute(s, "Time", boost::lexical_cast(f.audioProperties()->length())); + setAttribute(s, "Time", boost::lexical_cast(f.audioProperties()->lengthInSeconds())); if (auto mpeg_file = dynamic_cast(f.file())) { @@ -306,7 +306,10 @@ bool write(MPD::MutableSong &s) { writeID3v2Tags(s, mpeg_file->ID3v2Tag(true)); // write id3v2.4 tags only - if (!mpeg_file->save(TagLib::MPEG::File::ID3v2, true, 4, false)) + if (!mpeg_file->save(TagLib::MPEG::File::ID3v2, + TagLib::File::StripOthers, + TagLib::ID3v2::v4, + TagLib::File::DoNotDuplicate)) return false; // do not call generic save() as it will duplicate tags saved = true; From 81e5cf58b44be4ec0dc50722e2ed6d534df3973d Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Thu, 30 May 2024 14:58:09 +0200 Subject: [PATCH 02/29] extras: fix compilation with taglib 2.0 --- extras/artist_to_albumartist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/artist_to_albumartist.cpp b/extras/artist_to_albumartist.cpp index c3ddfee3..0349d0ae 100644 --- a/extras/artist_to_albumartist.cpp +++ b/extras/artist_to_albumartist.cpp @@ -34,7 +34,7 @@ enum class CopyResult { Success, NoArtist, AlbumArtistAlreadyInPlace }; bool is_framelist_empty(const TagLib::ID3v2::FrameList &list) { for (auto it = list.begin(); it != list.end(); ++it) - if ((*it)->toString() != TagLib::String::null) + if (!(*it)->toString().isEmpty()) return false; return true; } From 9c396d7ef09a86091f76ca4ef9ae0fe8b84f2a8a Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 24 Jul 2024 17:25:03 +0200 Subject: [PATCH 03/29] Fix removal of XiphComments --- src/tags.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tags.cpp b/src/tags.cpp index 6395807a..96704642 100644 --- a/src/tags.cpp +++ b/src/tags.cpp @@ -174,6 +174,7 @@ void writeID3v2Tags(const MPD::MutableSong &s, TagLib::ID3v2::Tag *tag) void writeXiphComments(const MPD::MutableSong &s, TagLib::Ogg::XiphComment *tag) { auto writeXiph = [&](const TagLib::String &type, const TagLib::StringList &list) { + tag->removeFields(type); for (auto it = list.begin(); it != list.end(); ++it) tag->addField(type, *it, it == list.begin()); }; From 51ebe9e52db78341d6ed77424c17da41bacedde8 Mon Sep 17 00:00:00 2001 From: Drew Marino <77032812+OneTrueC@users.noreply.github.com> Date: Wed, 24 Jul 2024 11:54:12 -0400 Subject: [PATCH 04/29] Fixed bug related to readline.h (#592) Terminals that don't restore the terminal state when a program exits display stdin incorrectly after quitting. This is not a bug in readline.h as its examples use termios in the same way. --- src/curses/window.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/curses/window.cpp b/src/curses/window.cpp index 59c45456..b0cc9633 100644 --- a/src/curses/window.cpp +++ b/src/curses/window.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "utility/readline.h" @@ -216,6 +217,8 @@ Color Color::Cyan(COLOR_CYAN, Color::current); Color Color::White(COLOR_WHITE, Color::current); Color Color::End(0, 0, false, true); +struct termios orig_termios; + int Color::pairNumber() const { // If colors are disabled, return default pair value. @@ -400,6 +403,7 @@ int colorCount() void initScreen(bool enable_colors, bool enable_mouse) { + tcgetattr(STDIN_FILENO, &orig_termios); initscr(); if (has_colors() && enable_colors) { @@ -481,6 +485,7 @@ void destroyScreen() Mouse::disable(); curs_set(1); endwin(); + tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); } Window::Window(size_t startx, size_t starty, size_t width, size_t height, From afb150138d5bf5d6f464c31b2c61ebdc037b93bb Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 24 Jul 2024 17:55:35 +0200 Subject: [PATCH 05/29] Change visibility of orig_termios --- src/curses/window.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/curses/window.cpp b/src/curses/window.cpp index b0cc9633..5db41fb9 100644 --- a/src/curses/window.cpp +++ b/src/curses/window.cpp @@ -199,6 +199,8 @@ int add_base() int color_pair_counter; std::vector color_pair_map; +termios orig_termios; + } namespace NC { @@ -217,8 +219,6 @@ Color Color::Cyan(COLOR_CYAN, Color::current); Color Color::White(COLOR_WHITE, Color::current); Color Color::End(0, 0, false, true); -struct termios orig_termios; - int Color::pairNumber() const { // If colors are disabled, return default pair value. From e87c104dd6d742d87c19fd88fedf75e04084b595 Mon Sep 17 00:00:00 2001 From: Denys Tynok Date: Wed, 24 Jul 2024 18:56:14 +0300 Subject: [PATCH 06/29] fix: update obsolete macros in autoconf (#582) * fix: update obsolete macros in autoconf * fix: update obsolete macro 'AC_PROG_LIBTOOL' in autoconf --- configure.ac | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index ef0c52b7..7ff1382b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,15 +1,15 @@ -AC_INIT([ncmpcpp], [0.10_dev]) +AC_INIT([ncmpcpp],[0.10_dev]) AC_CONFIG_SRCDIR([configure.ac]) AC_CONFIG_HEADERS(config.h) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_MACRO_DIR([m4]) -AC_PREREQ(2.59) +AC_PREREQ([2.71]) -AC_LANG_CPLUSPLUS +AC_LANG([C++]) AC_PROG_CXX -AC_PROG_LIBTOOL +LT_INIT AC_ARG_ENABLE(outputs, AS_HELP_STRING([--enable-outputs], [Enable outputs screen @<:@default=no@:>@]), [outputs=$enableval], [outputs=no]) AC_ARG_ENABLE(visualizer, AS_HELP_STRING([--enable-visualizer], [Enable music visualizer screen @<:@default=no@:>@]), [visualizer=$enableval], [visualizer=no]) From f76dd085b24ca487930c9c59637b1a5ab60cc035 Mon Sep 17 00:00:00 2001 From: Alex Balgavy <8124851+thezeroalpha@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:57:38 +0200 Subject: [PATCH 07/29] Fix crash when background-fetching lyrics for streams (#561) When `fetch_lyrics_for_current_song_in_background` is set to `yes`, and an HTTP(S) stream is loaded with a long URL, ncmpcpp crashes due to the length of the filename generated to store lyrics. This commit makes the background lyrics fetcher ignore such streams, preventing the crash. Addresses issue #380. --- src/screens/lyrics.cpp | 26 ++++++++++++++++++++++++-- src/song.cpp | 6 ++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/screens/lyrics.cpp b/src/screens/lyrics.cpp index d34ba617..5ca42869 100644 --- a/src/screens/lyrics.cpp +++ b/src/screens/lyrics.cpp @@ -361,6 +361,25 @@ void Lyrics::toggleFetcher() Statusbar::print("Using all lyrics fetchers"); } +/* For HTTP(S) streams, fetchInBackground makes ncmpcpp crash: the lyrics_file + * gets set to the stream URL, which is too long, hence + * boost::filesystem::exists() fails. + * Possible solutions: + * - truncate the URL and use that as a filename. Problem: resulting filename + * might not be unique. + * - generate filenames in a different way for streams. Problem: what is a good + * method for this? Perhaps hashing -- but then the lyrics filenames are not + * informative. + * - skip fetching lyrics for streams with URLs that are too long. Problem: + * this leads to inconsistent behavior since lyrics will be fetched for some + * streams but not others. + * - avoid fetching lyrics for streams altogether. + * + * We choose the last solution, and ignore streams when fetching lyrics. This + * is because fetching lyrics for a stream may not be accurate (streams do not + * always provide the necessary metadata to look up lyrics reliably). + * Furthermore, fetching lyrics for streams is not necessarily desirable. + */ void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_) { auto consumer_impl = [this] { @@ -377,7 +396,10 @@ void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_) break; } lyrics_file = lyricsFilename(consumer->songs.front().song()); - if (!boost::filesystem::exists(lyrics_file)) + + // For long filenames (e.g. http(s) stream URLs), boost::filesystem::exists() fails. + // This if condition is fine, because evaluation order is guaranteed. + if (!consumer->songs.front().song().isStream() && !boost::filesystem::exists(lyrics_file)) { cs = consumer->songs.front(); if (cs.notify()) @@ -389,7 +411,7 @@ void Lyrics::fetchInBackground(const MPD::Song &s, bool notify_) } consumer->songs.pop(); } - if (!cs.song().empty()) + if (!cs.song().empty() && !cs.song().isStream()) { auto lyrics = downloadLyrics(cs.song(), nullptr, nullptr, m_fetcher); if (lyrics) diff --git a/src/song.cpp b/src/song.cpp index 70822d10..c274d43f 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -293,7 +293,9 @@ bool Song::isFromDatabase() const bool Song::isStream() const { assert(m_song); - return !strncmp(mpd_song_get_uri(m_song.get()), "http://", 7); + const char *song_uri = mpd_song_get_uri(m_song.get()); + // Stream schemas: http, https + return !strncmp(song_uri, "http://", 7) || !strncmp(song_uri, "https://", 8); } bool Song::empty() const @@ -308,7 +310,7 @@ std::string Song::ShowTime(unsigned length) int minutes = length/60; length -= minutes*60; int seconds = length; - + std::string result; if (hours > 0) result = (boost::format("%d:%02d:%02d") % hours % minutes % seconds).str(); From 8746ded880e03a382e3712fbb2a3e5d13f7391a0 Mon Sep 17 00:00:00 2001 From: George Abbott Date: Wed, 24 Jul 2024 17:01:07 +0100 Subject: [PATCH 08/29] Added hh:mm:ss to g command (#550) * Added hh:mm:ss to g command * Updated statusbar prompt with h:m:ss as well * corrected spaces to tabs --- src/actions.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index 9bcb15ec..578172bd 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -1746,7 +1746,7 @@ void JumpToPositionInSong::run() std::string spos; { Statusbar::ScopedLock slock; - Statusbar::put() << "Position to go (in %/m:ss/seconds(s)): "; + Statusbar::put() << "Position to go (in %/h:m:ss/m:ss/seconds(s)): "; spos = wFooter->prompt(); } @@ -1771,8 +1771,17 @@ void JumpToPositionInSong::run() int secs = (percent * s.getDuration()) / 100.0; Mpd.Seek(s.getPosition(), secs); } + else if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{1,2}):([0-9]{2})"))) // position in hh:mm:ss + { + auto hours = fromString(what[1]); + auto mins = fromString(what[2]); + auto secs = fromString(what[3]); + boundsCheck(mins, 0u, 60u); + boundsCheck(secs, 0u, 60u); + Mpd.Seek(s.getPosition(), hours * 3600 + mins * 60 + secs); + } else - Statusbar::print("Invalid format ([m]:[ss], [s]s, [%]%, [%] accepted)"); + Statusbar::print("Invalid format ([h]:[m]:[ss], [m]:[ss], [s]s, [%]%, [%] accepted)"); } bool SelectItem::canBeRun() From 95bca25cb6696724774474a35f5c316c127f3423 Mon Sep 17 00:00:00 2001 From: gardockt <42496375+gardockt@users.noreply.github.com> Date: Wed, 24 Jul 2024 16:04:51 +0000 Subject: [PATCH 09/29] Tag editor: only write files with modified tags (#536) --- src/screens/tag_editor.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/screens/tag_editor.cpp b/src/screens/tag_editor.cpp index d754f499..5ad68382 100644 --- a/src/screens/tag_editor.cpp +++ b/src/screens/tag_editor.cpp @@ -798,13 +798,16 @@ void TagEditor::runAction() Statusbar::print("Writing changes..."); for (auto it = EditedSongs.begin(); it != EditedSongs.end(); ++it) { - Statusbar::printf("Writing tags in \"%1%\"...", (*it)->getName()); - if (!Tags::write(**it)) + if ((*it)->isModified()) { - Statusbar::printf("Error while writing tags to \"%1%\": %2%", - (*it)->getName(), strerror(errno)); - success = 0; - break; + Statusbar::printf("Writing tags in \"%1%\"...", (*it)->getName()); + if (!Tags::write(**it)) + { + Statusbar::printf("Error while writing tags to \"%1%\": %2%", + (*it)->getName(), strerror(errno)); + success = 0; + break; + } } } if (success) From b218d901934f0f729b228e5a7475c25c69e434a2 Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Wed, 24 Jul 2024 17:07:34 +0100 Subject: [PATCH 10/29] Check for taglib with pkg-config before trying taglib-config (#558) Programs like taglib-config are not good when cross-compiling. --- configure.ac | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 7ff1382b..b11213aa 100644 --- a/configure.ac +++ b/configure.ac @@ -257,19 +257,30 @@ PKG_CHECK_MODULES([libcurl], [libcurl], [ # taglib if test "$taglib" != "no" ; then - AC_PATH_PROG(TAGLIB_CONFIG, taglib-config) - if test "$TAGLIB_CONFIG" != "" ; then - CPPFLAGS="$CPPFLAGS `$TAGLIB_CONFIG --cflags`" - LIBS="$LIBS `$TAGLIB_CONFIG --libs`" + PKG_CHECK_MODULES([taglib], [taglib], [ + AC_SUBST(taglib_CFLAGS) + AC_SUBST(taglib_LIBS) + ], [ + AC_PATH_PROG([TAGLIB_CONFIG], [taglib-config]) + if test "$TAGLIB_CONFIG" != ""; then + taglib_CFLAGS=`$TAGLIB_CONFIG --cflags` + taglib_LIBS=`$TAGLIB_CONFIG --libs` + else + if test "$taglib" = "yes" ; then + AC_MSG_ERROR([could not find taglib.pc or taglib-config executable]) + fi + fi + ]) + + if test "$TAGLIB_CONFIG$taglib_LIBS" != "" ; then + CPPFLAGS="$CPPFLAGS $taglib_CFLAGS" + LIBS="$LIBS $taglib_LIBS" + AC_CHECK_HEADERS([taglib.h], , if test "$taglib" = "yes" ; then AC_MSG_ERROR([missing taglib.h header]) fi ) - else - if test "$taglib" = "yes" ; then - AC_MSG_ERROR([taglib-config executable is missing]) - fi fi fi From 8ecbb8b49b47a6adf29a7ad79a2fd8d295f27c7b Mon Sep 17 00:00:00 2001 From: djvs <2954343+djvs@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:15:02 -0400 Subject: [PATCH 11/29] Expose filepath in columns view (#530) * Expose filepath in columns view * update --- doc/config | 1 + doc/ncmpcpp.1 | 1 + src/display.cpp | 2 ++ src/utility/type_conversions.cpp | 2 ++ 4 files changed, 6 insertions(+) diff --git a/doc/config b/doc/config index 57daa8ef..747f2055 100644 --- a/doc/config +++ b/doc/config @@ -172,6 +172,7 @@ ## ## %l - length ## %f - filename +## %F - full filepath ## %D - directory ## %a - artist ## %A - album artist diff --git a/doc/ncmpcpp.1 b/doc/ncmpcpp.1 index e1889f80..7ab7cf90 100644 --- a/doc/ncmpcpp.1 +++ b/doc/ncmpcpp.1 @@ -472,6 +472,7 @@ For song format you can use: %l - length %f - filename + %F - full filepath %D - directory %a - artist %A - album artist diff --git a/src/display.cpp b/src/display.cpp index 4a52d8ce..ddf87932 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -47,6 +47,8 @@ const wchar_t *toColumnName(char c) return L"Filename"; case 'D': return L"Directory"; + case 'F': + return L"Filepath"; case 'a': return L"Artist"; case 'A': diff --git a/src/utility/type_conversions.cpp b/src/utility/type_conversions.cpp index d4bfb8cd..b546fa4a 100644 --- a/src/utility/type_conversions.cpp +++ b/src/utility/type_conversions.cpp @@ -168,6 +168,8 @@ MPD::Song::GetFunction charToGetFunction(char c) return &MPD::Song::getDirectory; case 'f': return &MPD::Song::getName; + case 'F': + return &MPD::Song::getURI; case 'a': return &MPD::Song::getArtist; case 'A': From af7550a69f98a1872ad1a8cc93cd6f250d139943 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 24 Jul 2024 18:02:35 +0200 Subject: [PATCH 12/29] Adjust the new regex to require 2 minute digits --- src/actions.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index 578172bd..89405920 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -1752,27 +1752,31 @@ void JumpToPositionInSong::run() boost::regex rx; boost::smatch what; - if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{2})"))) // mm:ss + // mm:ss + if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{2})"))) { auto mins = fromString(what[1]); auto secs = fromString(what[2]); boundsCheck(secs, 0u, 60u); Mpd.Seek(s.getPosition(), mins * 60 + secs); } - else if (boost::regex_match(spos, what, rx.assign("([0-9]+)s"))) // position in seconds + // position in seconds + else if (boost::regex_match(spos, what, rx.assign("([0-9]+)s"))) { auto secs = fromString(what[1]); Mpd.Seek(s.getPosition(), secs); } - else if (boost::regex_match(spos, what, rx.assign("([0-9]+)[%]{0,1}"))) // position in % + // position in% + else if (boost::regex_match(spos, what, rx.assign("([0-9]+)[%]{0,1}"))) { auto percent = fromString(what[1]); boundsCheck(percent, 0u, 100u); int secs = (percent * s.getDuration()) / 100.0; Mpd.Seek(s.getPosition(), secs); } - else if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{1,2}):([0-9]{2})"))) // position in hh:mm:ss - { + // position in hh:mm:ss + else if (boost::regex_match(spos, what, rx.assign("([0-9]+):([0-9]{2}):([0-9]{2})"))) + { auto hours = fromString(what[1]); auto mins = fromString(what[2]); auto secs = fromString(what[3]); @@ -1781,7 +1785,7 @@ void JumpToPositionInSong::run() Mpd.Seek(s.getPosition(), hours * 3600 + mins * 60 + secs); } else - Statusbar::print("Invalid format ([h]:[m]:[ss], [m]:[ss], [s]s, [%]%, [%] accepted)"); + Statusbar::print("Invalid format ([h]:[mm]:[ss], [m]:[ss], [s]s, [%]%, [%] accepted)"); } bool SelectItem::canBeRun() From 6f8d12da8ce6a7c7a7e1494c773f7219bddb9049 Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 24 Jul 2024 19:18:00 +0200 Subject: [PATCH 13/29] If both strings are numbers, compare them as such --- src/screens/media_library.cpp | 18 ++++-------------- src/utility/comparators.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/screens/media_library.cpp b/src/screens/media_library.cpp index df2b5866..1b046117 100644 --- a/src/screens/media_library.cpp +++ b/src/screens/media_library.cpp @@ -98,7 +98,7 @@ bool MoveToAlbum(NC::Menu &albums, const std::string &primary_tag, c struct SortSongs { typedef NC::Menu::Item SongItem; - static const std::array GetFuns; + static const std::array GetFuns; LocaleStringComparison m_cmp; @@ -117,26 +117,16 @@ public: return ret < 0; } - // Sort by track numbers. - try { - ret = boost::lexical_cast(a.getTags(&MPD::Song::getTrackNumber)) - - boost::lexical_cast(b.getTags(&MPD::Song::getTrackNumber)); - } catch (boost::bad_lexical_cast &) { - ret = a.getTrackNumber().compare(b.getTrackNumber()); - } - if (ret != 0) - return ret < 0; - - // If track numbers are equal, sort by the display format. return Format::stringify(Config.song_library_format, &a) < Format::stringify(Config.song_library_format, &b); } }; -const std::array SortSongs::GetFuns = {{ +const std::array SortSongs::GetFuns = {{ &MPD::Song::getDate, &MPD::Song::getAlbum, - &MPD::Song::getDisc + &MPD::Song::getDisc, + &MPD::Song::getTrackNumber, }}; class SortAlbumEntries { diff --git a/src/utility/comparators.cpp b/src/utility/comparators.cpp index a9c0d339..49e3b97d 100644 --- a/src/utility/comparators.cpp +++ b/src/utility/comparators.cpp @@ -34,10 +34,22 @@ bool hasTheWord(const std::string &s) && (s[3] == ' '); } +long long strToLL(const char *s, size_t len) +{ + long long n = 0; + while (len--) + n = 10*n + *s++ - '0'; + return n; +} + } int LocaleStringComparison::compare(const char *a, size_t a_len, const char *b, size_t b_len) const { + // If both strings are numbers, compare them as such. + if (std::all_of(a, a + a_len, isdigit) && std::all_of(b, b + b_len, isdigit)) + return strToLL(a, a_len) - strToLL(b, b_len); + size_t ac_off = 0, bc_off = 0; if (m_ignore_the) { From b2c8ca91c49dd3e198f772bc5d70b322fa6491ec Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 24 Jul 2024 19:38:30 +0200 Subject: [PATCH 14/29] Don't treat empty strings as numbers --- src/utility/comparators.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utility/comparators.cpp b/src/utility/comparators.cpp index 49e3b97d..3959962b 100644 --- a/src/utility/comparators.cpp +++ b/src/utility/comparators.cpp @@ -47,7 +47,8 @@ long long strToLL(const char *s, size_t len) int LocaleStringComparison::compare(const char *a, size_t a_len, const char *b, size_t b_len) const { // If both strings are numbers, compare them as such. - if (std::all_of(a, a + a_len, isdigit) && std::all_of(b, b + b_len, isdigit)) + if ( a_len > 0 && std::all_of(a, a + a_len, isdigit) + && b_len > 0 && std::all_of(b, b + b_len, isdigit)) return strToLL(a, a_len) - strToLL(b, b_len); size_t ac_off = 0, bc_off = 0; From 985bc09b5c61d67cd179b1a6562c5949da2f368d Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Wed, 24 Jul 2024 20:33:32 +0200 Subject: [PATCH 15/29] Update lyrics fetchers Removes azlyrics, musixmatch, sing365/lyrics007 and metrolyrics. --- doc/config | 2 +- src/configuration.cpp | 6 +----- src/lyrics_fetcher.cpp | 24 +++++------------------- src/lyrics_fetcher.h | 40 ++-------------------------------------- src/settings.cpp | 2 +- 5 files changed, 10 insertions(+), 64 deletions(-) diff --git a/doc/config b/doc/config index 747f2055..82a80fcb 100644 --- a/doc/config +++ b/doc/config @@ -409,7 +409,7 @@ # #cyclic_scrolling = no # -#lyrics_fetchers = azlyrics, genius, musixmatch, sing365, metrolyrics, justsomelyrics, jahlyrics, plyrics, tekstowo, zeneszoveg, internet +#lyrics_fetchers = genius, tekstowo, plyrics, justsomelyrics, jahlyrics, zeneszoveg, internet # #follow_now_playing_lyrics = no # diff --git a/src/configuration.cpp b/src/configuration.cpp index c9eb3fef..c1e26913 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -156,14 +156,10 @@ bool configure(int argc, char **argv) if (vm.count("test-lyrics-fetchers")) { std::vector> fetcher_data = { - std::make_tuple("azlyrics", "rihanna", "umbrella"), std::make_tuple("genius", "rihanna", "umbrella"), - std::make_tuple("musixmatch", "rihanna", "umbrella"), - std::make_tuple("sing365", "rihanna", "umbrella"), - std::make_tuple("metrolyrics", "rihanna", "umbrella"), std::make_tuple("justsomelyrics", "rihanna", "umbrella"), std::make_tuple("jahlyrics", "sean kingston", "dry your eyes"), - std::make_tuple("plyrics", "offspring", "genocide"), + std::make_tuple("plyrics", "rihanna", "umbrella"), std::make_tuple("tekstowo", "rihanna", "umbrella"), std::make_tuple("zeneszoveg", "rihanna", "umbrella"), }; diff --git a/src/lyrics_fetcher.cpp b/src/lyrics_fetcher.cpp index 12a6fb2f..0f30f40d 100644 --- a/src/lyrics_fetcher.cpp +++ b/src/lyrics_fetcher.cpp @@ -38,16 +38,8 @@ std::istream &operator>>(std::istream &is, LyricsFetcher_ &fetcher) { std::string s; is >> s; - if (s == "azlyrics") - fetcher = std::make_unique(); - else if (s == "genius") + if (s == "genius") fetcher = std::make_unique(); - else if (s == "musixmatch") - fetcher = std::make_unique(); - else if (s == "sing365") - fetcher = std::make_unique(); - else if (s == "metrolyrics") - fetcher = std::make_unique(); else if (s == "justsomelyrics") fetcher = std::make_unique(); else if (s == "jahlyrics") @@ -76,7 +68,7 @@ LyricsFetcher::Result LyricsFetcher::fetch(const std::string &artist, std::string url = urlTemplate(); boost::replace_all(url, "%artist%", Curl::escape(artist)); boost::replace_all(url, "%title%", Curl::escape(title)); - + std::string data; CURLcode code = Curl::perform(data, url, "", true); @@ -88,9 +80,11 @@ LyricsFetcher::Result LyricsFetcher::fetch(const std::string &artist, auto lyrics = getContent(regex(), data); + //std::cerr << "URL: " << url << "\n"; + //std::cerr << "Data: " << data << "\n"; + if (lyrics.empty() || notLyrics(data)) { - //std::cerr << "Data: " << data << "\n"; //std::cerr << "Empty: " << lyrics.empty() << "\n"; //std::cerr << "Not Lyrics: " << notLyrics(data) << "\n"; result.second = msgNotFound; @@ -202,14 +196,6 @@ bool GoogleLyricsFetcher::isURLOk(const std::string &url) /**********************************************************************/ -bool MetrolyricsFetcher::isURLOk(const std::string &url) -{ - // it sometimes return link to sitemap.xml, which is huge so we need to discard it - return GoogleLyricsFetcher::isURLOk(url) && url.find("sitemap") == std::string::npos; -} - -/**********************************************************************/ - LyricsFetcher::Result InternetLyricsFetcher::fetch(const std::string &artist, const std::string &title) { diff --git a/src/lyrics_fetcher.h b/src/lyrics_fetcher.h index 672352ff..f4cfc0b2 100644 --- a/src/lyrics_fetcher.h +++ b/src/lyrics_fetcher.h @@ -69,34 +69,6 @@ private: const char *URL; }; -struct MusixmatchFetcher : public GoogleLyricsFetcher -{ - virtual const char *name() const override { return "musixmatch.com"; } - -protected: - virtual const char *regex() const override { return "(.*?)"; } - - virtual void postProcess(std::string &) const override { } -}; - -struct MetrolyricsFetcher : public GoogleLyricsFetcher -{ - virtual const char *name() const override { return "metrolyrics.com"; } - -protected: - virtual const char *regex() const override { return "
(.*?)(.*?)(.*?)
"; } - - virtual bool isURLOk(const std::string &url) override; -}; - -struct Sing365Fetcher : public GoogleLyricsFetcher -{ - virtual const char *name() const override { return "lyrics007.com"; } - -protected: - virtual const char *regex() const override { return "
(.*?)
"; } -}; - struct JustSomeLyricsFetcher : public GoogleLyricsFetcher { virtual const char *name() const override { return "justsomelyrics.com"; } @@ -105,14 +77,6 @@ protected: virtual const char *regex() const override { return "
(.*?)See also"; } }; -struct AzLyricsFetcher : public GoogleLyricsFetcher -{ - virtual const char *name() const override { return "azlyrics.com"; } - -protected: - virtual const char *regex() const override { return "
.*?.*
(.*?)
"; } -}; - struct GeniusFetcher : public GoogleLyricsFetcher { virtual const char *name() const override { return "genius.com"; } @@ -142,7 +106,7 @@ struct TekstowoFetcher : public GoogleLyricsFetcher virtual const char *name() const override { return "tekstowo.pl"; } protected: - virtual const char *regex() const override { return "
.*?(.*?)(.*?)
"; } }; struct ZeneszovegFetcher : public GoogleLyricsFetcher @@ -150,7 +114,7 @@ struct ZeneszovegFetcher : public GoogleLyricsFetcher virtual const char *name() const override { return "zeneszoveg.hu"; } protected: - virtual const char *regex() const override { return "
(.*?)
"; } + virtual const char *regex() const override { return "
(.*?)