separate some code from ncmpcpp.cpp

This commit is contained in:
Andrzej Rybczak
2009-02-13 17:24:06 +01:00
parent 29301aefd5
commit 8ba72bc78a
29 changed files with 2956 additions and 2168 deletions

View File

@@ -1,8 +1,8 @@
bin_PROGRAMS = ncmpcpp
ncmpcpp_SOURCES = browser.cpp charset.cpp clock.cpp display.cpp help.cpp \
helpers.cpp libmpdclient.c lyrics.cpp misc.cpp mpdpp.cpp ncmpcpp.cpp scrollpad.cpp \
search_engine.cpp settings.cpp song.cpp status_checker.cpp str_pool.c tag_editor.cpp \
window.cpp
helpers.cpp info.cpp libmpdclient.c lyrics.cpp media_library.cpp misc.cpp mpdpp.cpp \
ncmpcpp.cpp playlist.cpp playlist_editor.cpp scrollpad.cpp search_engine.cpp \
settings.cpp song.cpp status_checker.cpp str_pool.c tag_editor.cpp window.cpp
# set the include path found by configure
INCLUDES= $(all_includes)
@@ -10,5 +10,6 @@ INCLUDES= $(all_includes)
# the library search path.
ncmpcpp_LDFLAGS = $(all_libraries)
noinst_HEADERS = browser.h charset.h clock.h display.h global.h help.h \
helpers.h lyrics.h menu.h mpdpp.h scrollpad.h search_engine.h settings.h song.h \
status_checker.h tag_editor.h window.h
helpers.h info.h lyrics.h media_library.h menu.h mpdpp.h playlist_editor.h \
scrollpad.h search_engine.h settings.h song.h status_checker.h tag_editor.h \
window.h

View File

@@ -28,6 +28,7 @@
#include "global.h"
#include "helpers.h"
#include "settings.h"
#include "status_checker.h"
#ifdef HAVE_TAGLIB_H
# include "tag_editor.h"
#endif // HAVE_TAGLIB_H
@@ -36,6 +37,190 @@ using namespace Global;
using namespace MPD;
using std::string;
Menu<Item> *Global::mBrowser;
void Browser::Init()
{
mBrowser = new Menu<Item>(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
mBrowser->HighlightColor(Config.main_highlight_color);
mBrowser->SetTimeout(ncmpcpp_window_timeout);
mBrowser->SetSelectPrefix(&Config.selected_item_prefix);
mBrowser->SetSelectSuffix(&Config.selected_item_suffix);
mBrowser->SetItemDisplayer(Display::Items);
}
void Browser::Resize()
{
mBrowser->Resize(COLS, main_height);
}
void Browser::SwitchTo()
{
if (current_screen != csBrowser
# ifdef HAVE_TAGLIB_H
&& current_screen != csTinyTagEditor
# endif // HAVE_TAGLIB_H
)
{
CLEAR_FIND_HISTORY;
mBrowser->Empty() ? GetDirectory(browsed_dir) : UpdateItemList(mBrowser);
wCurrent = mBrowser;
wCurrent->Hide();
current_screen = csBrowser;
// redraw_screen = 1;
redraw_header = 1;
}
}
void Browser::EnterPressed()
{
if (mBrowser->Empty())
return;
const Item &item = mBrowser->Current();
switch (item.type)
{
case itDirectory:
{
CLEAR_FIND_HISTORY;
GetDirectory(item.name, browsed_dir);
redraw_header = 1;
break;
}
case itSong:
{
block_item_list_update = 1;
if (Config.ncmpc_like_songs_adding && mBrowser->isBold())
{
bool found = 0;
long long hash = mBrowser->Current().song->GetHash();
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->Play(i);
found = 1;
break;
}
}
if (found)
break;
}
Song &s = *item.song;
int id = Mpd->AddSong(s);
if (id >= 0)
{
Mpd->PlayID(id);
ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str());
mBrowser->BoldOption(mBrowser->Choice(), 1);
}
break;
}
case itPlaylist:
{
SongList list;
Mpd->GetPlaylistContent(locale_to_utf_cpy(item.name), list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Loading and playing playlist %s...", item.name.c_str());
Song *s = &mPlaylist->at(mPlaylist->Size()-list.size());
if (s->GetHash() == list[0]->GetHash())
Mpd->PlayID(s->GetID());
else
ShowMessage("%s", message_part_of_songs_added);
}
FreeSongList(list);
break;
}
}
}
void Browser::SpacePressed()
{
if (mBrowser->Empty())
return;
const Item &item = mBrowser->Current();
switch (item.type)
{
case itDirectory:
{
if (browsed_dir != "/" && !mBrowser->Choice())
break; // do not let add parent dir.
if (Config.local_browser)
{
ShowMessage("Adding whole directories from local browser is not supported!");
break;
}
SongList list;
Mpd->GetDirectoryRecursive(locale_to_utf_cpy(item.name), list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Added folder: %s", item.name.c_str());
Song &s = mPlaylist->at(mPlaylist->Size()-list.size());
if (s.GetHash() != list[0]->GetHash())
ShowMessage("%s", message_part_of_songs_added);
}
FreeSongList(list);
break;
}
case itSong:
{
block_item_list_update = 1;
if (Config.ncmpc_like_songs_adding && mBrowser->isBold())
{
block_playlist_update = 1;
long long hash = mBrowser->Current().song->GetHash();
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->QueueDeleteSong(i);
mPlaylist->DeleteOption(i);
i--;
}
}
Mpd->CommitQueue();
mBrowser->BoldOption(mBrowser->Choice(), 0);
}
else
{
Song &s = *item.song;
if (Mpd->AddSong(s) != -1)
{
ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str());
mBrowser->BoldOption(mBrowser->Choice(), 1);
}
}
break;
}
case itPlaylist:
{
SongList list;
Mpd->GetPlaylistContent(locale_to_utf_cpy(item.name), list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Loading playlist %s...", item.name.c_str());
Song &s = mPlaylist->at(mPlaylist->Size()-list.size());
if (s.GetHash() != list[0]->GetHash())
ShowMessage("%s", message_part_of_songs_added);
}
FreeSongList(list);
break;
}
}
mBrowser->Scroll(wDown);
}
namespace
{
const char *supported_extensions[] = { "wma", "asf", "rm", "mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav", "au", "aiff", "aif", "ac3", "aac", "mpc", "it", "mod", "s3m", "xm", "wv", 0 };

View File

@@ -24,6 +24,16 @@
#include "mpdpp.h"
#include "ncmpcpp.h"
namespace Browser
{
void Init();
void Resize();
void SwitchTo();
void EnterPressed();
void SpacePressed();
}
void UpdateItemList(Menu<MPD::Item> *);
void GetDirectory(std::string, std::string = "/");

View File

@@ -21,12 +21,17 @@
/// NOTICE: Major part of this code is ported from ncmpc's clock screen
#include "clock.h"
#include "display.h"
#include "global.h"
#ifdef ENABLE_CLOCK
#include "display.h"
#include "global.h"
#include "settings.h"
#include "status_checker.h"
using namespace Global;
Scrollpad *Global::wClock;
namespace
{
@@ -52,14 +57,47 @@ namespace
}
}
void InitClock()
namespace Clock
{
const size_t width = Config.clock_display_seconds ? 60 : 40;
const size_t height = 8;
}
void Clock::Init()
{
wClock = new Scrollpad((COLS-width)/2, (LINES-height)/2, width, height-1, "", Config.main_color, Border(Config.main_color));
wClock->SetTimeout(ncmpcpp_window_timeout);
}
void Clock::Resize()
{
if (width <= size_t(COLS) && height <= main_height)
{
wClock->MoveTo((COLS-width)/2, (LINES-height)/2);
if (current_screen == csClock)
{
mPlaylist->Hide();
Prepare();
wClock->Display();
}
}
}
void Clock::Prepare()
{
for (int i = 0; i < 5; i++)
older[i] = newer[i] = next[i] = 0;
}
void Display::Clock(Window &w, const tm *time)
void Clock::Update()
{
if (width > size_t(COLS) || height > main_height)
return;
time_t rawtime;
time(&rawtime);
tm *time = localtime(&rawtime);
mask = 0;
set(time->tm_sec % 10, 0);
set(time->tm_sec / 10, 4);
@@ -72,9 +110,9 @@ void Display::Clock(Window &w, const tm *time)
char buf[54];
strftime(buf, 64, "%x", time);
attron(COLOR_PAIR(Global::Config.main_color));
mvprintw(w.GetStartY()+w.GetHeight(), w.GetStartX()+(w.GetWidth()-strlen(buf))/2, "%s", buf);
attroff(COLOR_PAIR(Global::Config.main_color));
attron(COLOR_PAIR(Config.main_color));
mvprintw(wCurrent->GetStartY()+wCurrent->GetHeight(), wCurrent->GetStartX()+(wCurrent->GetWidth()-strlen(buf))/2, "%s", buf);
attroff(COLOR_PAIR(Config.main_color));
refresh();
for (int k = 0; k < 6; k++)
@@ -83,7 +121,7 @@ void Display::Clock(Window &w, const tm *time)
next[k] = 0;
for (int s = 1; s >= 0; s--)
{
w.Reverse(s);
wCurrent->Reverse(s);
for (int i = 0; i < 6; i++)
{
long a = (newer[i] ^ older[i]) & (s ? newer : older)[i];
@@ -96,10 +134,10 @@ void Display::Clock(Window &w, const tm *time)
{
if (!(a & (t << 1)))
{
w.GotoXY(2*j+2, i);
wCurrent->GotoXY(2*j+2, i);
}
if (Global::Config.clock_display_seconds || j < 18)
w << " ";
*wCurrent << " ";
}
}
}
@@ -108,13 +146,32 @@ void Display::Clock(Window &w, const tm *time)
older[i] = newer[i];
}
}
if (!s)
{
w.Refresh();
}
}
}
}
void Clock::SwitchTo()
{
if (width > size_t(COLS) || height > main_height)
{
ShowMessage("Screen is too small to display clock!");
}
else if (
current_screen != csClock
# ifdef HAVE_TAGLIB_H
&& current_screen != csTinyTagEditor
# endif // HAVE_TAGLIB_H
)
{
CLEAR_FIND_HISTORY;
wCurrent = wClock;
mPlaylist->Hide();
current_screen = csClock;
redraw_header = 1;
Clock::Prepare();
wCurrent->Display();
}
}
#endif // ENABLE_CLOCK

View File

@@ -27,11 +27,19 @@
#ifdef ENABLE_CLOCK
#include <ctime>
#include "window.h"
void InitClock();
namespace Clock
{
void Init();
void Resize();
void SwitchTo();
void Update();
void Prepare();
}
#include <ctime>
#endif // ENABLE_CLOCK

View File

@@ -51,5 +51,16 @@ namespace Display
void Clock(Window &, const tm *);
}
namespace Refresh
{
void MediaLibrary();
void PlaylistEditor();
# ifdef HAVE_TAGLIB_H
void TagEditor();
# endif
}
#endif

View File

@@ -49,11 +49,10 @@ namespace Global
extern Menu<Buffer> *mTagEditor;
extern Menu<string_pair> *mEditorAlbums;
extern Menu<string_pair> *mEditorDirs;
# endif // HAVE_TAGLIB_H
// blah, I use below in conditionals.
extern Menu<string_pair> *mEditorLeftCol;
extern Menu<std::string> *mEditorTagTypes;
extern Menu<MPD::Song> *mEditorTags;
# endif // HAVE_TAGLIB_H
extern Window *wPlaylistEditorActiveCol;
extern Menu<std::string> *mPlaylistList;
@@ -75,21 +74,22 @@ namespace Global
extern int lock_statusbar_delay;
extern size_t browsed_dir_scroll_begin;
extern size_t main_start_y;
extern size_t main_height;
extern size_t lyrics_scroll_begin;
extern time_t timer;
extern std::string browsed_dir;
extern std::string editor_browsed_dir;
extern std::string editor_highlighted_dir;
extern std::string info_title;
extern NcmpcppScreen current_screen;
extern NcmpcppScreen prev_screen;
# ifdef HAVE_CURL_CURL_H
extern pthread_t lyrics_downloader;
extern pthread_t artist_info_downloader;
extern bool lyrics_ready;
extern bool artist_info_ready;
extern pthread_mutex_t curl;
# endif
extern bool dont_change_now_playing;
@@ -113,6 +113,11 @@ namespace Global
extern const char *search_mode_normal;
extern const char *search_mode_strict;
extern std::vector<int> vFoundPositions;
extern int found_pos;
extern MPD::Song lyrics_song;
}
#endif

