media library: add support for sorting by mtime
This commit is contained in:
committed by
Andrzej Rybczak
parent
add40d542d
commit
b487f10f10
@@ -431,6 +431,9 @@
|
|||||||
#def_key "m"
|
#def_key "m"
|
||||||
# move_selected_items_up
|
# move_selected_items_up
|
||||||
#
|
#
|
||||||
|
#def_key "m"
|
||||||
|
# toggle_media_library_sort_mode
|
||||||
|
#
|
||||||
#def_key "n"
|
#def_key "n"
|
||||||
# move_sort_order_down
|
# move_sort_order_down
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -437,6 +437,8 @@
|
|||||||
#
|
#
|
||||||
#media_library_display_empty_tag = "yes"
|
#media_library_display_empty_tag = "yes"
|
||||||
#
|
#
|
||||||
|
#media_library_sort_by_mtime = "no"
|
||||||
|
#
|
||||||
#enable_window_title = "yes"
|
#enable_window_title = "yes"
|
||||||
#
|
#
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -1397,13 +1397,13 @@ void EditLibraryTag::Run()
|
|||||||
|
|
||||||
Statusbar::lock();
|
Statusbar::lock();
|
||||||
Statusbar::put() << NC::fmtBold << tagTypeToString(Config.media_lib_primary_tag) << NC::fmtBoldEnd << ": ";
|
Statusbar::put() << NC::fmtBold << tagTypeToString(Config.media_lib_primary_tag) << NC::fmtBoldEnd << ": ";
|
||||||
std::string new_tag = wFooter->getString(myLibrary->Tags.current().value());
|
std::string new_tag = wFooter->getString(myLibrary->Tags.current().value().tag());
|
||||||
Statusbar::unlock();
|
Statusbar::unlock();
|
||||||
if (!new_tag.empty() && new_tag != myLibrary->Tags.current().value())
|
if (!new_tag.empty() && new_tag != myLibrary->Tags.current().value().tag())
|
||||||
{
|
{
|
||||||
Statusbar::msg("Updating tags...");
|
Statusbar::msg("Updating tags...");
|
||||||
Mpd.StartSearch(1);
|
Mpd.StartSearch(1);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, myLibrary->Tags.current().value());
|
Mpd.AddSearch(Config.media_lib_primary_tag, myLibrary->Tags.current().value().tag());
|
||||||
MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag);
|
MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag);
|
||||||
assert(set);
|
assert(set);
|
||||||
bool success = true;
|
bool success = true;
|
||||||
@@ -2162,12 +2162,15 @@ void ToggleLibraryTagType::Run()
|
|||||||
myLibrary->Tags.setTitle(Config.titles_visibility ? item_type + "s" : "");
|
myLibrary->Tags.setTitle(Config.titles_visibility ? item_type + "s" : "");
|
||||||
myLibrary->Tags.reset();
|
myLibrary->Tags.reset();
|
||||||
item_type = lowercase(item_type);
|
item_type = lowercase(item_type);
|
||||||
|
std::string and_mtime = Config.media_library_sort_by_mtime ?
|
||||||
|
" and mtime" :
|
||||||
|
"";
|
||||||
if (myLibrary->Columns() == 2)
|
if (myLibrary->Columns() == 2)
|
||||||
{
|
{
|
||||||
myLibrary->Songs.clear();
|
myLibrary->Songs.clear();
|
||||||
myLibrary->Albums.reset();
|
myLibrary->Albums.reset();
|
||||||
myLibrary->Albums.clear();
|
myLibrary->Albums.clear();
|
||||||
myLibrary->Albums.setTitle(Config.titles_visibility ? "Albums (sorted by " + item_type + ")" : "");
|
myLibrary->Albums.setTitle(Config.titles_visibility ? "Albums (sorted by " + item_type + and_mtime + ")" : "");
|
||||||
myLibrary->Albums.display();
|
myLibrary->Albums.display();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2179,6 +2182,16 @@ void ToggleLibraryTagType::Run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ToggleMediaLibrarySortMode::canBeRun() const
|
||||||
|
{
|
||||||
|
return myScreen == myLibrary;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleMediaLibrarySortMode::Run()
|
||||||
|
{
|
||||||
|
myLibrary->toggleMTimeSort();
|
||||||
|
}
|
||||||
|
|
||||||
bool RefetchLyrics::canBeRun() const
|
bool RefetchLyrics::canBeRun() const
|
||||||
{
|
{
|
||||||
# ifdef HAVE_CURL_CURL_H
|
# ifdef HAVE_CURL_CURL_H
|
||||||
@@ -2295,7 +2308,7 @@ void ShowArtistInfo::Run()
|
|||||||
{
|
{
|
||||||
assert(!myLibrary->Tags.empty());
|
assert(!myLibrary->Tags.empty());
|
||||||
assert(Config.media_lib_primary_tag == MPD_TAG_ARTIST);
|
assert(Config.media_lib_primary_tag == MPD_TAG_ARTIST);
|
||||||
artist = myLibrary->Tags.current().value();
|
artist = myLibrary->Tags.current().value().tag();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2660,6 +2673,7 @@ void populateActions()
|
|||||||
insertAction(new AddRandomItems());
|
insertAction(new AddRandomItems());
|
||||||
insertAction(new ToggleBrowserSortMode());
|
insertAction(new ToggleBrowserSortMode());
|
||||||
insertAction(new ToggleLibraryTagType());
|
insertAction(new ToggleLibraryTagType());
|
||||||
|
insertAction(new ToggleMediaLibrarySortMode());
|
||||||
insertAction(new RefetchLyrics());
|
insertAction(new RefetchLyrics());
|
||||||
insertAction(new RefetchArtistInfo());
|
insertAction(new RefetchArtistInfo());
|
||||||
insertAction(new SetSelectedItemsPriority());
|
insertAction(new SetSelectedItemsPriority());
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ enum ActionType
|
|||||||
aCropMainPlaylist, aCropPlaylist, aClearMainPlaylist, aClearPlaylist, aSortPlaylist, aReversePlaylist,
|
aCropMainPlaylist, aCropPlaylist, aClearMainPlaylist, aClearPlaylist, aSortPlaylist, aReversePlaylist,
|
||||||
aApplyFilter, aFind, aFindItemForward, aFindItemBackward, aNextFoundItem,
|
aApplyFilter, aFind, aFindItemForward, aFindItemBackward, aNextFoundItem,
|
||||||
aPreviousFoundItem, aToggleFindMode, aToggleReplayGainMode, aToggleSpaceMode, aToggleAddMode,
|
aPreviousFoundItem, aToggleFindMode, aToggleReplayGainMode, aToggleSpaceMode, aToggleAddMode,
|
||||||
aToggleMouse, aToggleBitrateVisibility, aAddRandomItems, aToggleBrowserSortMode, aToggleLibraryTagType,
|
aToggleMouse, aToggleBitrateVisibility, aAddRandomItems, aToggleBrowserSortMode, aToggleLibraryTagType, aToggleMediaLibrarySortMode,
|
||||||
aRefetchLyrics, aRefetchArtistInfo, aSetSelectedItemsPriority, aFilterPlaylistOnPriorities,
|
aRefetchLyrics, aRefetchArtistInfo, aSetSelectedItemsPriority, aFilterPlaylistOnPriorities,
|
||||||
aShowSongInfo, aShowArtistInfo,
|
aShowSongInfo, aShowArtistInfo,
|
||||||
aShowLyrics, aQuit, aNextScreen, aPreviousScreen, aShowHelp, aShowPlaylist, aShowBrowser, aChangeBrowseMode,
|
aShowLyrics, aQuit, aNextScreen, aPreviousScreen, aShowHelp, aShowPlaylist, aShowBrowser, aChangeBrowseMode,
|
||||||
@@ -914,6 +914,16 @@ protected:
|
|||||||
virtual void Run();
|
virtual void Run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ToggleMediaLibrarySortMode : public Action
|
||||||
|
{
|
||||||
|
ToggleMediaLibrarySortMode()
|
||||||
|
: Action(aToggleMediaLibrarySortMode, "toggle_media_library_sort_mode") { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool canBeRun() const;
|
||||||
|
virtual void Run();
|
||||||
|
};
|
||||||
|
|
||||||
struct RefetchLyrics : public Action
|
struct RefetchLyrics : public Action
|
||||||
{
|
{
|
||||||
RefetchLyrics() : Action(aRefetchLyrics, "refetch_lyrics") { }
|
RefetchLyrics() : Action(aRefetchLyrics, "refetch_lyrics") { }
|
||||||
|
|||||||
@@ -529,6 +529,7 @@ void BindingsConfiguration::generateDefaults()
|
|||||||
{
|
{
|
||||||
bind(k, aMoveSortOrderUp);
|
bind(k, aMoveSortOrderUp);
|
||||||
bind(k, aMoveSelectedItemsUp);
|
bind(k, aMoveSelectedItemsUp);
|
||||||
|
bind(k, aToggleMediaLibrarySortMode);
|
||||||
}
|
}
|
||||||
if (notBound(k = stringToKey("n")))
|
if (notBound(k = stringToKey("n")))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -325,6 +325,7 @@ void Help::GetKeybindings()
|
|||||||
# endif // HAVE_TAGLIB_H
|
# endif // HAVE_TAGLIB_H
|
||||||
KeyDesc(aEditLibraryTag, "Edit tag (left column)/album (middle/right column)");
|
KeyDesc(aEditLibraryTag, "Edit tag (left column)/album (middle/right column)");
|
||||||
KeyDesc(aToggleLibraryTagType, "Toggle type of tag used in left column");
|
KeyDesc(aToggleLibraryTagType, "Toggle type of tag used in left column");
|
||||||
|
KeyDesc(aToggleMediaLibrarySortMode, "Toggle sort mode");
|
||||||
|
|
||||||
KeysSection("Playlist editor");
|
KeysSection("Playlist editor");
|
||||||
KeyDesc(aPreviousColumn, "Previous column");
|
KeyDesc(aPreviousColumn, "Previous column");
|
||||||
|
|||||||
@@ -66,12 +66,12 @@ typedef MediaLibrary::SearchConstraints SearchConstraints;
|
|||||||
std::string AlbumToString(const SearchConstraints &sc);
|
std::string AlbumToString(const SearchConstraints &sc);
|
||||||
std::string SongToString(const MPD::Song &s);
|
std::string SongToString(const MPD::Song &s);
|
||||||
|
|
||||||
bool TagEntryMatcher(const Regex &rx, const std::string &tag);
|
bool TagEntryMatcher(const Regex &rx, const MPD::TagMTime &tagmtime);
|
||||||
bool AlbumEntryMatcher(const Regex &rx, const NC::Menu<SearchConstraints>::Item &item, bool filter);
|
bool AlbumEntryMatcher(const Regex &rx, const NC::Menu<SearchConstraints>::Item &item, bool filter);
|
||||||
bool SongEntryMatcher(const Regex &rx, const MPD::Song &s);
|
bool SongEntryMatcher(const Regex &rx, const MPD::Song &s);
|
||||||
|
|
||||||
void DisplayAlbums(NC::Menu<SearchConstraints> &menu);
|
void DisplayAlbums(NC::Menu<SearchConstraints> &menu);
|
||||||
void DisplayPrimaryTags(NC::Menu<std::string> &menu);
|
void DisplayPrimaryTags(NC::Menu<MPD::TagMTime> &menu);
|
||||||
|
|
||||||
bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b);
|
bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b);
|
||||||
|
|
||||||
@@ -101,14 +101,34 @@ class SortSearchConstraints {
|
|||||||
public:
|
public:
|
||||||
SortSearchConstraints() : m_cmp(std::locale(), Config.ignore_leading_the) { }
|
SortSearchConstraints() : m_cmp(std::locale(), Config.ignore_leading_the) { }
|
||||||
bool operator()(const SearchConstraints &a, const SearchConstraints &b) const {
|
bool operator()(const SearchConstraints &a, const SearchConstraints &b) const {
|
||||||
int result;
|
if (Config.media_library_sort_by_mtime)
|
||||||
result = m_cmp(a.PrimaryTag, b.PrimaryTag);
|
{
|
||||||
if (result != 0)
|
return a.MTime > b.MTime;
|
||||||
return result < 0;
|
}
|
||||||
result = m_cmp(a.Date, b.Date);
|
else
|
||||||
if (result != 0)
|
{
|
||||||
return result < 0;
|
int result;
|
||||||
return m_cmp(a.Album, b.Album) < 0;
|
result = m_cmp(a.PrimaryTag, b.PrimaryTag);
|
||||||
|
if (result != 0)
|
||||||
|
return result < 0;
|
||||||
|
result = m_cmp(a.Date, b.Date);
|
||||||
|
if (result != 0)
|
||||||
|
return result < 0;
|
||||||
|
return m_cmp(a.Album, b.Album) < 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArtistSorting {
|
||||||
|
LocaleStringComparison m_cmp;
|
||||||
|
public:
|
||||||
|
ArtistSorting() : m_cmp(std::locale(), Config.ignore_leading_the) { }
|
||||||
|
bool operator()(const MPD::TagMTime &a,
|
||||||
|
const MPD::TagMTime &b) const {
|
||||||
|
if (Config.media_library_sort_by_mtime)
|
||||||
|
return a.mtime() > b.mtime();
|
||||||
|
else
|
||||||
|
return m_cmp(a.tag(), b.tag()) < 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,7 +143,7 @@ MediaLibrary::MediaLibrary()
|
|||||||
itsRightColWidth = COLS-COLS/3*2-1;
|
itsRightColWidth = COLS-COLS/3*2-1;
|
||||||
itsRightColStartX = itsLeftColWidth+itsMiddleColWidth+2;
|
itsRightColStartX = itsLeftColWidth+itsMiddleColWidth+2;
|
||||||
|
|
||||||
Tags = NC::Menu<std::string>(0, MainStartY, itsLeftColWidth, MainHeight, Config.titles_visibility ? tagTypeToString(Config.media_lib_primary_tag) + "s" : "", Config.main_color, NC::brNone);
|
Tags = NC::Menu<MPD::TagMTime>(0, MainStartY, itsLeftColWidth, MainHeight, Config.titles_visibility ? tagTypeToString(Config.media_lib_primary_tag) + "s" : "", Config.main_color, NC::brNone);
|
||||||
Tags.setHighlightColor(Config.active_column_color);
|
Tags.setHighlightColor(Config.active_column_color);
|
||||||
Tags.cyclicScrolling(Config.use_cyclic_scrolling);
|
Tags.cyclicScrolling(Config.use_cyclic_scrolling);
|
||||||
Tags.centeredCursor(Config.centered_cursor);
|
Tags.centeredCursor(Config.centered_cursor);
|
||||||
@@ -209,18 +229,74 @@ std::wstring MediaLibrary::title()
|
|||||||
return L"Media library";
|
return L"Media library";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MediaLibrary::hasMTimes()
|
||||||
|
{
|
||||||
|
bool has = false;
|
||||||
|
if (hasTwoColumns && !Albums.empty())
|
||||||
|
has = Albums.current().value().hasMTime();
|
||||||
|
else if (!hasTwoColumns && !Tags.empty())
|
||||||
|
has = Tags.current().value().hasMTime();
|
||||||
|
return has;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaLibrary::toggleMTimeSort()
|
||||||
|
{
|
||||||
|
Config.media_library_sort_by_mtime = !Config.media_library_sort_by_mtime;
|
||||||
|
if (Config.media_library_sort_by_mtime)
|
||||||
|
Statusbar::msg("Sorting library by: Modification time");
|
||||||
|
else
|
||||||
|
Statusbar::msg("Sorting library by: Name");
|
||||||
|
|
||||||
|
if (!hasMTimes() && Config.media_library_sort_by_mtime)
|
||||||
|
{
|
||||||
|
Tags.clear();
|
||||||
|
Albums.clear();
|
||||||
|
Songs.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!hasTwoColumns)
|
||||||
|
{
|
||||||
|
std::sort(Tags.beginV(), Tags.endV(), ArtistSorting());
|
||||||
|
Tags.refresh();
|
||||||
|
Albums.clear();
|
||||||
|
Songs.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::sort(Albums.beginV(), Albums.endV(), SortSearchConstraints());
|
||||||
|
Albums.refresh();
|
||||||
|
Songs.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasTwoColumns)
|
||||||
|
{
|
||||||
|
if (Config.titles_visibility)
|
||||||
|
{
|
||||||
|
std::string item_type = lowercase(tagTypeToString(Config.media_lib_primary_tag));
|
||||||
|
std::string and_mtime = Config.media_library_sort_by_mtime ?
|
||||||
|
" and mtime" :
|
||||||
|
"";
|
||||||
|
Albums.setTitle("Albums (sorted by " + item_type + and_mtime + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void MediaLibrary::update()
|
void MediaLibrary::update()
|
||||||
{
|
{
|
||||||
if (!hasTwoColumns && Tags.reallyEmpty())
|
if (!hasTwoColumns && Tags.reallyEmpty())
|
||||||
{
|
{
|
||||||
Albums.clear();
|
Albums.clear();
|
||||||
Songs.clear();
|
Songs.clear();
|
||||||
auto list = Mpd.GetList(Config.media_lib_primary_tag);
|
auto list = Mpd.GetListMTime(Config.media_lib_primary_tag,
|
||||||
std::sort(list.begin(), list.end(),
|
Config.media_library_sort_by_mtime);
|
||||||
LocaleBasedSorting(std::locale(), Config.ignore_leading_the));
|
|
||||||
|
std::sort(list.begin(), list.end(), ArtistSorting());
|
||||||
for (auto it = list.begin(); it != list.end(); ++it)
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->empty() && !Config.media_library_display_empty_tag)
|
if (it->tag().empty() && !Config.media_library_display_empty_tag)
|
||||||
continue;
|
continue;
|
||||||
Tags.addItem(*it);
|
Tags.addItem(*it);
|
||||||
}
|
}
|
||||||
@@ -234,22 +310,26 @@ void MediaLibrary::update()
|
|||||||
// and slows down the whole process.
|
// and slows down the whole process.
|
||||||
Mpd.BlockIdle(true);
|
Mpd.BlockIdle(true);
|
||||||
Albums.reset();
|
Albums.reset();
|
||||||
Mpd.StartFieldSearch(MPD_TAG_ALBUM);
|
Mpd.StartFieldSearchMTime(MPD_TAG_ALBUM, Config.media_library_sort_by_mtime);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value());
|
Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value().tag());
|
||||||
auto albums = Mpd.CommitSearchTags();
|
auto albums = Mpd.CommitSearchTagsMTime();
|
||||||
for (auto album = albums.begin(); album != albums.end(); ++album)
|
for (auto tagmtime = albums.begin(); tagmtime != albums.end(); ++tagmtime)
|
||||||
{
|
{
|
||||||
|
const std::string &album = tagmtime->tag();
|
||||||
|
time_t mtime = tagmtime->mtime();
|
||||||
if (Config.media_library_display_date)
|
if (Config.media_library_display_date)
|
||||||
{
|
{
|
||||||
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value());
|
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, *album);
|
Mpd.AddSearch(Config.media_lib_primary_tag,
|
||||||
|
Tags.current().value().tag());
|
||||||
|
Mpd.AddSearch(MPD_TAG_ALBUM, album);
|
||||||
auto dates = Mpd.CommitSearchTags();
|
auto dates = Mpd.CommitSearchTags();
|
||||||
for (auto date = dates.begin(); date != dates.end(); ++date)
|
for (auto date = dates.begin(); date != dates.end(); ++date)
|
||||||
Albums.addItem(SearchConstraints(*album, *date));
|
Albums.addItem(SearchConstraints(album, *date, mtime));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Albums.addItem(SearchConstraints(*album, ""));
|
Albums.addItem(SearchConstraints(album, "", mtime));
|
||||||
}
|
}
|
||||||
if (!Albums.empty())
|
if (!Albums.empty())
|
||||||
std::sort(Albums.beginV(), Albums.endV(), SortSearchConstraints());
|
std::sort(Albums.beginV(), Albums.endV(), SortSearchConstraints());
|
||||||
@@ -270,30 +350,33 @@ void MediaLibrary::update()
|
|||||||
auto artists = Mpd.GetList(Config.media_lib_primary_tag);
|
auto artists = Mpd.GetList(Config.media_lib_primary_tag);
|
||||||
for (auto artist = artists.begin(); artist != artists.end(); ++artist)
|
for (auto artist = artists.begin(); artist != artists.end(); ++artist)
|
||||||
{
|
{
|
||||||
Mpd.StartFieldSearch(MPD_TAG_ALBUM);
|
Mpd.StartFieldSearchMTime(MPD_TAG_ALBUM, Config.media_library_sort_by_mtime);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
||||||
auto albums = Mpd.CommitSearchTags();
|
auto albums = Mpd.CommitSearchTagsMTime();
|
||||||
for (auto album = albums.begin(); album != albums.end(); ++album)
|
for (auto am = albums.begin(); am != albums.end(); ++am)
|
||||||
{
|
{
|
||||||
|
const std::string &album = am->tag();
|
||||||
|
time_t mtime = am->mtime();
|
||||||
if (Config.media_library_display_date)
|
if (Config.media_library_display_date)
|
||||||
{
|
{
|
||||||
if (Config.media_lib_primary_tag != MPD_TAG_DATE)
|
if (Config.media_lib_primary_tag != MPD_TAG_DATE)
|
||||||
{
|
{
|
||||||
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, *album);
|
Mpd.AddSearch(MPD_TAG_ALBUM, album);
|
||||||
auto dates = Mpd.CommitSearchTags();
|
auto dates = Mpd.CommitSearchTags();
|
||||||
for (auto date = dates.begin(); date != dates.end(); ++date)
|
for (auto date = dates.begin(); date != dates.end(); ++date)
|
||||||
Albums.addItem(SearchConstraints(*artist, *album, *date));
|
Albums.addItem(SearchConstraints(*artist, album, *date, mtime));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Albums.addItem(SearchConstraints(*artist, *album, *artist));
|
Albums.addItem(SearchConstraints(*artist, album, *artist, mtime));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Albums.addItem(SearchConstraints(*artist, *album, ""));
|
Albums.addItem(SearchConstraints(*artist, album, "", mtime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mpd.BlockIdle(0);
|
Mpd.BlockIdle(0);
|
||||||
|
|
||||||
if (!Albums.empty())
|
if (!Albums.empty())
|
||||||
std::sort(Albums.beginV(), Albums.endV(), SortSearchConstraints());
|
std::sort(Albums.beginV(), Albums.endV(), SortSearchConstraints());
|
||||||
Albums.refresh();
|
Albums.refresh();
|
||||||
@@ -311,7 +394,9 @@ void MediaLibrary::update()
|
|||||||
Songs.reset();
|
Songs.reset();
|
||||||
|
|
||||||
Mpd.StartSearch(1);
|
Mpd.StartSearch(1);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, hasTwoColumns ? Albums.current().value().PrimaryTag : Tags.current().value());
|
Mpd.AddSearch(Config.media_lib_primary_tag,
|
||||||
|
hasTwoColumns ? Albums.current().value().PrimaryTag :
|
||||||
|
Tags.current().value().tag());
|
||||||
if (Albums.current().value().Date != AllTracksMarker)
|
if (Albums.current().value().Date != AllTracksMarker)
|
||||||
{
|
{
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, Albums.current().value().Album);
|
Mpd.AddSearch(MPD_TAG_ALBUM, Albums.current().value().Album);
|
||||||
@@ -471,7 +556,7 @@ std::string MediaLibrary::currentFilter()
|
|||||||
{
|
{
|
||||||
std::string filter;
|
std::string filter;
|
||||||
if (isActiveWindow(Tags))
|
if (isActiveWindow(Tags))
|
||||||
filter = RegexFilter<std::string>::currentFilter(Tags);
|
filter = RegexFilter<MPD::TagMTime>::currentFilter(Tags);
|
||||||
else if (isActiveWindow(Albums))
|
else if (isActiveWindow(Albums))
|
||||||
filter = RegexItemFilter<SearchConstraints>::currentFilter(Albums);
|
filter = RegexItemFilter<SearchConstraints>::currentFilter(Albums);
|
||||||
else if (isActiveWindow(Songs))
|
else if (isActiveWindow(Songs))
|
||||||
@@ -484,7 +569,7 @@ void MediaLibrary::applyFilter(const std::string &filter)
|
|||||||
if (isActiveWindow(Tags))
|
if (isActiveWindow(Tags))
|
||||||
{
|
{
|
||||||
Tags.showAll();
|
Tags.showAll();
|
||||||
auto rx = RegexFilter<std::string>(filter, Config.regex_type, TagEntryMatcher);
|
auto rx = RegexFilter<MPD::TagMTime>(filter, Config.regex_type, TagEntryMatcher);
|
||||||
Tags.filter(Tags.begin(), Tags.end(), rx);
|
Tags.filter(Tags.begin(), Tags.end(), rx);
|
||||||
}
|
}
|
||||||
else if (isActiveWindow(Albums))
|
else if (isActiveWindow(Albums))
|
||||||
@@ -514,7 +599,7 @@ bool MediaLibrary::search(const std::string &constraint)
|
|||||||
bool result = false;
|
bool result = false;
|
||||||
if (isActiveWindow(Tags))
|
if (isActiveWindow(Tags))
|
||||||
{
|
{
|
||||||
auto rx = RegexFilter<std::string>(constraint, Config.regex_type, TagEntryMatcher);
|
auto rx = RegexFilter<MPD::TagMTime>(constraint, Config.regex_type, TagEntryMatcher);
|
||||||
result = Tags.search(Tags.begin(), Tags.end(), rx);
|
result = Tags.search(Tags.begin(), Tags.end(), rx);
|
||||||
}
|
}
|
||||||
else if (isActiveWindow(Albums))
|
else if (isActiveWindow(Albums))
|
||||||
@@ -596,10 +681,10 @@ MPD::SongList MediaLibrary::getSelectedSongs()
|
|||||||
};
|
};
|
||||||
for (auto it = Tags.begin(); it != Tags.end(); ++it)
|
for (auto it = Tags.begin(); it != Tags.end(); ++it)
|
||||||
if (it->isSelected())
|
if (it->isSelected())
|
||||||
tag_handler(it->value());
|
tag_handler(it->value().tag());
|
||||||
// if no item is selected, add current one
|
// if no item is selected, add current one
|
||||||
if (result.empty() && !Tags.empty())
|
if (result.empty() && !Tags.empty())
|
||||||
tag_handler(Tags.current().value());
|
tag_handler(Tags.current().value().tag());
|
||||||
}
|
}
|
||||||
else if (isActiveWindow(Albums))
|
else if (isActiveWindow(Albums))
|
||||||
{
|
{
|
||||||
@@ -612,7 +697,8 @@ MPD::SongList MediaLibrary::getSelectedSongs()
|
|||||||
if (hasTwoColumns)
|
if (hasTwoColumns)
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, sc.PrimaryTag);
|
Mpd.AddSearch(Config.media_lib_primary_tag, sc.PrimaryTag);
|
||||||
else
|
else
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value());
|
Mpd.AddSearch(Config.media_lib_primary_tag,
|
||||||
|
Tags.current().value().tag());
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, sc.Album);
|
Mpd.AddSearch(MPD_TAG_ALBUM, sc.Album);
|
||||||
Mpd.AddSearch(MPD_TAG_DATE, sc.Date);
|
Mpd.AddSearch(MPD_TAG_DATE, sc.Date);
|
||||||
auto songs = Mpd.CommitSearchSongs();
|
auto songs = Mpd.CommitSearchSongs();
|
||||||
@@ -726,7 +812,10 @@ void MediaLibrary::toggleColumnsMode()
|
|||||||
if (Config.titles_visibility)
|
if (Config.titles_visibility)
|
||||||
{
|
{
|
||||||
std::string item_type = lowercase(tagTypeToString(Config.media_lib_primary_tag));
|
std::string item_type = lowercase(tagTypeToString(Config.media_lib_primary_tag));
|
||||||
Albums.setTitle("Albums (sorted by " + item_type + ")");
|
std::string and_mtime = Config.media_library_sort_by_mtime ?
|
||||||
|
" and mtime" :
|
||||||
|
"";
|
||||||
|
Albums.setTitle("Albums (sorted by " + item_type + and_mtime + ")");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Albums.setTitle("");
|
Albums.setTitle("");
|
||||||
@@ -792,11 +881,11 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
|||||||
Tags.showAll();
|
Tags.showAll();
|
||||||
if (Tags.empty())
|
if (Tags.empty())
|
||||||
update();
|
update();
|
||||||
if (primary_tag != Tags.current().value())
|
if (primary_tag != Tags.current().value().tag())
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < Tags.size(); ++i)
|
for (size_t i = 0; i < Tags.size(); ++i)
|
||||||
{
|
{
|
||||||
if (primary_tag == Tags[i].value())
|
if (primary_tag == Tags[i].value().tag())
|
||||||
{
|
{
|
||||||
Tags.highlight(i);
|
Tags.highlight(i);
|
||||||
Albums.clear();
|
Albums.clear();
|
||||||
@@ -866,7 +955,7 @@ void MediaLibrary::AddToPlaylist(bool add_n_play)
|
|||||||
|| (isActiveWindow(Albums) && Albums.current().value().Date == AllTracksMarker))
|
|| (isActiveWindow(Albums) && Albums.current().value().Date == AllTracksMarker))
|
||||||
{
|
{
|
||||||
std::string tag_type = lowercase(tagTypeToString(Config.media_lib_primary_tag));
|
std::string tag_type = lowercase(tagTypeToString(Config.media_lib_primary_tag));
|
||||||
Statusbar::msg("Songs with %s = \"%s\" added", tag_type.c_str(), Tags.current().value().c_str());
|
Statusbar::msg("Songs with %s = \"%s\" added", tag_type.c_str(), Tags.current().value().tag().c_str());
|
||||||
}
|
}
|
||||||
else if (isActiveWindow(Albums))
|
else if (isActiveWindow(Albums))
|
||||||
Statusbar::msg("Songs from album \"%s\" added", Albums.current().value().Album.c_str());
|
Statusbar::msg("Songs from album \"%s\" added", Albums.current().value().Album.c_str());
|
||||||
@@ -915,9 +1004,9 @@ std::string SongToString(const MPD::Song &s)
|
|||||||
return s.toString(Config.song_library_format, Config.tags_separator);
|
return s.toString(Config.song_library_format, Config.tags_separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TagEntryMatcher(const Regex &rx, const std::string &tag)
|
bool TagEntryMatcher(const Regex &rx, const MPD::TagMTime &tagmtime)
|
||||||
{
|
{
|
||||||
return rx.match(tag);
|
return rx.match(tagmtime.tag());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AlbumEntryMatcher(const Regex &rx, const NC::Menu<SearchConstraints>::Item &item, bool filter)
|
bool AlbumEntryMatcher(const Regex &rx, const NC::Menu<SearchConstraints>::Item &item, bool filter)
|
||||||
@@ -939,9 +1028,9 @@ void DisplayAlbums(NC::Menu<SearchConstraints> &menu)
|
|||||||
menu << AlbumToString(menu.drawn()->value());
|
menu << AlbumToString(menu.drawn()->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayPrimaryTags(NC::Menu<std::string> &menu)
|
void DisplayPrimaryTags(NC::Menu<MPD::TagMTime> &menu)
|
||||||
{
|
{
|
||||||
const std::string &tag = menu.drawn()->value();
|
const std::string &tag = menu.drawn()->value().tag();
|
||||||
if (tag.empty())
|
if (tag.empty())
|
||||||
menu << Config.empty_tag;
|
menu << Config.empty_tag;
|
||||||
else
|
else
|
||||||
@@ -952,7 +1041,7 @@ void DisplayPrimaryTags(NC::Menu<std::string> &menu)
|
|||||||
|
|
||||||
bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b)
|
bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b)
|
||||||
{
|
{
|
||||||
int cmp = a.getDisc().compare(b.getDisc());
|
int cmp = a.getDisc().compare(a.getDisc());
|
||||||
if (cmp != 0)
|
if (cmp != 0)
|
||||||
return cmp < 0;
|
return cmp < 0;
|
||||||
return a.getTrack() < b.getTrack();
|
return a.getTrack() < b.getTrack();
|
||||||
|
|||||||
@@ -74,20 +74,29 @@ struct MediaLibrary: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Sea
|
|||||||
void LocateSong(const MPD::Song &);
|
void LocateSong(const MPD::Song &);
|
||||||
ProxySongList songsProxyList();
|
ProxySongList songsProxyList();
|
||||||
|
|
||||||
|
// mtimes
|
||||||
|
bool hasMTimes();
|
||||||
|
void toggleMTimeSort();
|
||||||
|
|
||||||
struct SearchConstraints
|
struct SearchConstraints
|
||||||
{
|
{
|
||||||
SearchConstraints() { }
|
SearchConstraints() { }
|
||||||
SearchConstraints(const std::string &tag, const std::string &album, const std::string &date)
|
SearchConstraints(const std::string &tag, const std::string &album, const std::string &date) : PrimaryTag(tag), Album(album), Date(date), MTime(0) { }
|
||||||
: PrimaryTag(tag), Album(album), Date(date) { }
|
SearchConstraints(const std::string &album, const std::string &date) : Album(album), Date(date), MTime(0) { }
|
||||||
SearchConstraints(const std::string &album, const std::string &date)
|
SearchConstraints(const std::string &tag, const std::string &album, const std::string &date, time_t mtime) : PrimaryTag(tag), Album(album), Date(date), MTime(mtime) { }
|
||||||
: Album(album), Date(date) { }
|
SearchConstraints(const std::string &album, const std::string &date, time_t mtime) : Album(album), Date(date), MTime(mtime) { }
|
||||||
|
|
||||||
std::string PrimaryTag;
|
std::string PrimaryTag;
|
||||||
std::string Album;
|
std::string Album;
|
||||||
std::string Date;
|
std::string Date;
|
||||||
|
time_t MTime;
|
||||||
|
|
||||||
|
bool operator<(const SearchConstraints &a) const;
|
||||||
|
|
||||||
|
bool hasMTime() { return MTime != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
NC::Menu<std::string> Tags;
|
NC::Menu<MPD::TagMTime> Tags;
|
||||||
NC::Menu<SearchConstraints> Albums;
|
NC::Menu<SearchConstraints> Albums;
|
||||||
NC::Menu<MPD::Song> Songs;
|
NC::Menu<MPD::Song> Songs;
|
||||||
|
|
||||||
|
|||||||
103
src/mpdpp.cpp
103
src/mpdpp.cpp
@@ -21,6 +21,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "charset.h"
|
#include "charset.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
@@ -1140,6 +1141,52 @@ StringList Connection::GetList(mpd_tag_type type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TagMTimeList Connection::GetListMTime(mpd_tag_type type, bool get_mtime)
|
||||||
|
{
|
||||||
|
TagMTimeList result;
|
||||||
|
if (!itsConnection)
|
||||||
|
return result;
|
||||||
|
assert(!isCommandsListEnabled);
|
||||||
|
GoBusy();
|
||||||
|
|
||||||
|
if (!get_mtime)
|
||||||
|
{
|
||||||
|
mpd_search_db_tags(itsConnection, type);
|
||||||
|
mpd_search_commit(itsConnection);
|
||||||
|
while (mpd_pair *item = mpd_recv_pair_tag(itsConnection, type))
|
||||||
|
{
|
||||||
|
result.push_back(TagMTime(item->value));
|
||||||
|
mpd_return_pair(itsConnection, item);
|
||||||
|
}
|
||||||
|
mpd_response_finish(itsConnection);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mpd_send_list_all_meta(itsConnection, "/");
|
||||||
|
std::map<std::string, time_t> max_mtimes;
|
||||||
|
while (mpd_song *s = mpd_recv_song(itsConnection))
|
||||||
|
{
|
||||||
|
Song song(s);
|
||||||
|
const std::string &tag = song.getTag(type);
|
||||||
|
time_t mtime = song.getMTime();
|
||||||
|
auto mt = max_mtimes.find(tag);
|
||||||
|
if (mt == max_mtimes.end())
|
||||||
|
max_mtimes.insert(std::make_pair(tag, mtime));
|
||||||
|
else
|
||||||
|
mt->second = std::max(mt->second, mtime);
|
||||||
|
}
|
||||||
|
mpd_response_finish(itsConnection);
|
||||||
|
|
||||||
|
for (auto it = max_mtimes.begin(); it != max_mtimes.end(); ++it)
|
||||||
|
{
|
||||||
|
result.push_back(TagMTime(it->first, it->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GoIdle();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Connection::StartSearch(bool exact_match)
|
void Connection::StartSearch(bool exact_match)
|
||||||
{
|
{
|
||||||
if (itsConnection)
|
if (itsConnection)
|
||||||
@@ -1154,6 +1201,18 @@ void Connection::StartFieldSearch(mpd_tag_type item)
|
|||||||
mpd_search_db_tags(itsConnection, item);
|
mpd_search_db_tags(itsConnection, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void Connection::StartFieldSearchMTime(mpd_tag_type item, bool get_mtime)
|
||||||
|
{
|
||||||
|
if (itsConnection)
|
||||||
|
{
|
||||||
|
itsSearchedField = item;
|
||||||
|
itsSearchFieldMTime = get_mtime;
|
||||||
|
if (!get_mtime)
|
||||||
|
mpd_search_db_tags(itsConnection, item);
|
||||||
|
else
|
||||||
|
mpd_search_db_songs(itsConnection, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Connection::AddSearch(mpd_tag_type item, const std::string &str) const
|
void Connection::AddSearch(mpd_tag_type item, const std::string &str) const
|
||||||
{
|
{
|
||||||
@@ -1211,6 +1270,50 @@ StringList Connection::CommitSearchTags()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TagMTimeList Connection::CommitSearchTagsMTime()
|
||||||
|
{
|
||||||
|
TagMTimeList result;
|
||||||
|
if (!itsConnection)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
assert(!isCommandsListEnabled);
|
||||||
|
GoBusy();
|
||||||
|
mpd_search_commit(itsConnection);
|
||||||
|
|
||||||
|
if (!itsSearchFieldMTime)
|
||||||
|
{
|
||||||
|
while (mpd_pair *tag = mpd_recv_pair_tag(itsConnection, itsSearchedField))
|
||||||
|
{
|
||||||
|
result.push_back(TagMTime(tag->value));
|
||||||
|
mpd_return_pair(itsConnection, tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::map<std::string, time_t> max_mtimes;
|
||||||
|
while (mpd_song *s = mpd_recv_song(itsConnection))
|
||||||
|
{
|
||||||
|
Song song(s);
|
||||||
|
const std::string &tag = song.getTag(itsSearchedField);
|
||||||
|
time_t mtime = song.getMTime();
|
||||||
|
auto mt = max_mtimes.find(tag);
|
||||||
|
if (mt == max_mtimes.end())
|
||||||
|
max_mtimes.insert(std::make_pair(tag, mtime));
|
||||||
|
else
|
||||||
|
mt->second = std::max(mt->second, mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = max_mtimes.begin(); it != max_mtimes.end(); ++it)
|
||||||
|
{
|
||||||
|
result.push_back(TagMTime(it->first, it->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mpd_response_finish(itsConnection);
|
||||||
|
GoIdle();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ItemList Connection::GetDirectory(const std::string &path)
|
ItemList Connection::GetDirectory(const std::string &path)
|
||||||
{
|
{
|
||||||
ItemList result;
|
ItemList result;
|
||||||
|
|||||||
34
src/mpdpp.h
34
src/mpdpp.h
@@ -93,6 +93,35 @@ private:
|
|||||||
bool m_enabled;
|
bool m_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TagMTime
|
||||||
|
{
|
||||||
|
TagMTime(const std::string &tag_) : m_tag(tag_), m_mtime(0) { }
|
||||||
|
TagMTime(const std::string &tag_, time_t mtime_) : m_tag(tag_), m_mtime(mtime_) { }
|
||||||
|
|
||||||
|
const std::string &tag() const { return m_tag; }
|
||||||
|
time_t mtime() const { return m_mtime; }
|
||||||
|
|
||||||
|
void set_mtime(time_t mtime_)
|
||||||
|
{
|
||||||
|
m_mtime = mtime_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_tag(std::string tag_)
|
||||||
|
{
|
||||||
|
m_tag = tag_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasMTime()
|
||||||
|
{
|
||||||
|
return (m_mtime != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_tag;
|
||||||
|
time_t m_mtime;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<TagMTime> TagMTimeList;
|
||||||
typedef std::vector<Item> ItemList;
|
typedef std::vector<Item> ItemList;
|
||||||
typedef std::vector<std::string> StringList;
|
typedef std::vector<std::string> StringList;
|
||||||
typedef std::vector<Output> OutputList;
|
typedef std::vector<Output> OutputList;
|
||||||
@@ -213,14 +242,17 @@ public:
|
|||||||
|
|
||||||
void StartSearch(bool);
|
void StartSearch(bool);
|
||||||
void StartFieldSearch(mpd_tag_type);
|
void StartFieldSearch(mpd_tag_type);
|
||||||
|
void StartFieldSearchMTime(mpd_tag_type, bool);
|
||||||
void AddSearch(mpd_tag_type, const std::string &) const;
|
void AddSearch(mpd_tag_type, const std::string &) const;
|
||||||
void AddSearchAny(const std::string &str) const;
|
void AddSearchAny(const std::string &str) const;
|
||||||
void AddSearchURI(const std::string &str) const;
|
void AddSearchURI(const std::string &str) const;
|
||||||
SongList CommitSearchSongs();
|
SongList CommitSearchSongs();
|
||||||
StringList CommitSearchTags();
|
StringList CommitSearchTags();
|
||||||
|
TagMTimeList CommitSearchTagsMTime();
|
||||||
|
|
||||||
StringList GetPlaylists();
|
StringList GetPlaylists();
|
||||||
StringList GetList(mpd_tag_type);
|
StringList GetList(mpd_tag_type);
|
||||||
|
TagMTimeList GetListMTime(mpd_tag_type, bool);
|
||||||
ItemList GetDirectory(const std::string &);
|
ItemList GetDirectory(const std::string &);
|
||||||
SongList GetDirectoryRecursive(const std::string &);
|
SongList GetDirectoryRecursive(const std::string &);
|
||||||
SongList GetSongs(const std::string &);
|
SongList GetSongs(const std::string &);
|
||||||
@@ -272,6 +304,7 @@ private:
|
|||||||
void *itsErrorHandlerUserdata;
|
void *itsErrorHandlerUserdata;
|
||||||
|
|
||||||
mpd_tag_type itsSearchedField;
|
mpd_tag_type itsSearchedField;
|
||||||
|
bool itsSearchFieldMTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -279,4 +312,3 @@ private:
|
|||||||
extern MPD::Connection Mpd;
|
extern MPD::Connection Mpd;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void replaceTag(mpd_tag_type tag_type, std::string &&orig_value,
|
void replaceTag(mpd_tag_type tag_type, std::string &&orig_value,
|
||||||
const std::string &value, unsigned idx);
|
const std::string &value, unsigned idx);
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
std::string getTag(mpd_tag_type tag_type, F orig_value, unsigned idx) const {
|
std::string getTag(mpd_tag_type tag_type, F orig_value, unsigned idx) const {
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ void Configuration::SetDefaults()
|
|||||||
new_design = false;
|
new_design = false;
|
||||||
visualizer_use_wave = true;
|
visualizer_use_wave = true;
|
||||||
visualizer_in_stereo = false;
|
visualizer_in_stereo = false;
|
||||||
|
media_library_sort_by_mtime = false;
|
||||||
tag_editor_extended_numeration = false;
|
tag_editor_extended_numeration = false;
|
||||||
media_library_display_date = true;
|
media_library_display_date = true;
|
||||||
media_library_display_empty_tag = true;
|
media_library_display_empty_tag = true;
|
||||||
@@ -953,6 +954,10 @@ void Configuration::Read()
|
|||||||
if (!v.empty())
|
if (!v.empty())
|
||||||
media_lib_primary_tag = charToTagType(v[0]);
|
media_lib_primary_tag = charToTagType(v[0]);
|
||||||
}
|
}
|
||||||
|
else if (name == "media_library_sort_by_mtime")
|
||||||
|
{
|
||||||
|
media_library_sort_by_mtime = v == "yes";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
std::cout << "Unknown option: " << name << ", ignoring.\n";
|
std::cout << "Unknown option: " << name << ", ignoring.\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ struct Configuration
|
|||||||
bool new_design;
|
bool new_design;
|
||||||
bool visualizer_use_wave;
|
bool visualizer_use_wave;
|
||||||
bool visualizer_in_stereo;
|
bool visualizer_in_stereo;
|
||||||
|
bool media_library_sort_by_mtime;
|
||||||
bool tag_editor_extended_numeration;
|
bool tag_editor_extended_numeration;
|
||||||
bool media_library_display_date;
|
bool media_library_display_date;
|
||||||
bool media_library_display_empty_tag;
|
bool media_library_display_empty_tag;
|
||||||
|
|||||||
@@ -82,8 +82,9 @@ struct Song
|
|||||||
|
|
||||||
static const char FormatEscapeCharacter = 1;
|
static const char FormatEscapeCharacter = 1;
|
||||||
|
|
||||||
|
const char *getTag(mpd_tag_type type, unsigned idx = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *getTag(mpd_tag_type type, unsigned idx) const;
|
|
||||||
std::string ParseFormat(std::string::const_iterator &it, const std::string &tags_separator,
|
std::string ParseFormat(std::string::const_iterator &it, const std::string &tags_separator,
|
||||||
const std::string &escape_chars) const;
|
const std::string &escape_chars) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user