1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
27 #include "media_library.h"
33 using namespace Global
;
35 MediaLibrary
*myLibrary
= new MediaLibrary
;
37 bool MediaLibrary::hasTwoColumns
;
38 size_t MediaLibrary::itsLeftColWidth
;
39 size_t MediaLibrary::itsMiddleColWidth
;
40 size_t MediaLibrary::itsMiddleColStartX
;
41 size_t MediaLibrary::itsRightColWidth
;
42 size_t MediaLibrary::itsRightColStartX
;
44 void MediaLibrary::Init()
47 itsLeftColWidth
= COLS
/3-1;
48 itsMiddleColWidth
= COLS
/3;
49 itsMiddleColStartX
= itsLeftColWidth
+1;
50 itsRightColWidth
= COLS
-COLS
/3*2-1;
51 itsRightColStartX
= itsLeftColWidth
+itsMiddleColWidth
+2;
53 Artists
= new Menu
<std::string
>(0, MainStartY
, itsLeftColWidth
, MainHeight
, IntoStr(Config
.media_lib_primary_tag
) + "s", Config
.main_color
, brNone
);
54 Artists
->HighlightColor(Config
.active_column_color
);
55 Artists
->CyclicScrolling(Config
.use_cyclic_scrolling
);
56 Artists
->SetItemDisplayer(Display::Generic
);
58 Albums
= new Menu
< std::pair
<std::string
, SearchConstraints
> >(itsMiddleColStartX
, MainStartY
, itsMiddleColWidth
, MainHeight
, "Albums", Config
.main_color
, brNone
);
59 Albums
->HighlightColor(Config
.main_highlight_color
);
60 Albums
->CyclicScrolling(Config
.use_cyclic_scrolling
);
61 Albums
->SetItemDisplayer(Display::Pairs
);
62 Albums
->SetGetStringFunction(StringPairToString
);
64 Songs
= new Menu
<Song
>(itsRightColStartX
, MainStartY
, itsRightColWidth
, MainHeight
, "Songs", Config
.main_color
, brNone
);
65 Songs
->HighlightColor(Config
.main_highlight_color
);
66 Songs
->CyclicScrolling(Config
.use_cyclic_scrolling
);
67 Songs
->SetSelectPrefix(&Config
.selected_item_prefix
);
68 Songs
->SetSelectSuffix(&Config
.selected_item_suffix
);
69 Songs
->SetItemDisplayer(Display::Songs
);
70 Songs
->SetItemDisplayerUserData(&Config
.song_library_format
);
71 Songs
->SetGetStringFunction(SongToString
);
77 void MediaLibrary::Resize()
81 itsLeftColWidth
= COLS
/3-1;
82 itsMiddleColStartX
= itsLeftColWidth
+1;
83 itsMiddleColWidth
= COLS
/3;
84 itsRightColStartX
= itsLeftColWidth
+itsMiddleColWidth
+2;
85 itsRightColWidth
= COLS
-COLS
/3*2-1;
89 itsMiddleColStartX
= 0;
90 itsMiddleColWidth
= COLS
/2;
91 itsRightColStartX
= itsMiddleColWidth
+1;
92 itsRightColWidth
= COLS
-itsMiddleColWidth
-1;
95 Artists
->Resize(itsLeftColWidth
, MainHeight
);
96 Albums
->Resize(itsMiddleColWidth
, MainHeight
);
97 Songs
->Resize(itsRightColWidth
, MainHeight
);
99 Artists
->MoveTo(0, MainStartY
);
100 Albums
->MoveTo(itsMiddleColStartX
, MainStartY
);
101 Songs
->MoveTo(itsRightColStartX
, MainStartY
);
106 void MediaLibrary::Refresh()
109 mvvline(MainStartY
, itsMiddleColStartX
-1, 0, MainHeight
);
111 mvvline(MainStartY
, itsRightColStartX
-1, 0, MainHeight
);
115 *Albums
<< XY(0, 0) << "No albums found.";
116 Albums
->Window::Refresh();
120 void MediaLibrary::SwitchTo()
122 if (myScreen
== this)
124 hasTwoColumns
= !hasTwoColumns
;
134 std::string item_type
= IntoStr(Config
.media_lib_primary_tag
);
136 Albums
->SetTitle("Albums (sorted by " + item_type
+ ")");
139 Albums
->SetTitle("Albums");
151 UpdateSongList(Songs
);
154 std::basic_string
<my_char_t
> MediaLibrary::Title()
156 return U("Media library");
159 void MediaLibrary::Update()
161 if (!hasTwoColumns
&& Artists
->Empty())
166 Mpd
.GetList(list
, Config
.media_lib_primary_tag
);
167 sort(list
.begin(), list
.end(), CaseInsensitiveSorting());
168 for (TagList::iterator it
= list
.begin(); it
!= list
.end(); ++it
)
173 Artists
->AddOption(*it
);
176 Artists
->Window::Clear();
180 if (!hasTwoColumns
&& !Artists
->Empty() && Albums
->Empty() && Songs
->Empty())
184 locale_to_utf(Artists
->Current());
185 if (Config
.media_lib_primary_tag
== MPD_TAG_ARTIST
)
186 Mpd
.GetAlbums(Artists
->Current(), list
);
189 Mpd
.StartFieldSearch(MPD_TAG_ALBUM
);
190 Mpd
.AddSearch(Config
.media_lib_primary_tag
, Artists
->Current());
191 Mpd
.CommitSearch(list
);
194 // <mpd-0.14 doesn't support searching for empty tag
195 if (Mpd
.Version() > 13)
197 SongList noalbum_list
;
199 Mpd
.AddSearch(Config
.media_lib_primary_tag
, Artists
->Current());
200 Mpd
.AddSearch(MPD_TAG_ALBUM
, "");
201 Mpd
.CommitSearch(noalbum_list
);
202 if (!noalbum_list
.empty())
203 Albums
->AddOption(std::make_pair("<no album>", SearchConstraints("", "")));
204 FreeSongList(noalbum_list
);
207 for (TagList::const_iterator it
= list
.begin(); it
!= list
.end(); ++it
)
210 Mpd
.StartFieldSearch(MPD_TAG_DATE
);
211 Mpd
.AddSearch(Config
.media_lib_primary_tag
, Artists
->Current());
212 Mpd
.AddSearch(MPD_TAG_ALBUM
, *it
);
216 Albums
->AddOption(std::make_pair(*it
, SearchConstraints(*it
, "")));
219 for (TagList::const_iterator j
= l
.begin(); j
!= l
.end(); ++j
)
220 Albums
->AddOption(std::make_pair("(" + *j
+ ") " + *it
, SearchConstraints(*it
, *j
)));
222 utf_to_locale(Artists
->Current());
223 for (size_t i
= 0; i
< Albums
->Size(); ++i
)
224 utf_to_locale((*Albums
)[i
].first
);
225 if (!Albums
->Empty())
226 Albums
->Sort
<CaseInsensitiveSorting
>((*Albums
)[0].first
== "<no album>");
229 else if (hasTwoColumns
&& Albums
->Empty() && Songs
->Empty())
232 *Albums
<< XY(0, 0) << "Fetching albums...";
233 Albums
->Window::Refresh();
234 Mpd
.GetList(artists
, Config
.media_lib_primary_tag
);
235 for (TagList::const_iterator i
= artists
.begin(); i
!= artists
.end(); ++i
)
238 Mpd
.StartFieldSearch(MPD_TAG_ALBUM
);
239 Mpd
.AddSearch(Config
.media_lib_primary_tag
, *i
);
240 Mpd
.CommitSearch(albums
);
241 for (TagList::const_iterator j
= albums
.begin(); j
!= albums
.end(); ++j
)
243 if (Config
.media_lib_primary_tag
!= MPD_TAG_DATE
)
246 Mpd
.StartFieldSearch(MPD_TAG_DATE
);
247 Mpd
.AddSearch(Config
.media_lib_primary_tag
, *i
);
248 Mpd
.AddSearch(MPD_TAG_ALBUM
, *j
);
249 Mpd
.CommitSearch(years
);
252 for (TagList::const_iterator k
= years
.begin(); k
!= years
.end(); ++k
)
254 Albums
->AddOption(std::make_pair(*i
+ " - (" + *k
+ ") " + *j
, SearchConstraints(*i
, *j
, *k
)));
258 Albums
->AddOption(std::make_pair(*i
+ " - " + *j
, SearchConstraints(*i
, *j
, "")));
261 Albums
->AddOption(std::make_pair(*i
+ " - " + *j
, SearchConstraints(*i
, *j
, *i
)));
264 for (size_t i
= 0; i
< Albums
->Size(); ++i
)
265 utf_to_locale((*Albums
)[i
].first
);
266 if (!Albums
->Empty())
267 Albums
->Sort
<CaseInsensitiveSorting
>();
271 if (!hasTwoColumns
&& !Artists
->Empty() && w
== Albums
&& Albums
->Empty())
273 Albums
->HighlightColor(Config
.main_highlight_color
);
274 Artists
->HighlightColor(Config
.active_column_color
);
278 if ((hasTwoColumns
|| !Artists
->Empty()) && Songs
->Empty())
285 Mpd
.AddSearch(Config
.media_lib_primary_tag
, hasTwoColumns
? Albums
->Current().second
.Artist
: locale_to_utf_cpy(Artists
->Current()));
286 if (Albums
->Empty()) // left for compatibility with <mpd-0.14
288 *Albums
<< XY(0, 0) << "No albums found.";
289 Albums
->Window::Refresh();
293 Mpd
.AddSearch(MPD_TAG_ALBUM
, Albums
->Current().second
.Album
);
294 if (!Albums
->Current().second
.Album
.empty()) // for <no album>
295 Mpd
.AddSearch(MPD_TAG_DATE
, Albums
->Current().second
.Year
);
297 Mpd
.CommitSearch(list
);
299 sort(list
.begin(), list
.end(), SortSongsByTrack
);
302 for (SongList::const_iterator it
= list
.begin(); it
!= list
.end(); ++it
)
304 for (size_t j
= 0; j
< myPlaylist
->Items
->Size(); ++j
)
306 if ((*it
)->GetHash() == myPlaylist
->Items
->at(j
).GetHash())
312 Songs
->AddOption(**it
, bold
);
316 Songs
->Window::Clear();
321 void MediaLibrary::SpacePressed()
323 if (Config
.space_selects
&& w
== Songs
)
325 Songs
->Select(Songs
->Choice(), !Songs
->isSelected());
332 void MediaLibrary::MouseButtonPressed(MEVENT me
)
334 if (!Artists
->Empty() && Artists
->hasCoords(me
.x
, me
.y
))
341 if (size_t(me
.y
) < Artists
->Size() && (me
.bstate
& (BUTTON1_PRESSED
| BUTTON3_PRESSED
)))
344 if (me
.bstate
& BUTTON3_PRESSED
)
346 size_t pos
= Artists
->Choice();
348 if (pos
< Artists
->Size()-1)
349 Artists
->Scroll(wUp
);
353 Screen
<Window
>::MouseButtonPressed(me
);
357 else if (!Albums
->Empty() && Albums
->hasCoords(me
.x
, me
.y
))
360 w
== Artists
? NextColumn() : PrevColumn();
361 if (size_t(me
.y
) < Albums
->Size() && (me
.bstate
& (BUTTON1_PRESSED
| BUTTON3_PRESSED
)))
364 if (me
.bstate
& BUTTON3_PRESSED
)
366 size_t pos
= Albums
->Choice();
368 if (pos
< Albums
->Size()-1)
373 Screen
<Window
>::MouseButtonPressed(me
);
376 else if (!Songs
->Empty() && Songs
->hasCoords(me
.x
, me
.y
))
383 if (size_t(me
.y
) < Songs
->Size() && (me
.bstate
& (BUTTON1_PRESSED
| BUTTON3_PRESSED
)))
386 if (me
.bstate
& BUTTON1_PRESSED
)
388 size_t pos
= Songs
->Choice();
390 if (pos
< Songs
->Size()-1)
397 Screen
<Window
>::MouseButtonPressed(me
);
401 MPD::Song
*MediaLibrary::CurrentSong()
403 return w
== Songs
&& !Songs
->Empty() ? &Songs
->Current() : 0;
406 List
*MediaLibrary::GetList()
410 else if (w
== Albums
)
414 else // silence compiler
418 void MediaLibrary::GetSelectedSongs(MPD::SongList
&v
)
420 std::vector
<size_t> selected
;
421 Songs
->GetSelected(selected
);
422 for (std::vector
<size_t>::const_iterator it
= selected
.begin(); it
!= selected
.end(); ++it
)
424 v
.push_back(new MPD::Song(Songs
->at(*it
)));
428 void MediaLibrary::ApplyFilter(const std::string
&s
)
430 GetList()->ApplyFilter(s
, 0, REG_ICASE
| Config
.regex_type
);
433 void MediaLibrary::NextColumn()
437 if (!hasTwoColumns
&& Songs
->Empty())
439 Artists
->HighlightColor(Config
.main_highlight_color
);
442 Albums
->HighlightColor(Config
.active_column_color
);
443 if (!Albums
->Empty())
446 if (w
== Albums
&& !Songs
->Empty())
448 Albums
->HighlightColor(Config
.main_highlight_color
);
451 Songs
->HighlightColor(Config
.active_column_color
);
455 void MediaLibrary::PrevColumn()
459 Songs
->HighlightColor(Config
.main_highlight_color
);
462 Albums
->HighlightColor(Config
.active_column_color
);
463 if (!Albums
->Empty())
466 if (w
== Albums
&& !hasTwoColumns
)
468 Albums
->HighlightColor(Config
.main_highlight_color
);
471 Artists
->HighlightColor(Config
.active_column_color
);
475 void MediaLibrary::AddToPlaylist(bool add_n_play
)
479 if (!Artists
->Empty() && w
== Artists
)
482 Mpd
.AddSearch(Config
.media_lib_primary_tag
, locale_to_utf_cpy(Artists
->Current()));
483 Mpd
.CommitSearch(list
);
485 if (myPlaylist
->Add(list
, add_n_play
))
487 std::string tag_type
= IntoStr(Config
.media_lib_primary_tag
);
489 ShowMessage("Adding songs of %s \"%s\"", tag_type
.c_str(), Artists
->Current().c_str());
492 else if (w
== Albums
)
495 l
.reserve(Songs
->Size());
496 for (size_t i
= 0; i
< Songs
->Size(); ++i
)
497 l
.push_back(&(*Songs
)[i
]);
499 if (myPlaylist
->Add(l
, add_n_play
))
500 ShowMessage("Adding songs from album \"%s\"", Albums
->Current().second
.Album
.c_str());
502 else if (w
== Songs
&& !Songs
->Empty())
503 Songs
->Bold(Songs
->Choice(), myPlaylist
->Add(Songs
->Current(), Songs
->isBold(), add_n_play
));
513 else if (w
== Albums
)
518 std::string
MediaLibrary::SongToString(const MPD::Song
&s
, void *)
520 return s
.toString(Config
.song_library_format
);
523 bool MediaLibrary::SortSongsByYear(Song
*a
, Song
*b
)
525 return a
->GetDate() < b
->GetDate();
528 bool MediaLibrary::SortSongsByTrack(Song
*a
, Song
*b
)
530 if (a
->GetDisc() == b
->GetDisc())
531 return StrToInt(a
->GetTrack()) < StrToInt(b
->GetTrack());
533 return StrToInt(a
->GetDisc()) < StrToInt(b
->GetDisc());