View File

@@ -24,71 +24,104 @@
#include "help.h"
#include "settings.h"
using Global::Key;
using Global::Mpd;
using namespace Global;
using std::string;
Scrollpad *Global::sHelp;
namespace
{
string DisplayKeys(int *key, int size = 2)
void GetKeybindings(Scrollpad &help);
}
void Help::Init()
{
sHelp = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
sHelp->SetTimeout(ncmpcpp_window_timeout);
GetKeybindings(*sHelp);
sHelp->Flush();
}
void Help::Resize()
{
sHelp->Resize(COLS, main_height);
}
void Help::SwitchTo()
{
if (current_screen != csHelp
# ifdef HAVE_TAGLIB_H
&& current_screen != csTinyTagEditor
# endif // HAVE_TAGLIB_H
)
{
bool backspace = 1;
string result = "\t";
for (int i = 0; i < size; i++)
{
if (key[i] == null_key);
else if (key[i] == 259)
result += "Up";
else if (key[i] == 258)
result += "Down";
else if (key[i] == 339)
result += "Page Up";
else if (key[i] == 338)
result += "Page Down";
else if (key[i] == 262)
result += "Home";
else if (key[i] == 360)
result += "End";
else if (key[i] == 32)
result += "Space";
else if (key[i] == 10)
result += "Enter";
else if (key[i] == 330)
result += "Delete";
else if (key[i] == 261)
result += "Right";
else if (key[i] == 260)
result += "Left";
else if (key[i] == 9)
result += "Tab";
else if (key[i] >= 1 && key[i] <= 26)
{
result += "Ctrl-";
result += key[i]+64;
}
else if (key[i] >= 265 && key[i] <= 276)
{
result += "F";
result += IntoStr(key[i]-264);
}
else if ((key[i] == 263 || key[i] == 127) && !backspace);
else if ((key[i] == 263 || key[i] == 127) && backspace)
{
result += "Backspace";
backspace = 0;
}
else
result += key[i];
result += " ";
}
if (result.length() > 12)
result = result.substr(0, 12);
for (size_t i = result.length(); i <= 12; result += " ", i++) { }
result += ": ";
return result;
wCurrent = sHelp;
wCurrent->Hide();
current_screen = csHelp;
redraw_header = 1;
}
}
namespace {
string DisplayKeys(int *key, int size = 2)
{
bool backspace = 1;
string result = "\t";
for (int i = 0; i < size; i++)
{
if (key[i] == null_key);
else if (key[i] == 259)
result += "Up";
else if (key[i] == 258)
result += "Down";
else if (key[i] == 339)
result += "Page Up";
else if (key[i] == 338)
result += "Page Down";
else if (key[i] == 262)
result += "Home";
else if (key[i] == 360)
result += "End";
else if (key[i] == 32)
result += "Space";
else if (key[i] == 10)
result += "Enter";
else if (key[i] == 330)
result += "Delete";
else if (key[i] == 261)
result += "Right";
else if (key[i] == 260)
result += "Left";
else if (key[i] == 9)
result += "Tab";
else if (key[i] >= 1 && key[i] <= 26)
{
result += "Ctrl-";
result += key[i]+64;
}
else if (key[i] >= 265 && key[i] <= 276)
{
result += "F";
result += IntoStr(key[i]-264);
}
else if ((key[i] == 263 || key[i] == 127) && !backspace);
else if ((key[i] == 263 || key[i] == 127) && backspace)
{
result += "Backspace";
backspace = 0;
}
else
result += key[i];
result += " ";
}
if (result.length() > 12)
result = result.substr(0, 12);
for (size_t i = result.length(); i <= 12; result += " ", i++) { }
result += ": ";
return result;
}
void GetKeybindings(Scrollpad &help)
{
help << " " << fmtBold << "Keys - Movement\n -----------------------------------------\n" << fmtBoldEnd;
@@ -193,7 +226,7 @@ void GetKeybindings(Scrollpad &help)
help << DisplayKeys(Key.Space) << "Add to playlist song/album/artist's songs\n";
help << DisplayKeys(Key.SwitchTagTypeList) << "Tag type list switcher (left column)\n\n\n";
help << " " << fmtBold << "Keys - Playlist Editorz\n -----------------------------------------\n" << fmtBoldEnd;
help << " " << fmtBold << "Keys - Playlist Editor\n -----------------------------------------\n" << fmtBoldEnd;
help << DisplayKeys(&Key.VolumeDown[0], 1) << "Previous column\n";
help << DisplayKeys(&Key.VolumeUp[0], 1) << "Next column\n";
help << DisplayKeys(Key.Enter) << "Add item to playlist and play\n";
@@ -218,3 +251,4 @@ void GetKeybindings(Scrollpad &help)
# endif // HAVE_TAGLIB_H
}
}

View File

@@ -23,7 +23,12 @@
#include "ncmpcpp.h"
void GetKeybindings(Scrollpad &);
namespace Help
{
void Init();
void Resize();
void SwitchTo();
}
#endif

View File

@@ -265,43 +265,6 @@ string FindSharedDir(const string &one, const string &two)
return i != string::npos ? result.substr(0, i) : "/";
}
void GetInfo(Song &s, Scrollpad &info)
{
# ifdef HAVE_TAGLIB_H
string path_to_file;
if (s.IsFromDB())
path_to_file += Config.mpd_music_dir;
path_to_file += s.GetFile();
TagLib::FileRef f(path_to_file.c_str());
if (!f.isNull())
s.SetComment(f.tag()->comment().to8Bit(1));
# endif // HAVE_TAGLIB_H
info << fmtBold << Config.color1 << "Filename: " << fmtBoldEnd << Config.color2 << s.GetName() << "\n" << clEnd;
info << fmtBold << "Directory: " << fmtBoldEnd << Config.color2 << ShowTagInInfoScreen(s.GetDirectory()) << "\n\n" << clEnd;
info << fmtBold << "Length: " << fmtBoldEnd << Config.color2 << s.GetLength() << "\n" << clEnd;
# ifdef HAVE_TAGLIB_H
if (!f.isNull())
{
info << fmtBold << "Bitrate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->bitrate() << " kbps\n" << clEnd;
info << fmtBold << "Sample rate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->sampleRate() << " Hz\n" << clEnd;
info << fmtBold << "Channels: " << fmtBoldEnd << Config.color2 << (f.audioProperties()->channels() == 1 ? "Mono" : "Stereo") << "\n" << clDefault;
}
else
info << clDefault;
# endif // HAVE_TAGLIB_H
info << fmtBold << "\nTitle: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTitle());
info << fmtBold << "\nArtist: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetArtist());
info << fmtBold << "\nAlbum: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetAlbum());
info << fmtBold << "\nYear: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetYear());
info << fmtBold << "\nTrack: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTrack());
info << fmtBold << "\nGenre: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetGenre());
info << fmtBold << "\nComposer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComposer());
info << fmtBold << "\nPerformer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetPerformer());
info << fmtBold << "\nDisc: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetDisc());
info << fmtBold << "\nComment: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComment());
}
string GetLineValue(string &line, char a, char b, bool once)
{
int i = 0;
@@ -342,21 +305,6 @@ const Buffer &ShowTag(const string &tag)
return result;
}
const basic_buffer<my_char_t> &ShowTagInInfoScreen(const string &tag)
{
# ifdef _UTF8
static WBuffer result;
result.Clear();
if (tag.empty())
result << Config.empty_tags_color << ToWString(Config.empty_tag) << clEnd;
else
result << ToWString(tag);
return result;
# else
return ShowTag(tag);
# endif
}
void Scroller(Window &w, const string &string, size_t width, size_t &pos)
{
std::basic_string<my_char_t> s = TO_WSTRING(string);
@@ -401,3 +349,12 @@ void Scroller(Window &w, const string &string, size_t width, size_t &pos)
w << s;
}
#ifdef HAVE_CURL_CURL_H
size_t write_data(char *buffer, size_t size, size_t nmemb, string data)
{
size_t result = size * nmemb;
data.append(buffer, result);
return result;
}
#endif // HAVE_CURL_CURL_H

View File

@@ -44,16 +44,17 @@ bool Keypressed(int, const int *);
std::string FindSharedDir(const std::string &, const std::string &);
void GetInfo(MPD::Song &, Scrollpad &);
std::string GetLineValue(std::string &, char = '"', char = '"', bool = 0);
Window &Statusbar();
const Buffer &ShowTag(const std::string &);
const basic_buffer<my_char_t> &ShowTagInInfoScreen(const std::string &);
void Scroller(Window &, const std::string &, size_t, size_t &);
#ifdef HAVE_CURL_CURL_H
size_t write_data(char *, size_t, size_t, std::string);
#endif
#endif

451
src/info.cpp Normal file
View File

