void SortPlaylistDialog::sort() const { auto &pl = myPlaylist->main(); auto begin = pl.begin(), end = pl.end(); std::tie(begin, end) = getSelectedRange(begin, end); size_t start_pos = begin - pl.begin(); MPD::SongList playlist; playlist.reserve(end - begin); for (; begin != end; ++begin) playlist.push_back(begin->value()); typedef MPD::SongList::iterator Iterator; LocaleStringComparison cmp(std::locale(), Config.ignore_leading_the); std::function<void(Iterator, Iterator)> iter_swap, quick_sort; auto song_cmp = [this, &cmp](const MPD::Song &a, const MPD::Song &b) -> bool { for (auto it = w.beginV(); it->item().second; ++it) { int res = cmp(a.getTags(it->item().second, Config.tags_separator), b.getTags(it->item().second, Config.tags_separator)); if (res != 0) return res < 0; } return a.getPosition() < b.getPosition(); }; iter_swap = [&playlist, &start_pos](Iterator a, Iterator b) { std::iter_swap(a, b); Mpd.Swap(start_pos+a-playlist.begin(), start_pos+b-playlist.begin()); }; quick_sort = [this, &song_cmp, &quick_sort, &iter_swap](Iterator first, Iterator last) { if (last-first > 1) { Iterator pivot = first+rand()%(last-first); iter_swap(pivot, last-1); pivot = last-1; Iterator tmp = first; for (Iterator i = first; i != pivot; ++i) if (song_cmp(*i, *pivot)) iter_swap(i, tmp++); iter_swap(tmp, pivot); quick_sort(first, tmp); quick_sort(tmp+1, last); } }; Statusbar::msg("Sorting..."); Mpd.StartCommandsList(); quick_sort(playlist.begin(), playlist.end()); if (Mpd.CommitCommandsList()) { Statusbar::msg("Playlist sorted"); switchToPreviousScreen(); } }
void PlaylistEditor::Update() { if (Playlists->ReallyEmpty()) { Content->Clear(); MPD::TagList list; Mpd.GetPlaylists(list); sort(list.begin(), list.end(), CaseInsensitiveSorting()); for (MPD::TagList::iterator it = list.begin(); it != list.end(); ++it) { utf_to_locale(*it); Playlists->AddOption(*it); } Playlists->Window::Clear(); Playlists->Refresh(); } if (!Playlists->Empty() && Content->ReallyEmpty()) { Content->Reset(); MPD::SongList list; Mpd.GetPlaylistContent(locale_to_utf_cpy(Playlists->Current()), list); if (!list.empty()) Content->SetTitle(Config.titles_visibility ? "Playlist's content (" + IntoStr(list.size()) + " item" + (list.size() == 1 ? ")" : "s)") : ""); else Content->SetTitle(Config.titles_visibility ? "Playlist's content" : ""); bool bold = 0; for (MPD::SongList::const_iterator it = list.begin(); it != list.end(); ++it) { for (size_t j = 0; j < myPlaylist->Items->Size(); ++j) { if ((*it)->GetHash() == myPlaylist->Items->at(j).GetHash()) { bold = 1; break; } } Content->AddOption(**it, bold); bold = 0; } MPD::FreeSongList(list); Content->Window::Clear(); Content->Display(); } if (w == Content && Content->ReallyEmpty()) { Content->HighlightColor(Config.main_highlight_color); Playlists->HighlightColor(Config.active_column_color); w = Playlists; } if (Content->ReallyEmpty()) { *Content << XY(0, 0) << "Playlist is empty."; Content->Window::Refresh(); } }
std::string FindSharedDir(const MPD::SongList &v) { if (v.empty()) // this should never happen, but in case... FatalError("empty SongList passed to FindSharedDir(const SongList &)!"); size_t i = -1; std::string first = v.front()->GetDirectory(); for (MPD::SongList::const_iterator it = ++v.begin(); it != v.end(); ++it) { size_t j = 0; std::string dir = (*it)->GetDirectory(); size_t length = std::min(first.length(), dir.length()); while (!first.compare(j, 1, dir, j, 1) && j < length && j < i) ++j; i = j; } return i ? first.substr(0, i) : "/"; }
void MediaLibrary::AddToPlaylist(bool add_n_play) { if (isActiveWindow(Songs) && !Songs.empty()) addSongToPlaylist(Songs.current().value(), add_n_play); else { if ((!Tags.empty() && isActiveWindow(Tags)) || (isActiveWindow(Albums) && Albums.current().value().isAllTracksEntry())) { MPD::SongList list; Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value().tag()); Mpd.CommitSearchSongs(vectorMoveInserter(list)); addSongsToPlaylist(list.begin(), list.end(), add_n_play, -1); std::string tag_type = boost::locale::to_lower( tagTypeToString(Config.media_lib_primary_tag)); Statusbar::msg("Songs with %s = \"%s\" added", tag_type.c_str(), Tags.current().value().tag().c_str()); } else if (isActiveWindow(Albums)) { withUnfilteredMenu(Songs, [&]() { addSongsToPlaylist(Songs.beginV(), Songs.endV(), add_n_play, -1); }); Statusbar::msg("Songs from album \"%s\" added", Albums.current().value().entry().album().c_str()); } } if (!add_n_play) { w->scroll(NC::Scroll::Down); if (isActiveWindow(Tags)) { Albums.clear(); Songs.clear(); } else if (isActiveWindow(Albums)) Songs.clear(); } }
MPD::SongList MediaLibrary::getSelectedSongs() { MPD::SongList result; if (isActiveWindow(Tags)) { auto tag_handler = [&result](const std::string &tag) { Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, tag); Mpd.CommitSearchSongs(vectorMoveInserter(result)); }; bool any_selected = false; for (auto &e : Tags) { if (e.isSelected()) { any_selected = true; tag_handler(e.value().tag()); } } // if no item is selected, add current one if (!any_selected && !Tags.empty()) tag_handler(Tags.current().value().tag()); } else if (isActiveWindow(Albums)) { bool any_selected = false; for (auto it = Albums.begin(); it != Albums.end() && !it->isSeparator(); ++it) { if (it->isSelected()) { any_selected = true; auto &sc = it->value(); Mpd.StartSearch(true); if (hasTwoColumns) Mpd.AddSearch(Config.media_lib_primary_tag, sc.entry().tag()); else Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value().tag()); Mpd.AddSearch(MPD_TAG_ALBUM, sc.entry().album()); Mpd.AddSearch(MPD_TAG_DATE, sc.entry().date()); size_t begin = result.size(); Mpd.CommitSearchSongs(vectorMoveInserter(result)); std::sort(result.begin()+begin, result.end(), SortSongs(false)); } } // if no item is selected, add songs from right column if (!any_selected && !Albums.empty()) { withUnfilteredMenu(Songs, [this, &result]() { result.insert(result.end(), Songs.beginV(), Songs.endV()); }); } } else if (isActiveWindow(Songs)) { for (auto it = Songs.begin(); it != Songs.end(); ++it) if (it->isSelected()) result.push_back(it->value()); // if no item is selected, add current one if (result.empty() && !Songs.empty()) result.push_back(Songs.current().value()); } return result; }
void SearchEngine::Search() { bool constraints_empty = 1; for (size_t i = 0; i < ConstraintsNumber; ++i) { if (!itsConstraints[i].empty()) { constraints_empty = 0; break; } } if (constraints_empty) return; if (Config.search_in_db && (SearchMode == &SearchModes[0] || SearchMode == &SearchModes[2])) // use built-in mpd searching { Mpd.StartSearch(SearchMode == &SearchModes[2]); if (!itsConstraints[0].empty()) Mpd.AddSearchAny(itsConstraints[0]); if (!itsConstraints[1].empty()) Mpd.AddSearch(MPD_TAG_ARTIST, itsConstraints[1]); if (!itsConstraints[2].empty()) Mpd.AddSearch(MPD_TAG_TITLE, itsConstraints[2]); if (!itsConstraints[3].empty()) Mpd.AddSearch(MPD_TAG_ALBUM, itsConstraints[3]); if (!itsConstraints[4].empty()) Mpd.AddSearchURI(itsConstraints[4]); if (!itsConstraints[5].empty()) Mpd.AddSearch(MPD_TAG_COMPOSER, itsConstraints[5]); if (!itsConstraints[6].empty()) Mpd.AddSearch(MPD_TAG_PERFORMER, itsConstraints[6]); if (!itsConstraints[7].empty()) Mpd.AddSearch(MPD_TAG_GENRE, itsConstraints[7]); if (!itsConstraints[8].empty()) Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[8]); if (!itsConstraints[9].empty()) Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[9]); MPD::SongList results; Mpd.CommitSearch(results); for (MPD::SongList::const_iterator it = results.begin(); it != results.end(); ++it) w->AddOption(std::make_pair(static_cast<Buffer *>(0), *it)); return; } MPD::SongList list; if (Config.search_in_db) Mpd.GetDirectoryRecursive("/", list); else { list.reserve(myPlaylist->Items->Size()); for (size_t i = 0; i < myPlaylist->Items->Size(); ++i) list.push_back(&(*myPlaylist->Items)[i]); } bool any_found = 1; bool found = 1; for (MPD::SongList::const_iterator it = list.begin(); it != list.end(); ++it) { if (SearchMode != &SearchModes[2]) // match to pattern { regex_t rx; if (!itsConstraints[0].empty()) { if (regcomp(&rx, itsConstraints[0].c_str(), REG_ICASE | Config.regex_type) == 0) { any_found = !regexec(&rx, (*it)->GetArtist().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetTitle().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetAlbum().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetName().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetComposer().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetPerformer().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetGenre().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetDate().c_str(), 0, 0, 0) || !regexec(&rx, (*it)->GetComment().c_str(), 0, 0, 0); } regfree(&rx); } if (found && !itsConstraints[1].empty()) { if (!regcomp(&rx, itsConstraints[1].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetArtist().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[2].empty()) { if (!regcomp(&rx, itsConstraints[2].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetTitle().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[3].empty()) { if (!regcomp(&rx, itsConstraints[3].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetAlbum().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[4].empty()) { if (!regcomp(&rx, itsConstraints[4].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetName().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[5].empty()) { if (!regcomp(&rx, itsConstraints[5].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetComposer().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[6].empty()) { if (!regcomp(&rx, itsConstraints[6].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetPerformer().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[7].empty()) { if (!regcomp(&rx, itsConstraints[7].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetGenre().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[8].empty()) { if (!regcomp(&rx, itsConstraints[8].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetDate().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[9].empty()) { if (!regcomp(&rx, itsConstraints[9].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, (*it)->GetComment().c_str(), 0, 0, 0); regfree(&rx); } } else // match only if values are equal { CaseInsensitiveStringComparison cmp; if (!itsConstraints[0].empty()) any_found = !cmp((*it)->GetArtist(), itsConstraints[0]) || !cmp((*it)->GetTitle(), itsConstraints[0]) || !cmp((*it)->GetAlbum(), itsConstraints[0]) || !cmp((*it)->GetName(), itsConstraints[0]) || !cmp((*it)->GetComposer(), itsConstraints[0]) || !cmp((*it)->GetPerformer(), itsConstraints[0]) || !cmp((*it)->GetGenre(), itsConstraints[0]) || !cmp((*it)->GetDate(), itsConstraints[0]) || !cmp((*it)->GetComment(), itsConstraints[0]); if (found && !itsConstraints[1].empty()) found = !cmp((*it)->GetArtist(), itsConstraints[1]); if (found && !itsConstraints[2].empty()) found = !cmp((*it)->GetTitle(), itsConstraints[2]); if (found && !itsConstraints[3].empty()) found = !cmp((*it)->GetAlbum(), itsConstraints[3]); if (found && !itsConstraints[4].empty()) found = !cmp((*it)->GetName(), itsConstraints[4]); if (found && !itsConstraints[5].empty()) found = !cmp((*it)->GetComposer(), itsConstraints[5]); if (found && !itsConstraints[6].empty()) found = !cmp((*it)->GetPerformer(), itsConstraints[6]); if (found && !itsConstraints[7].empty()) found = !cmp((*it)->GetGenre(), itsConstraints[7]); if (found && !itsConstraints[8].empty()) found = !cmp((*it)->GetDate(), itsConstraints[8]); if (found && !itsConstraints[9].empty()) found = !cmp((*it)->GetComment(), itsConstraints[9]); } if (found && any_found) { MPD::Song *ss = Config.search_in_db ? *it : new MPD::Song(**it); w->AddOption(std::make_pair(static_cast<Buffer *>(0), ss)); list[it-list.begin()] = 0; } found = 1; any_found = 1; } if (Config.search_in_db) // free song list only if it's database MPD::FreeSongList(list); }
void SearchEngine::Search() { bool constraints_empty = 1; for (size_t i = 0; i < ConstraintsNumber; ++i) { if (!itsConstraints[i].empty()) { constraints_empty = 0; break; } } if (constraints_empty) return; if (Config.search_in_db && (SearchMode == &SearchModes[0] || SearchMode == &SearchModes[2])) // use built-in mpd searching { Mpd.StartSearch(SearchMode == &SearchModes[2]); if (!itsConstraints[0].empty()) Mpd.AddSearchAny(itsConstraints[0]); if (!itsConstraints[1].empty()) Mpd.AddSearch(MPD_TAG_ARTIST, itsConstraints[1]); if (!itsConstraints[2].empty()) Mpd.AddSearch(MPD_TAG_ALBUM_ARTIST, itsConstraints[2]); if (!itsConstraints[3].empty()) Mpd.AddSearch(MPD_TAG_TITLE, itsConstraints[3]); if (!itsConstraints[4].empty()) Mpd.AddSearch(MPD_TAG_ALBUM, itsConstraints[4]); if (!itsConstraints[5].empty()) Mpd.AddSearchURI(itsConstraints[5]); if (!itsConstraints[6].empty()) Mpd.AddSearch(MPD_TAG_COMPOSER, itsConstraints[6]); if (!itsConstraints[7].empty()) Mpd.AddSearch(MPD_TAG_PERFORMER, itsConstraints[7]); if (!itsConstraints[8].empty()) Mpd.AddSearch(MPD_TAG_GENRE, itsConstraints[8]); if (!itsConstraints[9].empty()) Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]); if (!itsConstraints[10].empty()) Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]); auto songs = Mpd.CommitSearchSongs(); for (auto s = songs.begin(); s != songs.end(); ++s) w.addItem(*s); return; } MPD::SongList list; if (Config.search_in_db) list = Mpd.GetDirectoryRecursive("/"); else { list.reserve(myPlaylist->main().size()); for (auto s = myPlaylist->main().beginV(); s != myPlaylist->main().endV(); ++s) list.push_back(*s); } bool any_found = 1; bool found = 1; LocaleStringComparison cmp(std::locale(), Config.ignore_leading_the); for (auto it = list.begin(); it != list.end(); ++it) { if (SearchMode != &SearchModes[2]) // match to pattern { regex_t rx; if (!itsConstraints[0].empty()) { if (regcomp(&rx, itsConstraints[0].c_str(), REG_ICASE | Config.regex_type) == 0) { any_found = !regexec(&rx, it->getArtist().c_str(), 0, 0, 0) || !regexec(&rx, it->getAlbumArtist().c_str(), 0, 0, 0) || !regexec(&rx, it->getTitle().c_str(), 0, 0, 0) || !regexec(&rx, it->getAlbum().c_str(), 0, 0, 0) || !regexec(&rx, it->getName().c_str(), 0, 0, 0) || !regexec(&rx, it->getComposer().c_str(), 0, 0, 0) || !regexec(&rx, it->getPerformer().c_str(), 0, 0, 0) || !regexec(&rx, it->getGenre().c_str(), 0, 0, 0) || !regexec(&rx, it->getDate().c_str(), 0, 0, 0) || !regexec(&rx, it->getComment().c_str(), 0, 0, 0); } regfree(&rx); } if (found && !itsConstraints[1].empty()) { if (!regcomp(&rx, itsConstraints[1].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getArtist().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[2].empty()) { if (!regcomp(&rx, itsConstraints[2].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getAlbumArtist().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[3].empty()) { if(!regcomp(&rx, itsConstraints[3].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getTitle().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[4].empty()) { if (!regcomp(&rx, itsConstraints[4].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getAlbum().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[5].empty()) { if (!regcomp(&rx, itsConstraints[5].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getName().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[6].empty()) { if (!regcomp(&rx, itsConstraints[6].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getComposer().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[7].empty()) { if (!regcomp(&rx, itsConstraints[7].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getPerformer().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[8].empty()) { if (!regcomp(&rx, itsConstraints[8].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getGenre().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[9].empty()) { if (!regcomp(&rx, itsConstraints[9].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getDate().c_str(), 0, 0, 0); regfree(&rx); } if (found && !itsConstraints[10].empty()) { if (!regcomp(&rx, itsConstraints[10].c_str(), REG_ICASE | Config.regex_type)) found = !regexec(&rx, it->getComment().c_str(), 0, 0, 0); regfree(&rx); } } else // match only if values are equal { if (!itsConstraints[0].empty()) any_found = !cmp(it->getArtist(), itsConstraints[0]) || !cmp(it->getAlbumArtist(), itsConstraints[0]) || !cmp(it->getTitle(), itsConstraints[0]) || !cmp(it->getAlbum(), itsConstraints[0]) || !cmp(it->getName(), itsConstraints[0]) || !cmp(it->getComposer(), itsConstraints[0]) || !cmp(it->getPerformer(), itsConstraints[0]) || !cmp(it->getGenre(), itsConstraints[0]) || !cmp(it->getDate(), itsConstraints[0]) || !cmp(it->getComment(), itsConstraints[0]); if (found && !itsConstraints[1].empty()) found = !cmp(it->getArtist(), itsConstraints[1]); if (found && !itsConstraints[2].empty()) found = !cmp(it->getAlbumArtist(), itsConstraints[2]); if (found && !itsConstraints[3].empty()) found = !cmp(it->getTitle(), itsConstraints[3]); if (found && !itsConstraints[4].empty()) found = !cmp(it->getAlbum(), itsConstraints[4]); if (found && !itsConstraints[5].empty()) found = !cmp(it->getName(), itsConstraints[5]); if (found && !itsConstraints[6].empty()) found = !cmp(it->getComposer(), itsConstraints[6]); if (found && !itsConstraints[7].empty()) found = !cmp(it->getPerformer(), itsConstraints[7]); if (found && !itsConstraints[8].empty()) found = !cmp(it->getGenre(), itsConstraints[8]); if (found && !itsConstraints[9].empty()) found = !cmp(it->getDate(), itsConstraints[9]); if (found && !itsConstraints[10].empty()) found = !cmp(it->getComment(), itsConstraints[10]); } if (found && any_found) w.addItem(*it); found = 1; any_found = 1; } }