Files
ncmpcpp/src/helpers.cpp

754 lines
18 KiB
C++

/***************************************************************************
* Copyright (C) 2008 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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "helpers.h"
#include "settings.h"
extern MPDConnection *Mpd;
extern ncmpcpp_config Config;
extern Menu *mBrowser;
extern Menu *mTagEditor;
extern Menu *mSearcher;
extern Window *wFooter;
extern SongList vPlaylist;
extern ItemList vBrowser;
extern NcmpcppScreen current_screen;
extern Song edited_song;
extern Song searched_song;
extern int block_statusbar_update_delay;
extern int browsed_dir_scroll_begin;
extern time_t block_delay;
extern string browsed_dir;
extern string browsed_subdir;
extern bool messages_allowed;
extern bool block_progressbar_update;
extern bool block_statusbar_update;
extern bool search_case_sensitive;
extern bool search_mode_match;
extern bool redraw_me;
extern string EMPTY_TAG;
extern string UNKNOWN_ARTIST;
extern string UNKNOWN_TITLE;
extern string UNKNOWN_ALBUM;
string DisplayKeys(int *key, int size)
{
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 += key[i]-216;
}
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 (int i = result.length(); i <= 12; result += " ", i++);
result += ": ";
return result;
}
bool Keypressed(int in, const int *key)
{
return in == key[0] || in == key[1];
}
bool SortSongsByTrack(Song *a, Song *b)
{
return StrToInt(a->GetTrack()) < StrToInt(b->GetTrack());
}
bool CaseInsensitiveComparison(string a, string b)
{
transform(a.begin(), a.end(), a.begin(), tolower);
transform(b.begin(), b.end(), b.begin(), tolower);
return a < b;
}
void WindowTitle(const string &status)
{
if (TERMINAL_TYPE != "linux" && Config.set_window_title)
printf("\033]0;%s\7",status.c_str());
}
string TotalPlaylistLength()
{
const int MINUTE = 60;
const int HOUR = 60*MINUTE;
const int DAY = 24*HOUR;
const int YEAR = 365*DAY;
string result;
int length = 0;
for (SongList::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
length += (*it)->GetTotalLength();
if (!length)
return result;
result += ", length: ";
int years = length/YEAR;
if (years)
{
result += IntoStr(years) + (years == 1 ? " year" : " years");
length -= years*YEAR;
if (length)
result += ", ";
}
int days = length/DAY;
if (days)
{
result += IntoStr(days) + (days == 1 ? " day" : " days");
length -= days*DAY;
if (length)
result += ", ";
}
int hours = length/HOUR;
if (hours)
{
result += IntoStr(hours) + (hours == 1 ? " hour" : " hours");
length -= hours*HOUR;
if (length)
result += ", ";
}
int minutes = length/MINUTE;
if (minutes)
{
result += IntoStr(minutes) + (minutes == 1 ? " minute" : " minutes");
length -= minutes*MINUTE;
if (length)
result += ", ";
}
if (length)
result += IntoStr(length) + (length == 1 ? " second" : " seconds");
return result;
}
string DisplaySong(const Song &s, const string &song_template)
{
string result;
bool link_tags = 0;
bool tags_present = 0;
int i = 0;
for (string::const_iterator it = song_template.begin(); it != song_template.end(); it++)
{
if (*it == '}')
{
if (!tags_present)
result = result.substr(0, result.length()-i);
it++;
link_tags = 0;
i = 0;
if (*it == '|' && *(it+1) == '{')
{
if (!tags_present)
it++;
else
while (*++it != '}');
}
}
if (*it == '}')
{
if (!tags_present)
result = result.substr(0, result.length()-i);
it++;
link_tags = 0;
i = 0;
if (*it == '|' && *(it+1) == '{')
{
if (!tags_present)
it++;
else
while (*it++ != '}');
}
}
if (*it == '{')
{
i = 0;
tags_present = 1;
link_tags = 1;
it++;
}
if (it == song_template.end())
break;
if (*it != '%')
{
i++;
result += *it;
}
else
{
switch (*++it)
{
case 'l':
{
if (link_tags)
{
if (s.GetTotalLength() > 0)
{
result += s.GetLength();
i += s.GetLength().length();
}
else
tags_present = 0;
}
else
result += s.GetLength();
break;
}
case 'F':
{
result += s.GetFile();
i += s.GetFile().length();
break;
}
case 'f':
{
result += s.GetShortFilename();
i += s.GetShortFilename().length();
break;
}
case 'a':
{
if (link_tags)
{
if (s.GetArtist() != UNKNOWN_ARTIST)
{
result += s.GetArtist();
i += s.GetArtist().length();
}
else
tags_present = 0;
}
else
result += s.GetArtist();
break;
}
case 'b':
{
if (link_tags)
{
if (s.GetAlbum() != UNKNOWN_ALBUM)
{
result += s.GetAlbum();
i += s.GetAlbum().length();
}
else
tags_present = 0;
}
else
result += s.GetAlbum();
break;
}
case 'y':
{
if (link_tags)
{
if (s.GetYear() != EMPTY_TAG)
{
result += s.GetYear();
i += s.GetYear().length();
}
else
tags_present = 0;
}
else
result += s.GetYear();
break;
}
case 'n':
{
if (link_tags)
{
if (s.GetTrack() != EMPTY_TAG)
{
result += s.GetTrack();
i += s.GetTrack().length();
}
else
tags_present = 0;
}
else
result += s.GetTrack();
break;
}
case 'g':
{
if (link_tags)
{
if (s.GetGenre() != EMPTY_TAG)
{
result += s.GetGenre();
i += s.GetGenre().length();
}
else
tags_present = 0;
}
else
result += s.GetGenre();
break;
}
case 'c':
{
if (link_tags)
{
if (s.GetComposer() != EMPTY_TAG)
{
result += s.GetComposer();
i += s.GetComposer().length();
}
else
tags_present = 0;
}
else
result += s.GetComposer();
break;
}
case 'p':
{
if (link_tags)
{
if (s.GetPerformer() != EMPTY_TAG)
{
result += s.GetPerformer();
i += s.GetPerformer().length();
}
else
tags_present = 0;
}
else
result += s.GetPerformer();
break;
}
case 'd':
{
if (link_tags)
{
if (s.GetDisc() != EMPTY_TAG)
{
result += s.GetDisc();
i += s.GetDisc().length();
}
else
tags_present = 0;
}
else
result += s.GetDisc();
break;
}
case 'C':
{
if (link_tags)
{
if (s.GetComment() != EMPTY_TAG)
{
result += s.GetComment();
i += s.GetComment().length();
}
else
tags_present = 0;
}
else
result += s.GetComment();
break;
}
case 't':
{
if (link_tags)
{
if (s.GetTitle() != UNKNOWN_TITLE)
{
result += s.GetTitle();
i += s.GetTitle().length();
}
else
tags_present = 0;
}
else
result += s.GetTitle();
break;
}
}
}
}
return result;
}
void PrepareSearchEngine(Song &s)
{
s.Clear();
mSearcher->Clear();
mSearcher->Reset();
mSearcher->AddOption("[b]Filename:[/b] " + s.GetShortFilename());
mSearcher->AddOption("[b]Title:[/b] " + s.GetTitle());
mSearcher->AddOption("[b]Artist:[/b] " + s.GetArtist());
mSearcher->AddOption("[b]Album:[/b] " + s.GetAlbum());
mSearcher->AddOption("[b]Year:[/b] " + s.GetYear());
mSearcher->AddOption("[b]Track:[/b] " + s.GetTrack());
mSearcher->AddOption("[b]Genre:[/b] " + s.GetGenre());
mSearcher->AddOption("[b]Comment:[/b] " + s.GetComment());
mSearcher->AddSeparator();
mSearcher->AddOption("[b]Search mode:[/b] " + (search_mode_match ? search_mode_one : search_mode_two));
mSearcher->AddOption("[b]Case sensitive:[/b] " + (string)(search_case_sensitive ? "Yes" : "No"));
mSearcher->AddSeparator();
mSearcher->AddOption("Search");
mSearcher->AddOption("Reset");
}
void Search(SongList &result, Song &s)
{
FreeSongList(result);
if (s.Empty())
return;
SongList list;
Mpd->GetDirectoryRecursive("/", list);
bool found = 1;
s.GetEmptyFields(1);
if (!search_case_sensitive)
{
string t;
t = s.GetShortFilename();
transform(t.begin(), t.end(), t.begin(), tolower);
s.SetShortFilename(t);
t = s.GetTitle();
transform(t.begin(), t.end(), t.begin(), tolower);
s.SetTitle(t);
t = s.GetArtist();
transform(t.begin(), t.end(), t.begin(), tolower);
s.SetArtist(t);
t = s.GetAlbum();
transform(t.begin(), t.end(), t.begin(), tolower);
s.SetAlbum(t);
t = s.GetGenre();
transform(t.begin(), t.end(), t.begin(), tolower);
s.SetGenre(t);
t = s.GetComment();
transform(t.begin(), t.end(), t.begin(), tolower);
s.SetComment(t);
}
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
{
Song copy = **it;
if (!search_case_sensitive)
{
string t;
t = copy.GetShortFilename();
transform(t.begin(), t.end(), t.begin(), tolower);
copy.SetShortFilename(t);
t = copy.GetTitle();
transform(t.begin(), t.end(), t.begin(), tolower);
copy.SetTitle(t);
t = copy.GetArtist();
transform(t.begin(), t.end(), t.begin(), tolower);
copy.SetArtist(t);
t = copy.GetAlbum();
transform(t.begin(), t.end(), t.begin(), tolower);
copy.SetAlbum(t);
t = copy.GetGenre();
transform(t.begin(), t.end(), t.begin(), tolower);
copy.SetGenre(t);
t = copy.GetComment();
transform(t.begin(), t.end(), t.begin(), tolower);
copy.SetComment(t);
}
if (search_mode_match)
{
if (found && !s.GetShortFilename().empty())
found = copy.GetShortFilename().find(s.GetShortFilename()) != string::npos;
if (found && !s.GetTitle().empty())
found = copy.GetTitle().find(s.GetTitle()) != string::npos;
if (found && !s.GetArtist().empty())
found = copy.GetArtist().find(s.GetArtist()) != string::npos;
if (found && !s.GetAlbum().empty())
found = copy.GetAlbum().find(s.GetAlbum()) != string::npos;
if (found && !s.GetYear().empty())
found = atoi(copy.GetYear().c_str()) == atoi(s.GetYear().c_str()) && atoi(s.GetYear().c_str());
if (found && !s.GetTrack().empty())
found = atoi(copy.GetTrack().c_str()) == atoi(s.GetTrack().c_str()) && atoi(s.GetTrack().c_str());
if (found && !s.GetGenre().empty())
found = copy.GetGenre().find(s.GetGenre()) != string::npos;
if (found && !s.GetComment().empty())
found = copy.GetComment().find(s.GetComment()) != string::npos;
}
else
{
if (found && !s.GetShortFilename().empty())
found = copy.GetShortFilename() == s.GetShortFilename();
if (found && !s.GetTitle().empty())
found = copy.GetTitle() == s.GetTitle();
if (found && !s.GetArtist().empty())
found = copy.GetArtist() == s.GetArtist();
if (found && !s.GetAlbum().empty())
found = copy.GetAlbum() == s.GetAlbum();
if (found && !s.GetYear().empty())
found = atoi(copy.GetYear().c_str()) == atoi(s.GetYear().c_str()) && atoi(s.GetYear().c_str());
if (found && !s.GetTrack().empty())
found = atoi(copy.GetTrack().c_str()) == atoi(s.GetTrack().c_str()) && atoi(s.GetTrack().c_str());
if (found && !s.GetGenre().empty())
found = copy.GetGenre() == s.GetGenre();
if (found && !s.GetComment().empty())
found = copy.GetComment() == s.GetComment();
}
if (found)
{
Song *ss = new Song(**it);
result.push_back(ss);
}
found = 1;
}
FreeSongList(list);
s.GetEmptyFields(0);
}
void ShowMessage(const string &message, int delay)
{
if (messages_allowed)
{
block_delay = time(NULL);
block_statusbar_update_delay = delay;
if (Config.statusbar_visibility)
block_statusbar_update = 1;
else
block_progressbar_update = 1;
wFooter->Bold(0);
wFooter->WriteXY(0, Config.statusbar_visibility, message, 1);
wFooter->Bold(1);
}
}
bool GetSongInfo(Song &s)
{
string path_to_file = Config.mpd_music_dir + "/" + s.GetFile();
# ifdef HAVE_TAGLIB_H
TagLib::FileRef f(path_to_file.c_str());
if (f.isNull())
return false;
s.SetComment(f.tag()->comment().to8Bit(UNICODE));
# endif
mTagEditor->Clear();
mTagEditor->Reset();
mTagEditor->AddStaticOption("[b][white]Song name: [green][/b]" + s.GetShortFilename());
mTagEditor->AddStaticOption("[b][white]Location in DB: [green][/b]" + s.GetDirectory());
mTagEditor->AddStaticOption("");
mTagEditor->AddStaticOption("[b][white]Length: [green][/b]" + s.GetLength() + "[/green]");
# ifdef HAVE_TAGLIB_H
mTagEditor->AddStaticOption("[b][white]Bitrate: [green][/b]" + IntoStr(f.audioProperties()->bitrate()) + " kbps");
mTagEditor->AddStaticOption("[b][white]Sample rate: [green][/b]" + IntoStr(f.audioProperties()->sampleRate()) + " Hz");
mTagEditor->AddStaticOption("[b][white]Channels: [green][/b]" + (string)(f.audioProperties()->channels() == 1 ? "Mono" : "Stereo") + "[/green]");
# endif
mTagEditor->AddSeparator();
# ifdef HAVE_TAGLIB_H
mTagEditor->AddOption("[b]Title:[/b] " + s.GetTitle());
mTagEditor->AddOption("[b]Artist:[/b] " + s.GetArtist());
mTagEditor->AddOption("[b]Album:[/b] " + s.GetAlbum());
mTagEditor->AddOption("[b]Year:[/b] " + s.GetYear());
mTagEditor->AddOption("[b]Track:[/b] " + s.GetTrack());
mTagEditor->AddOption("[b]Genre:[/b] " + s.GetGenre());
mTagEditor->AddOption("[b]Comment:[/b] " + s.GetComment());
mTagEditor->AddSeparator();
mTagEditor->AddOption("Save");
mTagEditor->AddOption("Cancel");
# else
mTagEditor->AddStaticOption("[b]Title:[/b] " + s.GetTitle());
mTagEditor->AddStaticOption("[b]Artist:[/b] " + s.GetArtist());
mTagEditor->AddStaticOption("[b]Album:[/b] " + s.GetAlbum());
mTagEditor->AddStaticOption("[b]Year:[/b] " + s.GetYear());
mTagEditor->AddStaticOption("[b]Track:[/b] " + s.GetTrack());
mTagEditor->AddStaticOption("[b]Genre:[/b] " + s.GetGenre());
mTagEditor->AddStaticOption("[b]Comment:[/b] " + s.GetComment());
mTagEditor->AddSeparator();
mTagEditor->AddOption("Back");
# endif
edited_song = s;
return true;
}
bool SortDirectory(const Item &a, const Item &b)
{
if (a.type == b.type)
{
string sa = a.type == itSong ? a.song->GetShortFilename() : a.name;
string sb = b.type == itSong ? b.song->GetShortFilename() : b.name;
transform(sa.begin(), sa.end(), sa.begin(), tolower);
transform(sb.begin(), sb.end(), sb.begin(), tolower);
return sa < sb;
}
else
return a.type < b.type;
}
void GetDirectory(string dir)
{
int highlightme = -1;
browsed_dir_scroll_begin = 0;
if (browsed_dir != dir)
mBrowser->Reset();
browsed_dir = dir;
vBrowser.clear();
mBrowser->Clear(0);
if (dir != "/")
{
mBrowser->AddOption("[..]");
Item parent;
parent.type = itDirectory;
vBrowser.push_back(parent);
}
Mpd->GetDirectory(dir, vBrowser);
sort(vBrowser.begin(), vBrowser.end(), SortDirectory);
for (ItemList::iterator it = vBrowser.begin()+(dir != "/" ? 1 : 0); it != vBrowser.end(); it++)
{
switch (it->type)
{
case itPlaylist:
{
mBrowser->AddOption(Config.browser_playlist_prefix + string(it->name));
break;
}
case itDirectory:
{
string directory;
string subdir = it->name;
if (dir == "/")
directory = subdir.substr(browsed_dir.size()-1,subdir.size()-browsed_dir.size()+1);
else
directory = subdir.substr(browsed_dir.size()+1,subdir.size()-browsed_dir.size()-1);
mBrowser->AddOption("[" + directory + "]");
if (directory == browsed_subdir)
highlightme = mBrowser->MaxChoice();
it->name = directory;
break;
}
case itSong:
{
Song *s = it->song;
bool bold = 0;
for (SongList::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
{
if ((*it)->GetHash() == s->GetHash())
{
bold = 1;
break;
}
}
bold ? mBrowser->AddBoldOption(DisplaySong(*s)) : mBrowser->AddOption(DisplaySong(*s));
break;
}
}
}
mBrowser->Highlight(highlightme);
browsed_subdir.clear();
if (current_screen == csBrowser)
mBrowser->Hide();
}