@@ -0,0 +1,451 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "info.h"
#ifdef HAVE_CURL_CURL_H
# include <fstream>
# include <sys/stat.h>
# include <pthread.h>
# include "curl/curl.h"
# include "helpers.h"
#endif
#include "charset.h"
#include "global.h"
#include "media_library.h"
#include "playlist_editor.h"
#include "status_checker.h"
#include "tag_editor.h"
using namespace Global;
using std::string;
using std::vector;
Scrollpad *Global::sInfo;
const string artists_folder = home_folder + "/.ncmpcpp/artists";
namespace
{
pthread_t artist_info_downloader;
bool artist_info_ready = 0;
# ifdef HAVE_CURL_CURL_H
void *GetArtistInfo(void *);
# endif
void GetSongInfo(MPD::Song &, Scrollpad &);
const basic_buffer<my_char_t> &ShowTagInInfoScreen(const string &);
}
void Info::Init()
{
sInfo = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
sInfo->SetTimeout(ncmpcpp_window_timeout);
}
void Info::Resize()
{
sInfo->Resize(COLS, main_height);
}
bool Info::Ready()
{
if (!artist_info_ready)
return false;
pthread_join(artist_info_downloader, NULL);
sInfo->Flush();
artist_info_downloader = 0;
artist_info_ready = 0;
return true;
}
void Info::GetSong()
{
if (wCurrent == sInfo)
{
wCurrent->Hide();
current_screen = prev_screen;
wCurrent = wPrev;
// redraw_screen = 1;
redraw_header = 1;
if (current_screen == csLibrary)
{
MediaLibrary::Refresh();
}
else if (current_screen == csPlaylistEditor)
{
PlaylistEditor::Refresh();
}
# ifdef HAVE_TAGLIB_H
else if (current_screen == csTagEditor)
{
TagEditor::Refresh();
}
# endif // HAVE_TAGLIB_H
}
else if (
(wCurrent == mPlaylist && !mPlaylist->Empty())
|| (wCurrent == mBrowser && mBrowser->Current().type == MPD::itSong)
|| (wCurrent == mSearcher && !mSearcher->Current().first)
|| (wCurrent == mLibSongs && !mLibSongs->Empty())
|| (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty())
# ifdef HAVE_TAGLIB_H
|| (wCurrent == mEditorTags && !mEditorTags->Empty())
# endif // HAVE_TAGLIB_H
)
{
MPD::Song *s = 0;
size_t id = ((Menu<MPD::Song> *)wCurrent)->Choice();
switch (current_screen)
{
case csPlaylist:
s = &mPlaylist->at(id);
break;
case csBrowser:
s = mBrowser->at(id).song;
break;
case csSearcher:
s = mSearcher->at(id).second;
break;
case csLibrary:
s = &mLibSongs->at(id);
break;
case csPlaylistEditor:
s = &mPlaylistEditor->at(id);
break;
# ifdef HAVE_TAGLIB_H
case csTagEditor:
s = &mEditorTags->at(id);
break;
# endif // HAVE_TAGLIB_H
default:
break;
}
wPrev = wCurrent;
wCurrent = sInfo;
prev_screen = current_screen;
current_screen = csInfo;
redraw_header = 1;
info_title = "Song info";
sInfo->Clear();
GetSongInfo(*s, *sInfo);
sInfo->Flush();
sInfo->Hide();
}
}
void Info::GetArtist()
{
if (wCurrent == sInfo)
{
wCurrent->Hide();
current_screen = prev_screen;
wCurrent = wPrev;
// redraw_screen = 1;
redraw_header = 1;
if (current_screen == csLibrary)
{
MediaLibrary::Refresh();
}
else if (current_screen == csPlaylistEditor)
{
PlaylistEditor::Refresh();
}
# ifdef HAVE_TAGLIB_H
else if (current_screen == csTagEditor)
{
TagEditor::Refresh();
}
# endif // HAVE_TAGLIB_H
}
else if (
(wCurrent == mPlaylist && !mPlaylist->Empty())
|| (wCurrent == mBrowser && mBrowser->Current().type == MPD::itSong)
|| (wCurrent == mSearcher && !mSearcher->Current().first)
|| (wCurrent == mLibArtists && !mLibArtists->Empty())
|| (wCurrent == mLibSongs && !mLibSongs->Empty())
|| (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty())
# ifdef HAVE_TAGLIB_H
|| (wCurrent == mEditorTags && !mEditorTags->Empty())
# endif // HAVE_TAGLIB_H
)
{
if (artist_info_downloader)
{
ShowMessage("Artist's info is being downloaded...");
return;
}
string *artist = new string();
int id = ((Menu<MPD::Song> *)wCurrent)->Choice();
switch (current_screen)
{
case csPlaylist:
*artist = mPlaylist->at(id).GetArtist();
break;
case csBrowser:
*artist = mBrowser->at(id).song->GetArtist();
break;
case csSearcher:
*artist = mSearcher->at(id).second->GetArtist();
break;
case csLibrary:
*artist = mLibArtists->at(id);
break;
case csPlaylistEditor:
*artist = mPlaylistEditor->at(id).GetArtist();
break;
# ifdef HAVE_TAGLIB_H
case csTagEditor:
*artist = mEditorTags->at(id).GetArtist();
break;
# endif // HAVE_TAGLIB_H
default:
break;
}
if (!artist->empty())
{
wPrev = wCurrent;
wCurrent = sInfo;
prev_screen = current_screen;
current_screen = csInfo;
redraw_header = 1;
info_title = "Artist's info - " + *artist;
sInfo->Clear();
sInfo->WriteXY(0, 0, 0, "Fetching artist's info...");
sInfo->Refresh();
if (!artist_info_downloader)
{
pthread_create(&artist_info_downloader, NULL, GetArtistInfo, artist);
}
}
else
delete artist;
}
}
namespace {
#ifdef HAVE_CURL_CURL_H
void *GetArtistInfo(void *ptr)
{
string *strptr = static_cast<string *>(ptr);
string artist = *strptr;
delete strptr;
locale_to_utf(artist);
string filename = artist + ".txt";
ToLower(filename);
EscapeUnallowedChars(filename);
const string fullpath = artists_folder + "/" + filename;
mkdir(artists_folder.c_str(), 0755);
string result;
std::ifstream input(fullpath.c_str());
if (input.is_open())
{
bool first = 1;
string line;
while (getline(input, line))
{
if (!first)
*sInfo << "\n";
utf_to_locale(line);
*sInfo << line;
first = 0;
}
input.close();
sInfo->SetFormatting(fmtBold, "\n\nSimilar artists:\n", fmtBoldEnd, 0);
sInfo->SetFormatting(Config.color2, "\n * ", clEnd);
artist_info_ready = 1;
pthread_exit(NULL);
}
CURLcode code;
char *c_artist = curl_easy_escape(0, artist.c_str(), artist.length());
string url = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=";
url += c_artist;
url += "&api_key=d94e5b6e26469a2d1ffae8ef20131b79";
pthread_mutex_lock(&curl);
CURL *info = curl_easy_init();
curl_easy_setopt(info, CURLOPT_URL, url.c_str());
curl_easy_setopt(info, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(info, CURLOPT_WRITEDATA, &result);
curl_easy_setopt(info, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(info, CURLOPT_NOSIGNAL, 1);
code = curl_easy_perform(info);
curl_easy_cleanup(info);
pthread_mutex_unlock(&curl);
curl_free(c_artist);
if (code != CURLE_OK)
{
*sInfo << "Error while fetching artist's info: " << curl_easy_strerror(code);
artist_info_ready = 1;
pthread_exit(NULL);
}
size_t a, b;
bool save = 1;
a = result.find("status=\"failed\"");
if (a != string::npos)
{
EscapeHtml(result);
*sInfo << "Last.fm returned an error message: " << result;
artist_info_ready = 1;
pthread_exit(NULL);
}
vector<string> similar;
for (size_t i = result.find("<name>"); i != string::npos; i = result.find("<name>"))
{
result[i] = '.';
size_t j = result.find("</name>");
result[j] = '.';
i += 6;
similar.push_back(result.substr(i, j-i));
EscapeHtml(similar.back());
}
vector<string> urls;
for (size_t i = result.find("<url>"); i != string::npos; i = result.find("<url>"))
{
result[i] = '.';
size_t j = result.find("</url>");
result[j] = '.';
i += 5;
urls.push_back(result.substr(i, j-i));
}
a = result.find("<content>")+9;
b = result.find("</content>");
if (a == b)
{
result = "No description available for this artist.";
save = 0;
}
else
{
a += 9; // for <![CDATA[
b -= 3; // for ]]>
result = result.substr(a, b-a);
}
EscapeHtml(result);
Trim(result);
Buffer filebuffer;
if (save)
filebuffer << result;
utf_to_locale(result);
*sInfo << result;
if (save)
filebuffer << "\n\nSimilar artists:\n";
*sInfo << fmtBold << "\n\nSimilar artists:\n" << fmtBoldEnd;
for (size_t i = 1; i < similar.size(); i++)
{
if (save)
filebuffer << "\n * " << similar[i] << " (" << urls[i] << ")";
utf_to_locale(similar[i]);
utf_to_locale(urls[i]);
*sInfo << "\n" << Config.color2 << " * " << clEnd << similar[i] << " (" << urls[i] << ")";
}
if (save)
filebuffer << "\n\n" << urls.front();
utf_to_locale(urls.front());
*sInfo << "\n\n" << urls.front();
if (save)
{
std::ofstream output(fullpath.c_str());
if (output.is_open())
{
output << filebuffer.Str();
output.close();
}
}
artist_info_ready = 1;
pthread_exit(NULL);
}
#endif // HVAE_CURL_CURL_H
void GetSongInfo(MPD::Song &s, Scrollpad &info)
{
# ifdef HAVE_TAGLIB_H
string path_to_file;
if (s.IsFromDB())
path_to_file += Config.mpd_music_dir;
path_to_file += s.GetFile();
TagLib::FileRef f(path_to_file.c_str());
if (!f.isNull())
s.SetComment(f.tag()->comment().to8Bit(1));
# endif // HAVE_TAGLIB_H
info << fmtBold << Config.color1 << "Filename: " << fmtBoldEnd << Config.color2 << s.GetName() << "\n" << clEnd;
info << fmtBold << "Directory: " << fmtBoldEnd << Config.color2 << ShowTagInInfoScreen(s.GetDirectory()) << "\n\n" << clEnd;
info << fmtBold << "Length: " << fmtBoldEnd << Config.color2 << s.GetLength() << "\n" << clEnd;
# ifdef HAVE_TAGLIB_H
if (!f.isNull())
{
info << fmtBold << "Bitrate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->bitrate() << " kbps\n" << clEnd;
info << fmtBold << "Sample rate: " << fmtBoldEnd << Config.color2 << f.audioProperties()->sampleRate() << " Hz\n" << clEnd;
info << fmtBold << "Channels: " << fmtBoldEnd << Config.color2 << (f.audioProperties()->channels() == 1 ? "Mono" : "Stereo") << "\n" << clDefault;
}
else
info << clDefault;
# endif // HAVE_TAGLIB_H
info << fmtBold << "\nTitle: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTitle());
info << fmtBold << "\nArtist: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetArtist());
info << fmtBold << "\nAlbum: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetAlbum());
info << fmtBold << "\nYear: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetYear());
info << fmtBold << "\nTrack: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetTrack());
info << fmtBold << "\nGenre: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetGenre());
info << fmtBold << "\nComposer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComposer());
info << fmtBold << "\nPerformer: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetPerformer());
info << fmtBold << "\nDisc: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetDisc());
info << fmtBold << "\nComment: " << fmtBoldEnd << ShowTagInInfoScreen(s.GetComment());
}
const basic_buffer<my_char_t> &ShowTagInInfoScreen(const string &tag)
{
# ifdef _UTF8
static WBuffer result;
result.Clear();
if (tag.empty())
result << Config.empty_tags_color << ToWString(Config.empty_tag) << clEnd;
else
result << ToWString(tag);
return result;
# else
return ShowTag(tag);
# endif
}
}

41
src/info.h Normal file
View File

@@ -0,0 +1,41 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef _H_INFO
#define _H_INFO
#include "ncmpcpp.h"
#include "mpdpp.h"
namespace Info
{
void Init();
void Resize();
bool Ready();
void GetSong();
# ifdef HAVE_CURL_CURL_H
void GetArtist();
# endif
}
#endif

View File

@@ -25,231 +25,178 @@
#include "global.h"
#include "helpers.h"
#include "lyrics.h"
#include "media_library.h"
#include "playlist_editor.h"
#include "settings.h"
#include "song.h"
#include "status_checker.h"
#include "tag_editor.h"
using namespace Global;
using std::vector;
using std::string;
const string artists_folder = home_folder + "/.ncmpcpp/artists";
Scrollpad *Global::sLyrics;
MPD::Song Global::lyrics_song;
const string lyrics_folder = home_folder + "/.lyrics";
#ifdef HAVE_CURL_CURL_H
pthread_mutex_t Global::curl = PTHREAD_MUTEX_INITIALIZER;
#endif
namespace
{
pthread_mutex_t curl = PTHREAD_MUTEX_INITIALIZER;
pthread_t lyrics_downloader;
bool lyrics_ready;
size_t write_data(char *buffer, size_t size, size_t nmemb, string data)
{
size_t result = size * nmemb;
data.append(buffer, result);
return result;
}
void EscapeHtml(string &s)
{
bool erase = 0;
for (size_t i = s.find("<"); i != string::npos; i = s.find("<"))
{
size_t j = s.find(">")+1;
s.replace(i, j-i, "");
}
for (size_t i = s.find("&#039;"); i != string::npos; i = s.find("&#039;"))
s.replace(i, 6, "'");
for (size_t i = s.find("&quot;"); i != string::npos; i = s.find("&quot;"))
s.replace(i, 6, "\"");
for (size_t i = s.find("&amp;"); i != string::npos; i = s.find("&amp;"))
s.replace(i, 5, "&");
for (size_t i = 0; i < s.length(); i++)
{
if (erase)
{
s.erase(s.begin()+i);
erase = 0;
}
if (s[i] == 13) // ascii code for windows line ending, get rid of this shit
{
s[i] = '\n';
erase = 1;
}
else if (s[i] == '\t')
s[i] = ' ';
}
}
void Trim(string &s)
{
if (s.empty())
return;
size_t b = 0;
size_t e = s.length()-1;
while (!isprint(s[b]))
b++;
while (!isprint(s[e]))
e--;
e++;
if (b != 0 || e != s.length()-1)
s = s.substr(b, e-b);
}
void *GetLyrics(void *);
}
void *GetArtistInfo(void *ptr)
void Lyrics::Init()
{
string *strptr = static_cast<string *>(ptr);
string artist = *strptr;
delete strptr;
locale_to_utf(artist);
string filename = artist + ".txt";
ToLower(filename);
EscapeUnallowedChars(filename);
const string fullpath = artists_folder + "/" + filename;
mkdir(artists_folder.c_str(), 0755);
string result;
std::ifstream input(fullpath.c_str());
if (input.is_open())
{
bool first = 1;
string line;
while (getline(input, line))
{
if (!first)
*sInfo << "\n";
utf_to_locale(line);
*sInfo << line;
first = 0;
}
input.close();
sInfo->SetFormatting(fmtBold, "\n\nSimilar artists:\n", fmtBoldEnd, 0);
sInfo->SetFormatting(Config.color2, "\n * ", clEnd);
artist_info_ready = 1;
pthread_exit(NULL);
}
CURLcode code;
char *c_artist = curl_easy_escape(0, artist.c_str(), artist.length());
string url = "http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=";
url += c_artist;
url += "&api_key=d94e5b6e26469a2d1ffae8ef20131b79";
pthread_mutex_lock(&curl);
CURL *info = curl_easy_init();
curl_easy_setopt(info, CURLOPT_URL, url.c_str());
curl_easy_setopt(info, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(info, CURLOPT_WRITEDATA, &result);
curl_easy_setopt(info, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(info, CURLOPT_NOSIGNAL, 1);
code = curl_easy_perform(info);
curl_easy_cleanup(info);
pthread_mutex_unlock(&curl);
curl_free(c_artist);
if (code != CURLE_OK)
{
*sInfo << "Error while fetching artist's info: " << curl_easy_strerror(code);
artist_info_ready = 1;
pthread_exit(NULL);
}
size_t a, b;
bool save = 1;
a = result.find("status=\"failed\"");
if (a != string::npos)
{
EscapeHtml(result);
*sInfo << "Last.fm returned an error message: " << result;
artist_info_ready = 1;
pthread_exit(NULL);
}
vector<string> similar;
for (size_t i = result.find("<name>"); i != string::npos; i = result.find("<name>"))
{
result[i] = '.';
size_t j = result.find("</name>");
result[j] = '.';
i += 6;
similar.push_back(result.substr(i, j-i));
EscapeHtml(similar.back());
}
vector<string> urls;
for (size_t i = result.find("<url>"); i != string::npos; i = result.find("<url>"))
{
result[i] = '.';
size_t j = result.find("</url>");
result[j] = '.';
i += 5;
urls.push_back(result.substr(i, j-i));
}
a = result.find("<content>")+9;
b = result.find("</content>");
if (a == b)
{
result = "No description available for this artist.";
save = 0;
}
else
{
a += 9; // for <![CDATA[
b -= 3; // for ]]>
result = result.substr(a, b-a);
}
EscapeHtml(result);
Trim(result);
Buffer filebuffer;
if (save)
filebuffer << result;
utf_to_locale(result);
*sInfo << result;
if (save)
filebuffer << "\n\nSimilar artists:\n";
*sInfo << fmtBold << "\n\nSimilar artists:\n" << fmtBoldEnd;
for (size_t i = 1; i < similar.size(); i++)
{
if (save)
filebuffer << "\n * " << similar[i] << " (" << urls[i] << ")";
utf_to_locale(similar[i]);
utf_to_locale(urls[i]);
*sInfo << "\n" << Config.color2 << " * " << clEnd << similar[i] << " (" << urls[i] << ")";
}
if (save)
filebuffer << "\n\n" << urls.front();
utf_to_locale(urls.front());
*sInfo << "\n\n" << urls.front();
if (save)
{
std::ofstream output(fullpath.c_str());
if (output.is_open())
{
output << filebuffer.Str();
output.close();
}
}
artist_info_ready = 1;
pthread_exit(NULL);
sLyrics = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
sLyrics->SetTimeout(ncmpcpp_window_timeout);
}
void Lyrics::Resize()
{
sLyrics->Resize(COLS, main_height);
}
void Lyrics::Update()
{
if (!reload_lyrics)
return;
const MPD::Song &s = mPlaylist->at(now_playing);
if (!s.GetArtist().empty() && !s.GetTitle().empty())
Get();
else
reload_lyrics = 0;
}
bool Lyrics::Ready()
{
if (!lyrics_ready)
return false;
pthread_join(lyrics_downloader, NULL);
sLyrics->Flush();
lyrics_downloader = 0;
lyrics_ready = 0;
return true;
}
void Lyrics::Get()
{
if (wCurrent == sLyrics && !reload_lyrics)
{
wCurrent->Hide();
current_screen = prev_screen;
wCurrent = wPrev;
// redraw_screen = 1;
redraw_header = 1;
if (current_screen == csLibrary)
{
MediaLibrary::Refresh();
}
else if (current_screen == csPlaylistEditor)
{
PlaylistEditor::Refresh();
}
# ifdef HAVE_TAGLIB_H
else if (current_screen == csTagEditor)
{
TagEditor::Refresh();
}
# endif // HAVE_TAGLIB_H
}
else if (
reload_lyrics
|| (wCurrent == mPlaylist && !mPlaylist->Empty())
|| (wCurrent == mBrowser && mBrowser->Current().type == MPD::itSong)
|| (wCurrent == mSearcher && !mSearcher->Current().first)
|| (wCurrent == mLibSongs && !mLibSongs->Empty())
|| (wCurrent == mPlaylistEditor && !mPlaylistEditor->Empty())
# ifdef HAVE_TAGLIB_H
|| (wCurrent == mEditorTags && !mEditorTags->Empty())
# endif // HAVE_TAGLIB_H
)
{
# ifdef HAVE_CURL_CURL_H
if (lyrics_downloader)
{
ShowMessage("Lyrics are being downloaded...");
return;
}
# endif
MPD::Song *s = 0;
int id;
if (reload_lyrics)
{
current_screen = csPlaylist;
wCurrent = mPlaylist;
reload_lyrics = 0;
id = now_playing;
}
else
id = ((Menu<MPD::Song> *)wCurrent)->Choice();
switch (current_screen)
{
case csPlaylist:
s = &mPlaylist->at(id);
break;
case csBrowser:
s = mBrowser->at(id).song;
break;
case csSearcher:
s = mSearcher->at(id).second;
break;
case csLibrary:
s = &mLibSongs->at(id);
break;
case csPlaylistEditor:
s = &mPlaylistEditor->at(id);
break;
# ifdef HAVE_TAGLIB_H
case csTagEditor:
s = &mEditorTags->at(id);
break;
# endif // HAVE_TAGLIB_H
default:
break;
}
if (!s->GetArtist().empty() && !s->GetTitle().empty())
{
lyrics_scroll_begin = 0;
lyrics_song = *s;
wPrev = wCurrent;
prev_screen = current_screen;
wCurrent = sLyrics;
current_screen = csLyrics;
redraw_header = 1;
sLyrics->Clear();
sLyrics->WriteXY(0, 0, 0, "Fetching lyrics...");
sLyrics->Refresh();
# ifdef HAVE_CURL_CURL_H
if (!lyrics_downloader)
{
pthread_create(&lyrics_downloader, NULL, GetLyrics, s);
}
# else
GetLyrics(s);
sLyrics->Flush();
# endif
}
}
}
#ifdef HAVE_CURL_CURL_H
namespace
{
bool lyricwiki_not_found(const string &s)
@@ -311,6 +258,7 @@ const char *GetLyricsPluginName(int offset)
#endif // HAVE_CURL_CURL_H
namespace {
void *GetLyrics(void *song)
{
string artist = static_cast<MPD::Song *>(song)->GetArtist();
@@ -415,4 +363,4 @@ void *GetLyrics(void *song)
return NULL;
# endif
}
}

View File

@@ -26,7 +26,16 @@
#ifdef HAVE_CURL_CURL_H
# include <pthread.h>
# include "curl/curl.h"
void *GetArtistInfo(void *);
namespace Lyrics
{
void Init();
void Resize();
void Update();
bool Ready();
void Get();
}
struct LyricsPlugin
{
@@ -40,7 +49,5 @@ const char *GetLyricsPluginName(int);
#endif
void *GetLyrics(void *);
#endif

356
src/media_library.cpp Normal file
View File

@@ -0,0 +1,356 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <algorithm>
#include <map>
#include "charset.h"
#include "display.h"
#include "helpers.h"
#include "global.h"
#include "media_library.h"
#include "mpdpp.h"
#include "status_checker.h"
using namespace MPD;
using namespace Global;
using std::string;
Window *Global::wLibActiveCol;
Menu<string> *Global::mLibArtists;
Menu<string_pair> *Global::mLibAlbums;
Menu<Song> *Global::mLibSongs;
namespace MediaLibrary
{
size_t left_col_width;
size_t middle_col_width;
size_t middle_col_startx;
size_t right_col_width;
size_t right_col_startx;
}
void MediaLibrary::Init()
{
left_col_width = COLS/3-1;
middle_col_width = COLS/3;
middle_col_startx = left_col_width+1;
right_col_width = COLS-COLS/3*2-1;
right_col_startx = left_col_width+middle_col_width+2;
mLibArtists = new Menu<string>(0, main_start_y, left_col_width, main_height, IntoStr(Config.media_lib_primary_tag) + "s", Config.main_color, brNone);
mLibArtists->HighlightColor(Config.active_column_color);
mLibArtists->SetTimeout(ncmpcpp_window_timeout);
mLibArtists->SetItemDisplayer(Display::Generic);
mLibAlbums = new Menu<string_pair>(middle_col_startx, main_start_y, middle_col_width, main_height, "Albums", Config.main_color, brNone);
mLibAlbums->HighlightColor(Config.main_highlight_color);
mLibAlbums->SetTimeout(ncmpcpp_window_timeout);
mLibAlbums->SetItemDisplayer(Display::StringPairs);
mLibSongs = new Menu<Song>(right_col_startx, main_start_y, right_col_width, main_height, "Songs", Config.main_color, brNone);
mLibSongs->HighlightColor(Config.main_highlight_color);
mLibSongs->SetTimeout(ncmpcpp_window_timeout);
mLibSongs->SetSelectPrefix(&Config.selected_item_prefix);
mLibSongs->SetSelectSuffix(&Config.selected_item_suffix);
mLibSongs->SetItemDisplayer(Display::Songs);
mLibSongs->SetItemDisplayerUserData(&Config.song_library_format);
wLibActiveCol = mLibArtists;
}
void MediaLibrary::Resize()
{
left_col_width = COLS/3-1;
middle_col_startx = left_col_width+1;
middle_col_width = COLS/3;
right_col_startx = left_col_width+middle_col_width+2;
right_col_width = COLS-COLS/3*2-1;
mLibArtists->Resize(left_col_width, main_height);
mLibAlbums->Resize(middle_col_width, main_height);
mLibSongs->Resize(right_col_width, main_height);
mLibAlbums->MoveTo(middle_col_startx, main_start_y);
mLibSongs->MoveTo(right_col_startx, main_start_y);
}
void MediaLibrary::Refresh()
{
mLibArtists->Display();
mvvline(main_start_y, middle_col_startx-1, 0, main_height);
mLibAlbums->Display();
mvvline(main_start_y, right_col_startx-1, 0, main_height);
mLibSongs->Display();
if (mLibAlbums->Empty())
{
mLibAlbums->WriteXY(0, 0, 0, "No albums found.");
mLibAlbums->Refresh();
}
}
void MediaLibrary::SwitchTo()
{
if (current_screen != csLibrary
# ifdef HAVE_TAGLIB_H
&& current_screen != csTinyTagEditor
# endif // HAVE_TAGLIB_H
)
{
CLEAR_FIND_HISTORY;
mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width
// redraw_screen = 1;
redraw_header = 1;
MediaLibrary::Refresh();
wCurrent = wLibActiveCol;
current_screen = csLibrary;
UpdateSongList(mLibSongs);
}
}
void MediaLibrary::Update()
{
if (mLibArtists->Empty())
{
CLEAR_FIND_HISTORY;
TagList list;
mLibAlbums->Clear(0);
mLibSongs->Clear(0);
Mpd->GetList(list, Config.media_lib_primary_tag);
sort(list.begin(), list.end(), CaseInsensitiveSorting());
for (TagList::iterator it = list.begin(); it != list.end(); it++)
{
if (!it->empty())
{
utf_to_locale(*it);
mLibArtists->AddOption(*it);
}
}
mLibArtists->Window::Clear();
mLibArtists->Refresh();
}
if (!mLibArtists->Empty() && mLibAlbums->Empty() && mLibSongs->Empty())
{
mLibAlbums->Reset();
TagList list;
std::map<string, string, CaseInsensitiveSorting> maplist;
locale_to_utf(mLibArtists->Current());
if (Config.media_lib_primary_tag == MPD_TAG_ITEM_ARTIST)
Mpd->GetAlbums(mLibArtists->Current(), list);
else
{
Mpd->StartSearch(1);
Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current());
Mpd->StartFieldSearch(MPD_TAG_ITEM_ALBUM);
Mpd->CommitSearch(list);
}
// <mpd-0.14 doesn't support searching for empty tag
if (Mpd->Version() > 13)
{
SongList noalbum_list;
Mpd->StartSearch(1);
Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current());
Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, "");
Mpd->CommitSearch(noalbum_list);
if (!noalbum_list.empty())
mLibAlbums->AddOption(std::make_pair("<no album>", ""));
FreeSongList(noalbum_list);
}
for (TagList::iterator it = list.begin(); it != list.end(); it++)
{
SongList l;
Mpd->StartSearch(1);
Mpd->AddSearch(Config.media_lib_primary_tag, mLibArtists->Current());
Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, *it);
Mpd->CommitSearch(l);
if (!l.empty() && !l[0]->GetAlbum().empty())
{
utf_to_locale(*it);
l[0]->Localize();
maplist[l[0]->toString(Config.media_lib_album_format)] = *it;
}
FreeSongList(l);
}
utf_to_locale(mLibArtists->Current());
for (std::map<string, string>::const_iterator it = maplist.begin(); it != maplist.end(); it++)
mLibAlbums->AddOption(make_pair(it->first, it->second));
mLibAlbums->Window::Clear();
mLibAlbums->Refresh();
}
if (!mLibArtists->Empty() && wCurrent == mLibAlbums && mLibAlbums->Empty())
{
mLibAlbums->HighlightColor(Config.main_highlight_color);
mLibArtists->HighlightColor(Config.active_column_color);
wCurrent = wLibActiveCol = mLibArtists;
}
if (!mLibArtists->Empty() && mLibSongs->Empty())
{
mLibSongs->Reset();
SongList list;
mLibSongs->Clear(0);
Mpd->StartSearch(1);
Mpd->AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(mLibArtists->Current()));
if (mLibAlbums->Empty()) // left for compatibility with <mpd-0.14
{
mLibAlbums->WriteXY(0, 0, 0, "No albums found.");
mLibAlbums->Refresh();
}
else
Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, locale_to_utf_cpy(mLibAlbums->Current().second));
Mpd->CommitSearch(list);
sort(list.begin(), list.end(), SortSongsByTrack);
bool bold = 0;
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
{
for (size_t j = 0; j < mPlaylist->Size(); j++)
{
if ((*it)->GetHash() == mPlaylist->at(j).GetHash())
{
bold = 1;
break;
}
}
mLibSongs->AddOption(**it, bold);
bold = 0;
}
FreeSongList(list);
mLibSongs->Window::Clear();
mLibSongs->Refresh();
}
}
void MediaLibrary::EnterPressed(bool add_n_play)
{
SongList list;
if (!mLibArtists->Empty() && wCurrent == mLibArtists)
{
Mpd->StartSearch(1);
Mpd->AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(mLibArtists->Current()));
Mpd->CommitSearch(list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
string tag_type = IntoStr(Config.media_lib_primary_tag);
ToLower(tag_type);
ShowMessage("Adding songs of %s \"%s\"", tag_type.c_str(), mLibArtists->Current().c_str());
Song *s = &mPlaylist->at(mPlaylist->Size()-list.size());
if (s->GetHash() == list[0]->GetHash())
{
if (add_n_play)
Mpd->PlayID(s->GetID());
}
else
ShowMessage("%s", message_part_of_songs_added);
}
}
else if (wCurrent == mLibAlbums)
{
for (size_t i = 0; i < mLibSongs->Size(); i++)
Mpd->QueueAddSong(mLibSongs->at(i));
if (Mpd->CommitQueue())
{
ShowMessage("Adding songs from album \"%s\"", mLibAlbums->Current().second.c_str());
Song *s = &mPlaylist->at(mPlaylist->Size()-mLibSongs->Size());
if (s->GetHash() == mLibSongs->at(0).GetHash())
{
if (add_n_play)
Mpd->PlayID(s->GetID());
}
else
ShowMessage("%s", message_part_of_songs_added);
}
}
else if (wCurrent == mLibSongs)
{
if (!mLibSongs->Empty())
{
block_item_list_update = 1;
if (Config.ncmpc_like_songs_adding && mLibSongs->isBold())
{
long long hash = mLibSongs->Current().GetHash();
if (add_n_play)
{
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->Play(i);
break;
}
}
}
else
{
block_playlist_update = 1;
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->QueueDeleteSong(i);
mPlaylist->DeleteOption(i);
i--;
}
}
Mpd->CommitQueue();
mLibSongs->BoldOption(mLibSongs->Choice(), 0);
}
}
else
{
Song &s = mLibSongs->Current();
int id = Mpd->AddSong(s);
if (id >= 0)
{
ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str());
if (add_n_play)
Mpd->PlayID(id);
mLibSongs->BoldOption(mLibSongs->Choice(), 1);
}
}
}
}
FreeSongList(list);
if (!add_n_play)
{
wCurrent->Scroll(wDown);
if (wCurrent == mLibArtists)
{
mLibAlbums->Clear(0);
mLibSongs->Clear(0);
}
else if (wCurrent == mLibAlbums)
mLibSongs->Clear(0);
}
}

44
src/media_library.h Normal file
View File

@@ -0,0 +1,44 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef _H_MEDIA_LIBRARY
#define _H_MEDIA_LIBRARY
#include "ncmpcpp.h"
namespace MediaLibrary
{
void Init();
void Resize();
void Refresh();
void SwitchTo();
void Update();
void EnterPressed(bool = 1);
inline void SpacePressed();
}
void MediaLibrary::SpacePressed()
{
EnterPressed(0);
}
#endif

View File

@@ -160,3 +160,52 @@ void EscapeUnallowedChars(std::string &s)
}
}
void EscapeHtml(std::string &s)
{
bool erase = 0;
for (size_t i = s.find("<"); i != std::string::npos; i = s.find("<"))
{
size_t j = s.find(">")+1;
s.replace(i, j-i, "");
}
for (size_t i = s.find("&#039;"); i != std::string::npos; i = s.find("&#039;"))
s.replace(i, 6, "'");
for (size_t i = s.find("&quot;"); i != std::string::npos; i = s.find("&quot;"))
s.replace(i, 6, "\"");
for (size_t i = s.find("&amp;"); i != std::string::npos; i = s.find("&amp;"))
s.replace(i, 5, "&");
for (size_t i = 0; i < s.length(); i++)
{
if (erase)
{
s.erase(s.begin()+i);
erase = 0;
}
if (s[i] == 13) // ascii code for windows line ending, get rid of this shit
{
s[i] = '\n';
erase = 1;
}
else if (s[i] == '\t')
s[i] = ' ';
}
}
void Trim(std::string &s)
{
if (s.empty())
return;
size_t b = 0;
size_t e = s.length()-1;
while (!isprint(s[b]))
b++;
while (!isprint(s[e]))
e--;
e++;
if (b != 0 || e != s.length()-1)
s = s.substr(b, e-b);
}

View File

@@ -42,5 +42,9 @@ mpd_TagItems IntoTagItem(char);
void EscapeUnallowedChars(std::string &);
void EscapeHtml(std::string &s);
void Trim(std::string &s);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,12 @@
#include "scrollpad.h"
#include "misc.h"
#define CLEAR_FIND_HISTORY \
do { \
found_pos = -1; \
vFoundPositions.clear(); \
} while (0)
typedef std::pair<std::string, std::string> string_pair;
enum NcmpcppScreen
@@ -33,14 +39,20 @@ enum NcmpcppScreen
csHelp,
csPlaylist,
csBrowser,
# ifdef HAVE_TAGLIB_H
csTinyTagEditor,
# endif // HAVE_TAGLIB_H
csInfo,
csSearcher,
csLibrary,
csLyrics,
csPlaylistEditor,
# ifdef HAVE_TAGLIB_H
csTagEditor,
# endif // HAVE_TAGLIB_H
# ifdef ENABLE_CLOCK
csClock,
# endif // ENABLE_CLOCK
csOther
};
@@ -48,5 +60,7 @@ const int ncmpcpp_window_timeout = 500;
const std::string home_folder = getenv("HOME") ? getenv("HOME") : "";
const char * const message_part_of_songs_added = "Only part of requested songs' list added to playlist!";
#endif

64
src/playlist.cpp Normal file
View File

@@ -0,0 +1,64 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "display.h"
#include "global.h"
#include "menu.h"
#include "playlist.h"
#include "song.h"
using namespace Global;
Menu<MPD::Song> *Global::mPlaylist;
void Playlist::Init()
{
mPlaylist = new Menu<MPD::Song>(0, main_start_y, COLS, main_height, Config.columns_in_playlist ? Display::Columns(Config.song_columns_list_format) : "", Config.main_color, brNone);
mPlaylist->SetTimeout(ncmpcpp_window_timeout);
mPlaylist->HighlightColor(Config.main_highlight_color);
mPlaylist->SetSelectPrefix(&Config.selected_item_prefix);
mPlaylist->SetSelectSuffix(&Config.selected_item_suffix);
mPlaylist->SetItemDisplayer(Config.columns_in_playlist ? Display::SongsInColumns : Display::Songs);
mPlaylist->SetItemDisplayerUserData(Config.columns_in_playlist ? &Config.song_columns_list_format : &Config.song_list_format);
}
void Playlist::Resize()
{
mPlaylist->Resize(COLS, main_height);
mPlaylist->SetTitle(Config.columns_in_playlist ? Display::Columns(Config.song_columns_list_format) : "");
}
void Playlist::SwitchTo()
{
if (current_screen != csPlaylist
# ifdef HAVE_TAGLIB_H
&& current_screen != csTinyTagEditor
# endif // HAVE_TAGLIB_H
)
{
CLEAR_FIND_HISTORY;
wCurrent = mPlaylist;
wCurrent->Hide();
current_screen = csPlaylist;
// redraw_screen = 1;
redraw_header = 1;
}
}

32
src/playlist.h Normal file
View File

@@ -0,0 +1,32 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef _PLAYLIST_H
#define _PLAYLIST_H
namespace Playlist
{
void Init();
void Resize();
void SwitchTo();
}
#endif

244
src/playlist_editor.cpp Normal file
View File

@@ -0,0 +1,244 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <algorithm>
#include "charset.h"
#include "display.h"
#include "global.h"
#include "helpers.h"
#include "playlist_editor.h"
#include "mpdpp.h"
#include "status_checker.h"
using namespace Global;
using namespace MPD;
using std::string;
Window *Global::wPlaylistEditorActiveCol;
Menu<string> *Global::mPlaylistList;
Menu<Song> *Global::mPlaylistEditor;
namespace PlaylistEditor
{
size_t left_col_width;
size_t right_col_startx;
size_t right_col_width;
}
void PlaylistEditor::Init()
{
left_col_width = COLS/3-1;
right_col_startx = left_col_width+1;
right_col_width = COLS-left_col_width-1;
mPlaylistList = new Menu<string>(0, main_start_y, left_col_width, main_height, "Playlists", Config.main_color, brNone);
mPlaylistList->HighlightColor(Config.active_column_color);
mPlaylistList->SetTimeout(ncmpcpp_window_timeout);
mPlaylistList->SetItemDisplayer(Display::Generic);
mPlaylistEditor = new Menu<Song>(right_col_startx, main_start_y, right_col_width, main_height, "Playlist's content", Config.main_color, brNone);
mPlaylistEditor->HighlightColor(Config.main_highlight_color);
mPlaylistEditor->SetTimeout(ncmpcpp_window_timeout);
mPlaylistEditor->SetSelectPrefix(&Config.selected_item_prefix);
mPlaylistEditor->SetSelectSuffix(&Config.selected_item_suffix);
mPlaylistEditor->SetItemDisplayer(Display::Songs);
mPlaylistEditor->SetItemDisplayerUserData(&Config.song_list_format);
wPlaylistEditorActiveCol = mPlaylistList;
}
void PlaylistEditor::Resize()
{
left_col_width = COLS/3-1;
right_col_startx = left_col_width+1;
right_col_width = COLS-left_col_width-1;
mPlaylistList->Resize(left_col_width, main_height);
mPlaylistEditor->Resize(right_col_width, main_height);
mPlaylistEditor->MoveTo(right_col_startx, main_start_y);
}
void PlaylistEditor::Refresh()
{
mPlaylistList->Display();
mvvline(main_start_y, right_col_startx-1, 0, main_height);
mPlaylistEditor->Display();
}
void PlaylistEditor::SwitchTo()
{
if (current_screen != csPlaylistEditor
# ifdef HAVE_TAGLIB_H
&& current_screen != csTinyTagEditor
# endif // HAVE_TAGLIB_H
)
{
CLEAR_FIND_HISTORY;
mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width
// redraw_screen = 1;
redraw_header = 1;
PlaylistEditor::Refresh();
wCurrent = wPlaylistEditorActiveCol;
current_screen = csPlaylistEditor;
UpdateSongList(mPlaylistEditor);
}
}
void PlaylistEditor::Update()
{
if (mPlaylistList->Empty())
{
mPlaylistEditor->Clear(0);
TagList list;
Mpd->GetPlaylists(list);
sort(list.begin(), list.end(), CaseInsensitiveSorting());
for (TagList::iterator it = list.begin(); it != list.end(); it++)
{
utf_to_locale(*it);
mPlaylistList->AddOption(*it);
}
mPlaylistList->Window::Clear();
mPlaylistList->Refresh();
}
if (!mPlaylistList->Empty() && mPlaylistEditor->Empty())
{
mPlaylistEditor->Reset();
SongList list;
Mpd->GetPlaylistContent(locale_to_utf_cpy(mPlaylistList->Current()), list);
if (!list.empty())
mPlaylistEditor->SetTitle("Playlist's content (" + IntoStr(list.size()) + " item" + (list.size() == 1 ? ")" : "s)"));
else
mPlaylistEditor->SetTitle("Playlist's content");
bool bold = 0;
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
{
for (size_t j = 0; j < mPlaylist->Size(); j++)
{
if ((*it)->GetHash() == mPlaylist->at(j).GetHash())
{
bold = 1;
break;
}
}
mPlaylistEditor->AddOption(**it, bold);
bold = 0;
}
FreeSongList(list);
mPlaylistEditor->Window::Clear();
mPlaylistEditor->Display();
}
if (wCurrent == mPlaylistEditor && mPlaylistEditor->Empty())
{
mPlaylistEditor->HighlightColor(Config.main_highlight_color);
mPlaylistList->HighlightColor(Config.active_column_color);
wCurrent = wPlaylistEditorActiveCol = mPlaylistList;
}
if (mPlaylistEditor->Empty())
{
mPlaylistEditor->WriteXY(0, 0, 0, "Playlist is empty.");
mPlaylistEditor->Refresh();
}
}
void PlaylistEditor::EnterPressed(bool add_n_play)
{
SongList list;
if (wCurrent == mPlaylistList && !mPlaylistList->Empty())
{
Mpd->GetPlaylistContent(locale_to_utf_cpy(mPlaylistList->Current()), list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Loading playlist %s...", mPlaylistList->Current().c_str());
Song &s = mPlaylist->at(mPlaylist->Size()-list.size());
if (s.GetHash() == list[0]->GetHash())
{
if (add_n_play)
Mpd->PlayID(s.GetID());
}
else
ShowMessage("%s", message_part_of_songs_added);
}
}
else if (wCurrent == mPlaylistEditor)
{
if (!mPlaylistEditor->Empty())
{
block_item_list_update = 1;
if (Config.ncmpc_like_songs_adding && mPlaylistEditor->isBold())
{
long long hash = mPlaylistEditor->Current().GetHash();
if (add_n_play)
{
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->Play(i);
break;
}
}
}
else
{
block_playlist_update = 1;
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->QueueDeleteSong(i);
mPlaylist->DeleteOption(i);
i--;
}
}
Mpd->CommitQueue();
mPlaylistEditor->BoldOption(mPlaylistEditor->Choice(), 0);
}
}
else
{
Song &s = mPlaylistEditor->at(mPlaylistEditor->Choice());
int id = Mpd->AddSong(s);
if (id >= 0)
{
ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str());
if (add_n_play)
Mpd->PlayID(id);
mPlaylistEditor->BoldOption(mPlaylistEditor->Choice(), 1);
}
}
}
}
FreeSongList(list);
if (!add_n_play)
wCurrent->Scroll(wDown);
}

44
src/playlist_editor.h Normal file
View File

@@ -0,0 +1,44 @@
/***************************************************************************
* Copyright (C) 2008-2009 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef _PLAYLIST_EDITOR_H
#define _PLAYLIST_EDITOR_H
#include "ncmpcpp.h"
namespace PlaylistEditor
{
void Init();
void Resize();
void Refresh();
void SwitchTo();
void Update();
void EnterPressed(bool = 1);
inline void SpacePressed();
}
void PlaylistEditor::SpacePressed()
{
EnterPressed(0);
}
#endif

View File

@@ -23,17 +23,262 @@
#include "helpers.h"
#include "search_engine.h"
#include "settings.h"
#include "status_checker.h"
using namespace MPD;
using namespace Global;
using std::string;
Menu< std::pair<Buffer *, Song *> > *Global::mSearcher;
bool Global::search_match_to_pattern = 1;
bool Global::search_case_sensitive = 0;
const char *Global::search_mode_normal = "Match if tag contains searched phrase";
const char *Global::search_mode_strict = "Match only if both values are the same";
namespace
{
SearchPattern sought;
}
void SearchEngine::Init()
{
mSearcher = new Menu< std::pair<Buffer *, Song *> >(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
mSearcher->HighlightColor(Config.main_highlight_color);
mSearcher->SetTimeout(ncmpcpp_window_timeout);
mSearcher->SetItemDisplayer(Display::SearchEngine);
mSearcher->SetSelectPrefix(&Config.selected_item_prefix);
mSearcher->SetSelectSuffix(&Config.selected_item_suffix);
}
void SearchEngine::Resize()
{
mSearcher->Resize(COLS, main_height);
}
void SearchEngine::SwitchTo()
{
if (current_screen != csSearcher
# ifdef HAVE_TAGLIB_H
&& current_screen != csTinyTagEditor
# endif // HAVE_TAGLIB_H
)
{
CLEAR_FIND_HISTORY;
if (mSearcher->Empty())
PrepareSearchEngine();
wCurrent = mSearcher;
wCurrent->Hide();
current_screen = csSearcher;
// redraw_screen = 1;
redraw_header = 1;
if (!mSearcher->Back().first)
{
wCurrent->WriteXY(0, 0, 0, "Updating list...");
UpdateFoundList();
}
}
}
void SearchEngine::EnterPressed()
{
size_t option = mSearcher->Choice();
LockStatusbar();
SearchPattern &s = sought;
if (option <= 12)
mSearcher->Current().first->Clear();
switch (option)
{
case 0:
{
Statusbar() << fmtBold << "Any: " << fmtBoldEnd;
s.Any(wFooter->GetString(s.Any()));
*mSearcher->Current().first << fmtBold << "Any: " << fmtBoldEnd << ' ' << ShowTag(s.Any());
break;
}
case 1:
{
Statusbar() << fmtBold << "Artist: " << fmtBoldEnd;
s.SetArtist(wFooter->GetString(s.GetArtist()));
*mSearcher->Current().first << fmtBold << "Artist: " << fmtBoldEnd << ' ' << ShowTag(s.GetArtist());
break;
}
case 2:
{
Statusbar() << fmtBold << "Title: " << fmtBoldEnd;
s.SetTitle(wFooter->GetString(s.GetTitle()));
*mSearcher->Current().first << fmtBold << "Title: " << fmtBoldEnd << ' ' << ShowTag(s.GetTitle());
break;
}
case 3:
{
Statusbar() << fmtBold << "Album: " << fmtBoldEnd;
s.SetAlbum(wFooter->GetString(s.GetAlbum()));
*mSearcher->Current().first << fmtBold << "Album: " << fmtBoldEnd << ' ' << ShowTag(s.GetAlbum());
break;
}
case 4:
{
Statusbar() << fmtBold << "Filename: " << fmtBoldEnd;
s.SetFile(wFooter->GetString(s.GetFile()));
*mSearcher->Current().first << fmtBold << "Filename: " << fmtBoldEnd << ' ' << ShowTag(s.GetFile());
break;
}
case 5:
{
Statusbar() << fmtBold << "Composer: " << fmtBoldEnd;
s.SetComposer(wFooter->GetString(s.GetComposer()));
*mSearcher->Current().first << fmtBold << "Composer: " << fmtBoldEnd << ' ' << ShowTag(s.GetComposer());
break;
}
case 6:
{
Statusbar() << fmtBold << "Performer: " << fmtBoldEnd;
s.SetPerformer(wFooter->GetString(s.GetPerformer()));
*mSearcher->Current().first << fmtBold << "Performer:" << fmtBoldEnd << ' ' << ShowTag(s.GetPerformer());
break;
}
case 7:
{
Statusbar() << fmtBold << "Genre: " << fmtBoldEnd;
s.SetGenre(wFooter->GetString(s.GetGenre()));
*mSearcher->Current().first << fmtBold << "Genre: " << fmtBoldEnd << ' ' << ShowTag(s.GetGenre());
break;
}
case 8:
{
Statusbar() << fmtBold << "Year: " << fmtBoldEnd;
s.SetYear(wFooter->GetString(s.GetYear(), 4));
*mSearcher->Current().first << fmtBold << "Year: " << fmtBoldEnd << ' ' << ShowTag(s.GetYear());
break;
}
case 9:
{
Statusbar() << fmtBold << "Comment: " << fmtBoldEnd;
s.SetComment(wFooter->GetString(s.GetComment()));
*mSearcher->Current().first << fmtBold << "Comment: " << fmtBoldEnd << ' ' << ShowTag(s.GetComment());
break;
}
case 11:
{
Config.search_in_db = !Config.search_in_db;
*mSearcher->Current().first << fmtBold << "Search in:" << fmtBoldEnd << ' ' << (Config.search_in_db ? "Database" : "Current playlist");
break;
}
case 12:
{
search_match_to_pattern = !search_match_to_pattern;
*mSearcher->Current().first << fmtBold << "Search mode:" << fmtBoldEnd << ' ' << (search_match_to_pattern ? search_mode_normal : search_mode_strict);
break;
}
case 13:
{
search_case_sensitive = !search_case_sensitive;
*mSearcher->Current().first << fmtBold << "Case sensitive:" << fmtBoldEnd << ' ' << (search_case_sensitive ? "Yes" : "No");
break;
}
case 15:
{
ShowMessage("Searching...");
Search();
if (!mSearcher->Back().first)
{
if (Config.columns_in_search_engine)
mSearcher->SetTitle(Display::Columns(Config.song_columns_list_format));
size_t found = mSearcher->Size()-search_engine_static_options;
found += 3; // don't count options inserted below
mSearcher->InsertSeparator(search_engine_reset_button+1);
mSearcher->InsertOption(search_engine_reset_button+2, std::make_pair((Buffer *)0, (Song *)0), 1, 1);
mSearcher->at(search_engine_reset_button+2).first = new Buffer();
*mSearcher->at(search_engine_reset_button+2).first << Config.color1 << "Search results: " << Config.color2 << "Found " << found << (found > 1 ? " songs" : " song") << clDefault;
mSearcher->InsertSeparator(search_engine_reset_button+3);
UpdateFoundList();
ShowMessage("Searching finished!");
for (size_t i = 0; i < search_engine_static_options-4; i++)
mSearcher->Static(i, 1);
mSearcher->Scroll(wDown);
mSearcher->Scroll(wDown);
}
else
ShowMessage("No results found");
break;
}
case 16:
{
CLEAR_FIND_HISTORY;
PrepareSearchEngine();
ShowMessage("Search state reset");
break;
}
default:
{
block_item_list_update = 1;
if (Config.ncmpc_like_songs_adding && mSearcher->isBold())
{
long long hash = mSearcher->Current().second->GetHash();
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->Play(i);
break;
}
}
}
else
{
const Song &s = *mSearcher->Current().second;
int id = Mpd->AddSong(s);
if (id >= 0)
{
Mpd->PlayID(id);
ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str());
mSearcher->BoldOption(mSearcher->Choice(), 1);
}
}
break;
}
}
UnlockStatusbar();
}
void SearchEngine::SpacePressed()
{
if (mSearcher->Current().first)
return;
block_item_list_update = 1;
if (Config.ncmpc_like_songs_adding && mSearcher->isBold())
{
block_playlist_update = 1;
long long hash = mSearcher->Current().second->GetHash();
for (size_t i = 0; i < mPlaylist->Size(); i++)
{
if (mPlaylist->at(i).GetHash() == hash)
{
Mpd->QueueDeleteSong(i);
mPlaylist->DeleteOption(i);
i--;
}
}
Mpd->CommitQueue();
mSearcher->BoldOption(mSearcher->Choice(), 0);
}
else
{
const Song &s = *mSearcher->Current().second;
if (Mpd->AddSong(s) != -1)
{
ShowMessage("Added to playlist: %s", s.toString(Config.song_status_format).c_str());
mSearcher->BoldOption(mSearcher->Choice(), 1);
}
}
mSearcher->Scroll(wDown);
}
void UpdateFoundList()
{
bool bold = 0;
@@ -52,8 +297,10 @@ void UpdateFoundList()
}
}
void PrepareSearchEngine(SearchPattern &s)
void PrepareSearchEngine()
{
SearchPattern &s = sought;
for (size_t i = 0; i < mSearcher->Size(); i++)
{
try
@@ -101,11 +348,13 @@ void PrepareSearchEngine(SearchPattern &s)
*mSearcher->at(16).first << "Reset";
}
void Search(SearchPattern s)
void Search()
{
if (s.Empty())
if (sought.Empty())
return;
SearchPattern s = sought;
SongList list;
if (Config.search_in_db)
Mpd->GetDirectoryRecursive("/", list);

View File

@@ -24,6 +24,16 @@
#include "mpdpp.h"
#include "ncmpcpp.h"
namespace SearchEngine
{
void Init();
void Resize();
void SwitchTo();
void EnterPressed();
void SpacePressed();
}
class SearchPattern : public MPD::Song
{
public:
@@ -42,8 +52,8 @@ const size_t search_engine_search_button = 15;
const size_t search_engine_reset_button = 16;
void UpdateFoundList();
void PrepareSearchEngine(SearchPattern &s);
void Search(SearchPattern);
void PrepareSearchEngine();
void Search();
#endif

View File

@@ -33,11 +33,583 @@
#include "display.h"
#include "global.h"
#include "helpers.h"
#include "media_library.h"
#include "playlist_editor.h"
#include "status_checker.h"
using namespace Global;
using namespace MPD;
Menu<Buffer> *Global::mTagEditor;
Window *Global::wTagEditorActiveCol;
Menu<string_pair> *Global::mEditorAlbums;
Menu<string_pair> *Global::mEditorDirs;
Menu<string_pair> *Global::mEditorLeftCol;
Menu<string> *Global::mEditorTagTypes;
Menu<Song> *Global::mEditorTags;
void TinyTagEditor::Init()
{
mTagEditor = new Menu<Buffer>(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
mTagEditor->HighlightColor(Config.main_highlight_color);
mTagEditor->SetTimeout(ncmpcpp_window_timeout);
mTagEditor->SetItemDisplayer(Display::Generic);
}
void TinyTagEditor::EnterPressed(Song &s)
{
size_t option = mTagEditor->Choice();
LockStatusbar();
if (option >= 8 && option <= 20)
mTagEditor->at(option).Clear();
switch (option-7)
{
case 1:
{
Statusbar() << fmtBold << "Title: " << fmtBoldEnd;
s.SetTitle(wFooter->GetString(s.GetTitle()));
mTagEditor->at(option) << fmtBold << "Title:" << fmtBoldEnd << ' ' << ShowTag(s.GetTitle());
break;
}
case 2:
{
Statusbar() << fmtBold << "Artist: " << fmtBoldEnd;
s.SetArtist(wFooter->GetString(s.GetArtist()));
mTagEditor->at(option) << fmtBold << "Artist:" << fmtBoldEnd << ' ' << ShowTag(s.GetArtist());
break;
}
case 3:
{
Statusbar() << fmtBold << "Album: " << fmtBoldEnd;
s.SetAlbum(wFooter->GetString(s.GetAlbum()));
mTagEditor->at(option) << fmtBold << "Album:" << fmtBoldEnd << ' ' << ShowTag(s.GetAlbum());
break;
}
case 4:
{
Statusbar() << fmtBold << "Year: " << fmtBoldEnd;
s.SetYear(wFooter->GetString(s.GetYear(), 4));
mTagEditor->at(option) << fmtBold << "Year:" << fmtBoldEnd << ' ' << ShowTag(s.GetYear());
break;
}
case 5:
{
Statusbar() << fmtBold << "Track: " << fmtBoldEnd;
s.SetTrack(wFooter->GetString(s.GetTrack(), 3));
mTagEditor->at(option) << fmtBold << "Track:" << fmtBoldEnd << ' ' << ShowTag(s.GetTrack());
break;
}
case 6:
{
Statusbar() << fmtBold << "Genre: " << fmtBoldEnd;
s.SetGenre(wFooter->GetString(s.GetGenre()));
mTagEditor->at(option) << fmtBold << "Genre:" << fmtBoldEnd << ' ' << ShowTag(s.GetGenre());
break;
}
case 7:
{
Statusbar() << fmtBold << "Composer: " << fmtBoldEnd;
s.SetComposer(wFooter->GetString(s.GetComposer()));
mTagEditor->at(option) << fmtBold << "Composer:" << fmtBoldEnd << ' ' << ShowTag(s.GetComposer());
break;
}
case 8:
{
Statusbar() << fmtBold << "Performer: " << fmtBoldEnd;
s.SetPerformer(wFooter->GetString(s.GetPerformer()));
mTagEditor->at(option) << fmtBold << "Performer:" << fmtBoldEnd << ' ' << ShowTag(s.GetPerformer());
break;
}
case 9:
{
Statusbar() << fmtBold << "Disc: " << fmtBoldEnd;
s.SetDisc(wFooter->GetString(s.GetDisc()));
mTagEditor->at(option) << fmtBold << "Disc:" << fmtBoldEnd << ' ' << ShowTag(s.GetDisc());
break;
}
case 10:
{
Statusbar() << fmtBold << "Comment: " << fmtBoldEnd;
s.SetComment(wFooter->GetString(s.GetComment()));
mTagEditor->at(option) << fmtBold << "Comment:" << fmtBoldEnd << ' ' << ShowTag(s.GetComment());
break;
}
case 12:
{
Statusbar() << fmtBold << "Filename: " << fmtBoldEnd;
string filename = s.GetNewName().empty() ? s.GetName() : s.GetNewName();
size_t dot = filename.rfind(".");
string extension = filename.substr(dot);
filename = filename.substr(0, dot);
string new_name = wFooter->GetString(filename);
s.SetNewName(new_name + extension);
mTagEditor->at(option) << fmtBold << "Filename:" << fmtBoldEnd << ' ' << (s.GetNewName().empty() ? s.GetName() : s.GetNewName());
break;
}
case 14:
{
ShowMessage("Updating tags...");
if (WriteTags(s))
{
ShowMessage("Tags updated!");
if (s.IsFromDB())
{
Mpd->UpdateDirectory(locale_to_utf_cpy(s.GetDirectory()));
if (prev_screen == csSearcher)
*mSearcher->Current().second = s;
}
else
{
if (wPrev == mPlaylist)
mPlaylist->Current() = s;
else if (wPrev == mBrowser)
*mBrowser->Current().song = s;
}
}
else
ShowMessage("Error writing tags!");
}
case 15:
{
wCurrent->Clear();
wCurrent = wPrev;
current_screen = prev_screen;
redraw_header = 1;
if (current_screen == csLibrary)
{
MediaLibrary::Refresh();
}
else if (current_screen == csPlaylistEditor)
{
PlaylistEditor::Refresh();
}
else if (current_screen == csTagEditor)
{
TagEditor::Refresh();
}
break;
}
}
UnlockStatusbar();
}
namespace TagEditor
{
const size_t middle_col_width = 26;
size_t left_col_width;
size_t middle_col_startx;
size_t right_col_width;
size_t right_col_startx;
}
void TagEditor::Init()
{
left_col_width = COLS/2-middle_col_width/2;
middle_col_startx = left_col_width+1;
right_col_width = COLS-left_col_width-middle_col_width-2;
right_col_startx = left_col_width+middle_col_width+2;
mEditorAlbums = new Menu<string_pair>(0, main_start_y, left_col_width, main_height, "Albums", Config.main_color, brNone);
mEditorAlbums->HighlightColor(Config.active_column_color);
mEditorAlbums->SetTimeout(ncmpcpp_window_timeout);
mEditorAlbums->SetItemDisplayer(Display::StringPairs);
mEditorDirs = new Menu<string_pair>(0, main_start_y, left_col_width, main_height, "Directories", Config.main_color, brNone);
mEditorDirs->HighlightColor(Config.active_column_color);
mEditorDirs->SetTimeout(ncmpcpp_window_timeout);
mEditorDirs->SetItemDisplayer(Display::StringPairs);
mEditorLeftCol = Config.albums_in_tag_editor ? mEditorAlbums : mEditorDirs;
mEditorTagTypes = new Menu<string>(middle_col_startx, main_start_y, middle_col_width, main_height, "Tag types", Config.main_color, brNone);
mEditorTagTypes->HighlightColor(Config.main_highlight_color);
mEditorTagTypes->SetTimeout(ncmpcpp_window_timeout);
mEditorTagTypes->SetItemDisplayer(Display::Generic);
mEditorTags = new Menu<Song>(right_col_startx, main_start_y, right_col_width, main_height, "Tags", Config.main_color, brNone);
mEditorTags->HighlightColor(Config.main_highlight_color);
mEditorTags->SetTimeout(ncmpcpp_window_timeout);
mEditorTags->SetSelectPrefix(&Config.selected_item_prefix);
mEditorTags->SetSelectSuffix(&Config.selected_item_suffix);
mEditorTags->SetItemDisplayer(Display::Tags);
mEditorTags->SetItemDisplayerUserData(mEditorTagTypes);
wTagEditorActiveCol = mEditorLeftCol;
}
void TagEditor::Resize()
{
left_col_width = COLS/2-middle_col_width/2;
middle_col_startx = left_col_width+1;
right_col_width = COLS-left_col_width-middle_col_width-2;
right_col_startx = left_col_width+middle_col_width+2;
mEditorAlbums->Resize(left_col_width, main_height);
mEditorDirs->Resize(left_col_width, main_height);
mEditorTagTypes->Resize(middle_col_width, main_height);
mEditorTags->Resize(right_col_width, main_height);
mEditorTagTypes->MoveTo(middle_col_startx, main_start_y);
mEditorTags->MoveTo(right_col_startx, main_start_y);
}
void TagEditor::Refresh()
{
mEditorLeftCol->Display();
mvvline(main_start_y, middle_col_startx-1, 0, main_height);
mEditorTagTypes->Display();
mvvline(main_start_y, right_col_startx-1, 0, main_height);
mEditorTags->Display();
}
void TagEditor::SwitchTo()
{
if (current_screen != csTagEditor && current_screen != csTinyTagEditor)
{
CLEAR_FIND_HISTORY;
mPlaylist->Hide(); // hack, should be wCurrent, but it doesn't always have 100% width
// redraw_screen = 1;
redraw_header = 1;
TagEditor::Refresh();
if (mEditorTagTypes->Empty())
{
mEditorTagTypes->AddOption("Title");
mEditorTagTypes->AddOption("Artist");
mEditorTagTypes->AddOption("Album");
mEditorTagTypes->AddOption("Year");
mEditorTagTypes->AddOption("Track");
mEditorTagTypes->AddOption("Genre");
mEditorTagTypes->AddOption("Composer");
mEditorTagTypes->AddOption("Performer");
mEditorTagTypes->AddOption("Disc");
mEditorTagTypes->AddOption("Comment");
mEditorTagTypes->AddSeparator();
mEditorTagTypes->AddOption("Filename");
mEditorTagTypes->AddSeparator();
mEditorTagTypes->AddOption("Options", 1, 1, 0);
mEditorTagTypes->AddSeparator();
mEditorTagTypes->AddOption("Reset");
mEditorTagTypes->AddOption("Save");
mEditorTagTypes->AddSeparator();
mEditorTagTypes->AddOption("Capitalize First Letters");
mEditorTagTypes->AddOption("lower all letters");
}
wCurrent = wTagEditorActiveCol;
current_screen = csTagEditor;
}
}
void TagEditor::Update()
{
if (mEditorLeftCol->Empty())
{
CLEAR_FIND_HISTORY;
mEditorLeftCol->Window::Clear();
mEditorTags->Clear();
TagList list;
if (Config.albums_in_tag_editor)
{
std::map<string, string, CaseInsensitiveSorting> maplist;
mEditorAlbums->WriteXY(0, 0, 0, "Fetching albums' list...");
Mpd->GetAlbums("", list);
for (TagList::const_iterator it = list.begin(); it != list.end(); it++)
{
SongList l;
Mpd->StartSearch(1);
Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, *it);
Mpd->CommitSearch(l);
if (!l.empty())
{
l[0]->Localize();
maplist[l[0]->toString(Config.tag_editor_album_format)] = *it;
}
FreeSongList(l);
}
for (std::map<string, string>::const_iterator it = maplist.begin(); it != maplist.end(); it++)
mEditorAlbums->AddOption(make_pair(it->first, it->second));
}
else
{
int highlightme = -1;
Mpd->GetDirectories(editor_browsed_dir, list);
sort(list.begin(), list.end(), CaseInsensitiveSorting());
if (editor_browsed_dir != "/")
{
size_t slash = editor_browsed_dir.rfind("/");
string parent = slash != string::npos ? editor_browsed_dir.substr(0, slash) : "/";
mEditorDirs->AddOption(make_pair("[..]", parent));
}
else
{
mEditorDirs->AddOption(make_pair(".", "/"));
}
for (TagList::const_iterator it = list.begin(); it != list.end(); it++)
{
size_t slash = it->rfind("/");
string to_display = slash != string::npos ? it->substr(slash+1) : *it;
utf_to_locale(to_display);
mEditorDirs->AddOption(make_pair(to_display, *it));
if (*it == editor_highlighted_dir)
highlightme = mEditorDirs->Size()-1;
}
if (highlightme != -1)
mEditorDirs->Highlight(highlightme);
}
mEditorLeftCol->Display();
mEditorTagTypes->Refresh();
}
if (mEditorTags->Empty())
{
mEditorTags->Reset();
SongList list;
if (Config.albums_in_tag_editor)
{
Mpd->StartSearch(1);
Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, mEditorAlbums->Current().second);
Mpd->CommitSearch(list);
sort(list.begin(), list.end(), CaseInsensitiveSorting());
for (SongList::iterator it = list.begin(); it != list.end(); it++)
{
(*it)->Localize();
mEditorTags->AddOption(**it);
}
}
else
{
Mpd->GetSongs(mEditorDirs->Current().second, list);
sort(list.begin(), list.end(), CaseInsensitiveSorting());
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
{
(*it)->Localize();
mEditorTags->AddOption(**it);
}
}
FreeSongList(list);
mEditorTags->Window::Clear();
mEditorTags->Refresh();
}
if (/*redraw_screen && */wCurrent == mEditorTagTypes && mEditorTagTypes->Choice() < 13)
{
mEditorTags->Refresh();
// redraw_screen = 0;
}
else if (mEditorTagTypes->Choice() >= 13)
mEditorTags->Window::Clear();
}
void TagEditor::EnterPressed()
{
if (wCurrent == mEditorDirs)
{
TagList test;
Mpd->GetDirectories(mEditorLeftCol->Current().second, test);
if (!test.empty())
{
editor_highlighted_dir = editor_browsed_dir;
editor_browsed_dir = mEditorLeftCol->Current().second;
mEditorLeftCol->Clear(0);
mEditorLeftCol->Reset();
}
else
ShowMessage("No subdirs found");
return;
}
if (mEditorTags->Empty()) // we need songs to deal with, don't we?
return;
// if there are selected songs, perform operations only on them
SongList list;
if (mEditorTags->hasSelected())
{
vector<size_t> selected;
mEditorTags->GetSelected(selected);
for (vector<size_t>::const_iterator it = selected.begin(); it != selected.end(); it++)
list.push_back(&mEditorTags->at(*it));
}
else
for (size_t i = 0; i < mEditorTags->Size(); i++)
list.push_back(&mEditorTags->at(i));
SongGetFunction get = 0;
SongSetFunction set = 0;
size_t id = mEditorTagTypes->RealChoice();
switch (id)
{
case 0:
get = &Song::GetTitle;
set = &Song::SetTitle;
break;
case 1:
get = &Song::GetArtist;
set = &Song::SetArtist;
break;
case 2:
get = &Song::GetAlbum;
set = &Song::SetAlbum;
break;
case 3:
get = &Song::GetYear;
set = &Song::SetYear;
break;
case 4:
get = &Song::GetTrack;
set = &Song::SetTrack;
if (wCurrent == mEditorTagTypes)
{
LockStatusbar();
Statusbar() << "Number tracks? [y/n] ";
curs_set(1);
int in = 0;
do
{
TraceMpdStatus();
wFooter->ReadKey(in);
}
while (in != 'y' && in != 'n');
if (in == 'y')
{
int i = 1;
for (SongList::iterator it = list.begin(); it != list.end(); it++, i++)
(*it)->SetTrack(i);
ShowMessage("Tracks numbered!");
}
else
ShowMessage("Aborted!");
curs_set(0);
UnlockStatusbar();
}
break;
case 5:
get = &Song::GetGenre;
set = &Song::SetGenre;
break;
case 6:
get = &Song::GetComposer;
set = &Song::SetComposer;
break;
case 7:
get = &Song::GetPerformer;
set = &Song::SetPerformer;
break;
case 8:
get = &Song::GetDisc;
set = &Song::SetDisc;
break;
case 9:
get = &Song::GetComment;
set = &Song::SetComment;
break;
case 10:
{
if (wCurrent == mEditorTagTypes)
{
current_screen = csOther;
__deal_with_filenames(list);
current_screen = csTagEditor;
TagEditor::Refresh();
}
else if (wCurrent == mEditorTags)
{
Song &s = mEditorTags->Current();
string old_name = s.GetNewName().empty() ? s.GetName() : s.GetNewName();
size_t last_dot = old_name.rfind(".");
string extension = old_name.substr(last_dot);
old_name = old_name.substr(0, last_dot);
LockStatusbar();
Statusbar() << fmtBold << "New filename: " << fmtBoldEnd;
string new_name = wFooter->GetString(old_name);
UnlockStatusbar();
if (!new_name.empty() && new_name != old_name)
s.SetNewName(new_name + extension);
mEditorTags->Scroll(wDown);
}
return;
}
case 11: // reset
{
mEditorTags->Clear(0);
ShowMessage("Changes reset");
return;
}
case 12: // save
{
bool success = 1;
ShowMessage("Writing changes...");
for (SongList::iterator it = list.begin(); it != list.end(); it++)
{
ShowMessage("Writing tags in '%s'...", (*it)->GetName().c_str());
if (!WriteTags(**it))
{
ShowMessage("Error writing tags in '%s'!", (*it)->GetFile().c_str());
success = 0;
break;
}
}
if (success)
{
ShowMessage("Tags updated!");
mEditorTagTypes->HighlightColor(Config.main_highlight_color);
mEditorTagTypes->Reset();
wCurrent->Refresh();
wCurrent = mEditorLeftCol;
mEditorLeftCol->HighlightColor(Config.active_column_color);
Mpd->UpdateDirectory(FindSharedDir(mEditorTags));
}
else
mEditorTags->Clear(0);
return;
}
case 13: // capitalize first letters
{
ShowMessage("Processing...");
for (SongList::iterator it = list.begin(); it != list.end(); it++)
CapitalizeFirstLetters(**it);
ShowMessage("Done!");
break;
}
case 14: // lower all letters
{
ShowMessage("Processing...");
for (SongList::iterator it = list.begin(); it != list.end(); it++)
LowerAllLetters(**it);
ShowMessage("Done!");
break;
}
default:
break;
}
if (wCurrent == mEditorTagTypes && id != 0 && id != 4 && set != NULL)
{
LockStatusbar();
Statusbar() << fmtBold << mEditorTagTypes->Current() << fmtBoldEnd << ": ";
string new_tag = wFooter->GetString((mEditorTags->Current().*get)());
UnlockStatusbar();
for (SongList::iterator it = list.begin(); it != list.end(); it++)
(**it.*set)(new_tag);
}
else if (wCurrent == mEditorTags && set != NULL)
{
LockStatusbar();
Statusbar() << fmtBold << mEditorTagTypes->Current() << fmtBoldEnd << ": ";
string new_tag = wFooter->GetString((mEditorTags->Current().*get)());
UnlockStatusbar();
if (new_tag != (mEditorTags->Current().*get)())
(mEditorTags->Current().*set)(new_tag);
mEditorTags->Scroll(wDown);
}
}
namespace
{
const string patterns_list_file = config_dir + "patterns.list";

View File

@@ -32,6 +32,25 @@
#include "mpdpp.h"
#include "settings.h"
namespace TinyTagEditor
{
void Init();
void EnterPressed(MPD::Song &);
}
namespace TagEditor
{
void Init();
void Resize();
void Refresh();
void SwitchTo();
void Update();
void EnterPressed();
}
typedef void (MPD::Song::*SongSetFunction)(const std::string &);
typedef std::string (MPD::Song::*SongGetFunction)() const;