add support for browsing local filesystem
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
bin_PROGRAMS = ncmpcpp
|
bin_PROGRAMS = ncmpcpp
|
||||||
ncmpcpp_SOURCES = color_parser.cpp help.cpp helpers.cpp libmpdclient.c \
|
ncmpcpp_SOURCES = browser.cpp color_parser.cpp help.cpp helpers.cpp \
|
||||||
lyrics.cpp menu.cpp misc.cpp mpdpp.cpp ncmpcpp.cpp scrollpad.cpp search_engine.cpp \
|
libmpdclient.c lyrics.cpp menu.cpp misc.cpp mpdpp.cpp ncmpcpp.cpp scrollpad.cpp \
|
||||||
settings.cpp song.cpp status_checker.cpp str_pool.c tag_editor.cpp window.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
|
# set the include path found by configure
|
||||||
INCLUDES= $(all_includes)
|
INCLUDES= $(all_includes)
|
||||||
|
|
||||||
# the library search path.
|
# the library search path.
|
||||||
ncmpcpp_LDFLAGS = $(all_libraries)
|
ncmpcpp_LDFLAGS = $(all_libraries)
|
||||||
noinst_HEADERS = help.h helpers.h lyrics.h menu.h mpdpp.h scrollpad.h \
|
noinst_HEADERS = browser.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
|
search_engine.h settings.h song.h status_checker.h tag_editor.h window.h
|
||||||
|
|||||||
211
src/browser.cpp
Normal file
211
src/browser.cpp
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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 <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "browser.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#ifdef HAVE_TAGLIB_H
|
||||||
|
# include "tag_editor.h"
|
||||||
|
#endif // HAVE_TAGLIB_H
|
||||||
|
|
||||||
|
extern MPDConnection *Mpd;
|
||||||
|
|
||||||
|
extern ncmpcpp_config Config;
|
||||||
|
|
||||||
|
extern Menu<Song> *mPlaylist;
|
||||||
|
extern Menu<Item> *mBrowser;
|
||||||
|
|
||||||
|
extern NcmpcppScreen current_screen;
|
||||||
|
|
||||||
|
extern string browsed_dir;
|
||||||
|
|
||||||
|
extern int browsed_dir_scroll_begin;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const string supported_extensions[] = { "wma", "asf", "rm", "mp1", "mp2", "mp3", "mp4", "m4a", "flac", "ogg", "wav", "au", "aiff", "aif", "ac3", "aac", "mpc", "it", "mod", "s3m", "xm", "wv", "." };
|
||||||
|
|
||||||
|
bool hasSupportedExtension(const string &file)
|
||||||
|
{
|
||||||
|
unsigned int last_dot = file.find_last_of(".");
|
||||||
|
if (last_dot > file.length())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string ext = file.substr(last_dot+1);
|
||||||
|
for (int i = 0; supported_extensions[i] != "."; i++)
|
||||||
|
if (ext == supported_extensions[i])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetLocalDirectory(const string &dir, ItemList &v)
|
||||||
|
{
|
||||||
|
dirent **list;
|
||||||
|
int n = scandir(dir.c_str(), &list, NULL, alphasort);
|
||||||
|
if (n < 2)
|
||||||
|
{
|
||||||
|
delete list;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct stat file_stat;
|
||||||
|
string full_path;
|
||||||
|
for (int i = 2; i < n; i++)
|
||||||
|
{
|
||||||
|
Item new_item;
|
||||||
|
full_path = dir;
|
||||||
|
if (dir != "/")
|
||||||
|
full_path += "/";
|
||||||
|
full_path += list[i]->d_name;
|
||||||
|
stat(full_path.c_str(), &file_stat);
|
||||||
|
if (S_ISDIR(file_stat.st_mode))
|
||||||
|
{
|
||||||
|
new_item.type = itDirectory;
|
||||||
|
new_item.name = full_path;
|
||||||
|
v.push_back(new_item);
|
||||||
|
}
|
||||||
|
else if (hasSupportedExtension(list[i]->d_name))
|
||||||
|
{
|
||||||
|
new_item.type = itSong;
|
||||||
|
mpd_Song *s = mpd_newSong();
|
||||||
|
s->file = str_pool_get(full_path.c_str());
|
||||||
|
# ifdef HAVE_TAGLIB_H
|
||||||
|
ReadTagsFromFile(s);
|
||||||
|
# endif // HAVE_TAGLIB_H
|
||||||
|
new_item.song = new Song(s);
|
||||||
|
v.push_back(new_item);
|
||||||
|
}
|
||||||
|
delete list[i];
|
||||||
|
}
|
||||||
|
delete list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateItemList(Menu<Item> *menu)
|
||||||
|
{
|
||||||
|
bool bold = 0;
|
||||||
|
for (int i = 0; i < menu->Size(); i++)
|
||||||
|
{
|
||||||
|
if (menu->at(i).type == itSong)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < mPlaylist->Size(); j++)
|
||||||
|
{
|
||||||
|
if (mPlaylist->at(j).GetHash() == menu->at(i).song->GetHash())
|
||||||
|
{
|
||||||
|
bold = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu->BoldOption(i, bold);
|
||||||
|
bold = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu->Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
string DisplayItem(const Item &item, void *, const Menu<Item> *menu)
|
||||||
|
{
|
||||||
|
switch (item.type)
|
||||||
|
{
|
||||||
|
case itDirectory:
|
||||||
|
{
|
||||||
|
if (item.song)
|
||||||
|
return "[..]";
|
||||||
|
int slash = item.name.find_last_of("/");
|
||||||
|
return "[" + (slash != string::npos ? item.name.substr(slash+1) : item.name) + "]";
|
||||||
|
}
|
||||||
|
case itSong:
|
||||||
|
// I know casting that way is ugly etc., but it works.
|
||||||
|
return DisplaySong(*item.song, &Config.song_list_format, (const Menu<Song> *)menu);
|
||||||
|
case itPlaylist:
|
||||||
|
return Config.browser_playlist_prefix + item.name;
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetDirectory(string dir, string subdir)
|
||||||
|
{
|
||||||
|
if (dir.empty())
|
||||||
|
dir = "/";
|
||||||
|
|
||||||
|
int highlightme = -1;
|
||||||
|
browsed_dir_scroll_begin = 0;
|
||||||
|
if (browsed_dir != dir)
|
||||||
|
mBrowser->Reset();
|
||||||
|
browsed_dir = dir;
|
||||||
|
mBrowser->Clear(0);
|
||||||
|
|
||||||
|
if (dir != "/")
|
||||||
|
{
|
||||||
|
Item parent;
|
||||||
|
int slash = dir.find_last_of("/");
|
||||||
|
parent.song = (Song *) 1; // in that way we assume that's really parent dir
|
||||||
|
parent.name = slash != string::npos ? dir.substr(0, slash) : "/";
|
||||||
|
parent.type = itDirectory;
|
||||||
|
mBrowser->AddOption(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemList list;
|
||||||
|
Config.local_browser ? GetLocalDirectory(dir, list) : Mpd->GetDirectory(dir, list);
|
||||||
|
sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
||||||
|
|
||||||
|
for (ItemList::iterator it = list.begin(); it != list.end(); it++)
|
||||||
|
{
|
||||||
|
switch (it->type)
|
||||||
|
{
|
||||||
|
case itPlaylist:
|
||||||
|
{
|
||||||
|
mBrowser->AddOption(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case itDirectory:
|
||||||
|
{
|
||||||
|
if (it->name == subdir)
|
||||||
|
highlightme = mBrowser->Size();
|
||||||
|
mBrowser->AddOption(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case itSong:
|
||||||
|
{
|
||||||
|
bool bold = 0;
|
||||||
|
for (int i = 0; i < mPlaylist->Size(); i++)
|
||||||
|
{
|
||||||
|
if (mPlaylist->at(i).GetHash() == it->song->GetHash())
|
||||||
|
{
|
||||||
|
bold = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mBrowser->AddOption(*it, bold);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mBrowser->Highlight(highlightme);
|
||||||
|
|
||||||
|
if (current_screen == csBrowser)
|
||||||
|
mBrowser->Hide();
|
||||||
|
}
|
||||||
|
|
||||||
34
src/browser.h
Normal file
34
src/browser.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef HAVE_BROWSER_H
|
||||||
|
#define HAVE_BROWSER_H
|
||||||
|
|
||||||
|
#include "mpdpp.h"
|
||||||
|
#include "ncmpcpp.h"
|
||||||
|
|
||||||
|
void UpdateItemList(Menu<Item> *);
|
||||||
|
|
||||||
|
string DisplayItem(const Item &, void *, const Menu<Item> *);
|
||||||
|
|
||||||
|
void GetDirectory(string, string = "/");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -18,9 +18,13 @@
|
|||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "mpdpp.h"
|
||||||
|
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
|
extern MPDConnection *Mpd;
|
||||||
|
|
||||||
extern ncmpcpp_keys Key;
|
extern ncmpcpp_keys Key;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -165,6 +169,8 @@ string GetKeybindings()
|
|||||||
result += " [.b]Keys - Browse screen\n -----------------------------------------[/b]\n";
|
result += " [.b]Keys - Browse screen\n -----------------------------------------[/b]\n";
|
||||||
result += DisplayKeys(Key.Enter) + "Enter directory/Add item to playlist and play\n";
|
result += DisplayKeys(Key.Enter) + "Enter directory/Add item to playlist and play\n";
|
||||||
result += DisplayKeys(Key.Space) + "Add item to playlist\n";
|
result += DisplayKeys(Key.Space) + "Add item to playlist\n";
|
||||||
|
if (Mpd->GetHostname()[0] == '/') // are we connected to unix socket?
|
||||||
|
result += DisplayKeys(Key.SwitchTagTypeList) + "Browse MPD database/local filesystem\n";
|
||||||
result += DisplayKeys(Key.GoToParentDir) + "Go to parent directory\n";
|
result += DisplayKeys(Key.GoToParentDir) + "Go to parent directory\n";
|
||||||
result += DisplayKeys(Key.Delete) + "Delete playlist\n\n\n";
|
result += DisplayKeys(Key.Delete) + "Delete playlist\n\n\n";
|
||||||
|
|
||||||
|
|||||||
113
src/helpers.cpp
113
src/helpers.cpp
@@ -35,12 +35,9 @@ extern Window *wFooter;
|
|||||||
extern NcmpcppScreen current_screen;
|
extern NcmpcppScreen current_screen;
|
||||||
|
|
||||||
extern int lock_statusbar_delay;
|
extern int lock_statusbar_delay;
|
||||||
extern int browsed_dir_scroll_begin;
|
|
||||||
|
|
||||||
extern time_t time_of_statusbar_lock;
|
extern time_t time_of_statusbar_lock;
|
||||||
|
|
||||||
extern string browsed_dir;
|
|
||||||
|
|
||||||
extern bool messages_allowed;
|
extern bool messages_allowed;
|
||||||
extern bool block_progressbar_update;
|
extern bool block_progressbar_update;
|
||||||
extern bool block_statusbar_update;
|
extern bool block_statusbar_update;
|
||||||
@@ -220,28 +217,6 @@ bool CaseInsensitiveSorting::operator()(const Item &a, const Item &b)
|
|||||||
return a.type < b.type;
|
return a.type < b.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateItemList(Menu<Item> *menu)
|
|
||||||
{
|
|
||||||
bool bold = 0;
|
|
||||||
for (int i = 0; i < menu->Size(); i++)
|
|
||||||
{
|
|
||||||
if (menu->at(i).type == itSong)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < mPlaylist->Size(); j++)
|
|
||||||
{
|
|
||||||
if (mPlaylist->at(j).GetHash() == menu->at(i).song->GetHash())
|
|
||||||
{
|
|
||||||
bold = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu->BoldOption(i, bold);
|
|
||||||
bold = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu->Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateSongList(Menu<Song> *menu)
|
void UpdateSongList(Menu<Song> *menu)
|
||||||
{
|
{
|
||||||
bool bold = 0;
|
bool bold = 0;
|
||||||
@@ -395,27 +370,6 @@ string DisplayStringPair(const StringPair &pair, void *, const Menu<StringPair>
|
|||||||
return pair.first;
|
return pair.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
string DisplayItem(const Item &item, void *, const Menu<Item> *menu)
|
|
||||||
{
|
|
||||||
switch (item.type)
|
|
||||||
{
|
|
||||||
case itDirectory:
|
|
||||||
{
|
|
||||||
if (item.song)
|
|
||||||
return "[..]";
|
|
||||||
int slash = item.name.find_last_of("/");
|
|
||||||
return "[" + (slash != string::npos ? item.name.substr(slash+1) : item.name) + "]";
|
|
||||||
}
|
|
||||||
case itSong:
|
|
||||||
// I know casting that way is ugly etc., but it works.
|
|
||||||
return DisplaySong(*item.song, &Config.song_list_format, (const Menu<Song> *)menu);
|
|
||||||
case itPlaylist:
|
|
||||||
return Config.browser_playlist_prefix + item.name;
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string DisplayColumns(string song_template)
|
string DisplayColumns(string song_template)
|
||||||
{
|
{
|
||||||
vector<string> cols;
|
vector<string> cols;
|
||||||
@@ -577,7 +531,11 @@ string DisplaySongInColumns(const Song &s, void *s_template, const Menu<Song> *)
|
|||||||
v = TO_WSTRING(Window::OmitBBCodes(ss)).substr(0, width-1);
|
v = TO_WSTRING(Window::OmitBBCodes(ss)).substr(0, width-1);
|
||||||
for (int i = v.length(); i < width; i++, v += space) { }
|
for (int i = v.length(); i < width; i++, v += space) { }
|
||||||
if (!color.empty())
|
if (!color.empty())
|
||||||
result += open_col + color + close_col;
|
{
|
||||||
|
result += open_col;
|
||||||
|
result += color;
|
||||||
|
result += close_col;
|
||||||
|
}
|
||||||
result += v;
|
result += v;
|
||||||
if (!color.empty())
|
if (!color.empty())
|
||||||
result += close_col2;
|
result += close_col2;
|
||||||
@@ -913,64 +871,3 @@ void ShowMessage(const string &message, int delay)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetDirectory(string dir, string subdir)
|
|
||||||
{
|
|
||||||
int highlightme = -1;
|
|
||||||
browsed_dir_scroll_begin = 0;
|
|
||||||
if (browsed_dir != dir)
|
|
||||||
mBrowser->Reset();
|
|
||||||
browsed_dir = dir;
|
|
||||||
mBrowser->Clear(0);
|
|
||||||
|
|
||||||
if (dir != "/")
|
|
||||||
{
|
|
||||||
Item parent;
|
|
||||||
int slash = dir.find_last_of("/");
|
|
||||||
parent.song = (Song *) 1; // in that way we assume that's really parent dir
|
|
||||||
parent.name = slash != string::npos ? dir.substr(0, slash) : "/";
|
|
||||||
parent.type = itDirectory;
|
|
||||||
mBrowser->AddOption(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemList list;
|
|
||||||
Mpd->GetDirectory(dir, list);
|
|
||||||
sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
|
||||||
|
|
||||||
for (ItemList::iterator it = list.begin(); it != list.end(); it++)
|
|
||||||
{
|
|
||||||
switch (it->type)
|
|
||||||
{
|
|
||||||
case itPlaylist:
|
|
||||||
{
|
|
||||||
mBrowser->AddOption(*it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case itDirectory:
|
|
||||||
{
|
|
||||||
if (it->name == subdir)
|
|
||||||
highlightme = mBrowser->Size();
|
|
||||||
mBrowser->AddOption(*it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case itSong:
|
|
||||||
{
|
|
||||||
bool bold = 0;
|
|
||||||
for (int i = 0; i < mPlaylist->Size(); i++)
|
|
||||||
{
|
|
||||||
if (mPlaylist->at(i).GetHash() == it->song->GetHash())
|
|
||||||
{
|
|
||||||
bold = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mBrowser->AddOption(*it, bold);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mBrowser->Highlight(highlightme);
|
|
||||||
|
|
||||||
if (current_screen == csBrowser)
|
|
||||||
mBrowser->Hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ class CaseInsensitiveSorting
|
|||||||
|
|
||||||
bool SortSongsByTrack(Song *, Song *);
|
bool SortSongsByTrack(Song *, Song *);
|
||||||
|
|
||||||
void UpdateItemList(Menu<Item> *);
|
|
||||||
void UpdateSongList(Menu<Song> *);
|
void UpdateSongList(Menu<Song> *);
|
||||||
|
|
||||||
bool Keypressed(int, const int *);
|
bool Keypressed(int, const int *);
|
||||||
@@ -55,13 +54,11 @@ string IntoStr(mpd_TagItems);
|
|||||||
string FindSharedDir(const string &, const string &);
|
string FindSharedDir(const string &, const string &);
|
||||||
string TotalPlaylistLength();
|
string TotalPlaylistLength();
|
||||||
string DisplayStringPair(const StringPair &, void *, const Menu<StringPair> *);
|
string DisplayStringPair(const StringPair &, void *, const Menu<StringPair> *);
|
||||||
string DisplayItem(const Item &, void *, const Menu<Item> *);
|
|
||||||
string DisplayColumns(string);
|
string DisplayColumns(string);
|
||||||
string DisplaySongInColumns(const Song &, void *, const Menu<Song> *);
|
string DisplaySongInColumns(const Song &, void *, const Menu<Song> *);
|
||||||
string DisplaySong(const Song &, void * = &Config.song_list_format, const Menu<Song> * = NULL);
|
string DisplaySong(const Song &, void * = &Config.song_list_format, const Menu<Song> * = NULL);
|
||||||
string GetInfo(Song &);
|
string GetInfo(Song &);
|
||||||
void ShowMessage(const string &, int = Config.message_delay_time);
|
void ShowMessage(const string &, int = Config.message_delay_time);
|
||||||
void GetDirectory(string, string = "/");
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,14 @@
|
|||||||
|
|
||||||
const string playlist_max_message = "playlist is at the max size";
|
const string playlist_max_message = "playlist is at the max size";
|
||||||
|
|
||||||
MPDConnection::MPDConnection() : isConnected(0), itsErrorCode(0), itsMaxPlaylistLength(-1), MPD_HOST("localhost"), MPD_PORT(6600), MPD_TIMEOUT(15), itsUpdater(0), itsErrorHandler(0)
|
MPDConnection::MPDConnection() : isConnected(0),
|
||||||
|
itsErrorCode(0),
|
||||||
|
itsMaxPlaylistLength(-1),
|
||||||
|
MPD_HOST("localhost"),
|
||||||
|
MPD_PORT(6600),
|
||||||
|
MPD_TIMEOUT(15),
|
||||||
|
itsUpdater(0),
|
||||||
|
itsErrorHandler(0)
|
||||||
{
|
{
|
||||||
itsConnection = 0;
|
itsConnection = 0;
|
||||||
itsCurrentStats = 0;
|
itsCurrentStats = 0;
|
||||||
@@ -467,7 +474,7 @@ int MPDConnection::AddSong(const string &path)
|
|||||||
|
|
||||||
int MPDConnection::AddSong(const Song &s)
|
int MPDConnection::AddSong(const Song &s)
|
||||||
{
|
{
|
||||||
return !s.Empty() ? AddSong(s.GetFile()) : -1;
|
return !s.Empty() ? (s.IsFromDB() ? AddSong(s.GetFile()) : AddSong("file://" + s.GetFile())) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPDConnection::QueueAddSong(const string &path)
|
void MPDConnection::QueueAddSong(const string &path)
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ class MPDConnection
|
|||||||
bool Connected() const;
|
bool Connected() const;
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
|
|
||||||
|
const string & GetHostname() { return MPD_HOST; }
|
||||||
|
int GetPort() { return MPD_PORT; }
|
||||||
|
|
||||||
void SetHostname(const string &);
|
void SetHostname(const string &);
|
||||||
void SetPort(int port) { MPD_PORT = port; }
|
void SetPort(int port) { MPD_PORT = port; }
|
||||||
void SetTimeout(int timeout) { MPD_TIMEOUT = timeout; }
|
void SetTimeout(int timeout) { MPD_TIMEOUT = timeout; }
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "mpdpp.h"
|
#include "mpdpp.h"
|
||||||
#include "ncmpcpp.h"
|
#include "ncmpcpp.h"
|
||||||
|
|
||||||
|
#include "browser.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "lyrics.h"
|
#include "lyrics.h"
|
||||||
@@ -923,7 +924,7 @@ int main(int argc, char *argv[])
|
|||||||
if (wCurrent == mBrowser && browsed_dir != "/")
|
if (wCurrent == mBrowser && browsed_dir != "/")
|
||||||
{
|
{
|
||||||
mBrowser->Reset();
|
mBrowser->Reset();
|
||||||
goto GO_TO_PARENT_DIR;
|
goto ENTER_BROWSER_SCREEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.Enter))
|
else if (Keypressed(input, Key.Enter))
|
||||||
@@ -938,7 +939,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
case csBrowser:
|
case csBrowser:
|
||||||
{
|
{
|
||||||
GO_TO_PARENT_DIR:
|
ENTER_BROWSER_SCREEN:
|
||||||
|
|
||||||
const Item &item = mBrowser->Current();
|
const Item &item = mBrowser->Current();
|
||||||
switch (item.type)
|
switch (item.type)
|
||||||
@@ -1135,7 +1136,12 @@ int main(int argc, char *argv[])
|
|||||||
mSearcher->Current().second = s;
|
mSearcher->Current().second = s;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mPlaylist->Current() = s;
|
{
|
||||||
|
if (wPrev == mPlaylist)
|
||||||
|
mPlaylist->Current() = s;
|
||||||
|
else if (wPrev == mBrowser)
|
||||||
|
*mBrowser->Current().song = s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ShowMessage("Error writing tags!");
|
ShowMessage("Error writing tags!");
|
||||||
@@ -2025,7 +2031,8 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
Mpd->DeletePlaylist(name);
|
Mpd->DeletePlaylist(name);
|
||||||
ShowMessage("Playlist " + name + " deleted!");
|
ShowMessage("Playlist " + name + " deleted!");
|
||||||
GetDirectory("/");
|
if (!Config.local_browser)
|
||||||
|
GetDirectory("/");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ShowMessage("Aborted!");
|
ShowMessage("Aborted!");
|
||||||
@@ -2122,7 +2129,7 @@ int main(int argc, char *argv[])
|
|||||||
UnlockStatusbar();
|
UnlockStatusbar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (browsed_dir == "/" && !mBrowser->Empty())
|
if (!Config.local_browser && browsed_dir == "/" && !mBrowser->Empty())
|
||||||
GetDirectory(browsed_dir);
|
GetDirectory(browsed_dir);
|
||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.Stop))
|
else if (Keypressed(input, Key.Stop))
|
||||||
@@ -2653,27 +2660,6 @@ int main(int argc, char *argv[])
|
|||||||
ShowMessage("Cannot rename '" + full_old_dir + "' to '" + full_new_dir + "'!");
|
ShowMessage("Cannot rename '" + full_old_dir + "' to '" + full_new_dir + "'!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// blah, this key is already reserved for TagEditor. I'll merge this to its screen later.
|
|
||||||
/*else if (wCurrent == mBrowser && mBrowser->Current().type == itSong)
|
|
||||||
{
|
|
||||||
string old_name = mBrowser->Current().song->GetFile();
|
|
||||||
LockStatusbar();
|
|
||||||
wFooter->WriteXY(0, Config.statusbar_visibility, "[.b]Filename:[/b] ", 1);
|
|
||||||
string new_name = wFooter->GetString(old_name);
|
|
||||||
UnlockStatusbar();
|
|
||||||
if (!new_name.empty() && new_name != old_name)
|
|
||||||
{
|
|
||||||
string full_old_name = Config.mpd_music_dir + old_name;
|
|
||||||
string full_new_name = Config.mpd_music_dir + new_name;
|
|
||||||
if (rename(full_old_name.c_str(), full_new_name.c_str()) == 0)
|
|
||||||
{
|
|
||||||
Mpd->UpdateDirectory(FindSharedDir(old_name, new_name));
|
|
||||||
ShowMessage("'" + old_name + "' renamed to '" + new_name + "'");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ShowMessage("Cannot rename '" + old_name + "' to '" + new_name + "'!");
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
else if (wCurrent == mPlaylistList || (wCurrent == mBrowser && mBrowser->Current().type == itPlaylist))
|
else if (wCurrent == mPlaylistList || (wCurrent == mBrowser && mBrowser->Current().type == itPlaylist))
|
||||||
{
|
{
|
||||||
string old_name = wCurrent == mPlaylistList ? mPlaylistList->GetOption() : mBrowser->Current().name;
|
string old_name = wCurrent == mPlaylistList ? mPlaylistList->GetOption() : mBrowser->Current().name;
|
||||||
@@ -2685,7 +2671,8 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
Mpd->Rename(old_name, new_name);
|
Mpd->Rename(old_name, new_name);
|
||||||
ShowMessage("Playlist '" + old_name + "' renamed to '" + new_name + "'");
|
ShowMessage("Playlist '" + old_name + "' renamed to '" + new_name + "'");
|
||||||
GetDirectory("/");
|
if (!Config.local_browser)
|
||||||
|
GetDirectory("/");
|
||||||
mPlaylistList->Clear(0);
|
mPlaylistList->Clear(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2724,6 +2711,8 @@ int main(int argc, char *argv[])
|
|||||||
if (s->GetDirectory() == EMPTY_TAG) // for streams
|
if (s->GetDirectory() == EMPTY_TAG) // for streams
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Config.local_browser = !s->IsFromDB();
|
||||||
|
|
||||||
string option = DisplaySong(*s, &Config.song_list_format, mPlaylist);
|
string option = DisplaySong(*s, &Config.song_list_format, mPlaylist);
|
||||||
GetDirectory(s->GetDirectory());
|
GetDirectory(s->GetDirectory());
|
||||||
for (int i = 0; i < mBrowser->Size(); i++)
|
for (int i = 0; i < mBrowser->Size(); i++)
|
||||||
@@ -2949,7 +2938,7 @@ int main(int argc, char *argv[])
|
|||||||
if (id != mDialog->Size()-1)
|
if (id != mDialog->Size()-1)
|
||||||
{
|
{
|
||||||
// refresh playlist's lists
|
// refresh playlist's lists
|
||||||
if (browsed_dir == "/")
|
if (!Config.local_browser && browsed_dir == "/")
|
||||||
GetDirectory("/");
|
GetDirectory("/");
|
||||||
mPlaylistList->Clear(0); // make playlist editor update itself
|
mPlaylistList->Clear(0); // make playlist editor update itself
|
||||||
}
|
}
|
||||||
@@ -3097,31 +3086,43 @@ int main(int argc, char *argv[])
|
|||||||
Config.ncmpc_like_songs_adding = !Config.ncmpc_like_songs_adding;
|
Config.ncmpc_like_songs_adding = !Config.ncmpc_like_songs_adding;
|
||||||
ShowMessage("Add mode: " + string(Config.ncmpc_like_songs_adding ? "Add item to playlist, remove if already added" : "Always add item to playlist"));
|
ShowMessage("Add mode: " + string(Config.ncmpc_like_songs_adding ? "Add item to playlist, remove if already added" : "Always add item to playlist"));
|
||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.SwitchTagTypeList) && wCurrent == mLibArtists)
|
else if (Keypressed(input, Key.SwitchTagTypeList))
|
||||||
{
|
{
|
||||||
LockStatusbar();
|
if (wCurrent == mBrowser && Mpd->GetHostname()[0] == '/')
|
||||||
wFooter->WriteXY(0, Config.statusbar_visibility, "Tag type ? [[.b]a[/b]rtist/[.b]y[/b]ear/[.b]g[/b]enre/[.b]c[/b]omposer/[.b]p[/b]erformer] ", 1);
|
|
||||||
int item;
|
|
||||||
curs_set(1);
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
TraceMpdStatus();
|
Config.local_browser = !Config.local_browser;
|
||||||
wFooter->ReadKey(item);
|
ShowMessage("Browse mode: " + string(Config.local_browser ? "Local filesystem" : "MPD music dir"));
|
||||||
|
browsed_dir = Config.local_browser ? home_folder : "/";
|
||||||
|
mBrowser->Reset();
|
||||||
|
GetDirectory(browsed_dir);
|
||||||
|
redraw_header = 1;
|
||||||
}
|
}
|
||||||
while (item != 'a' && item != 'y' && item != 'g' && item != 'c' && item != 'p');
|
else if (wCurrent == mLibArtists)
|
||||||
curs_set(0);
|
|
||||||
UnlockStatusbar();
|
|
||||||
mpd_TagItems new_tagitem = IntoTagItem(item);
|
|
||||||
if (new_tagitem != Config.media_lib_primary_tag)
|
|
||||||
{
|
{
|
||||||
Config.media_lib_primary_tag = new_tagitem;
|
LockStatusbar();
|
||||||
string item_type = IntoStr(Config.media_lib_primary_tag);
|
wFooter->WriteXY(0, Config.statusbar_visibility, "Tag type ? [[.b]a[/b]rtist/[.b]y[/b]ear/[.b]g[/b]enre/[.b]c[/b]omposer/[.b]p[/b]erformer] ", 1);
|
||||||
mLibArtists->SetTitle(item_type + "s");
|
int item;
|
||||||
mLibArtists->Reset();
|
curs_set(1);
|
||||||
mLibArtists->Clear(0);
|
do
|
||||||
mLibArtists->Display();
|
{
|
||||||
ToLower(item_type);
|
TraceMpdStatus();
|
||||||
ShowMessage("Switched to list of " + item_type + " tag");
|
wFooter->ReadKey(item);
|
||||||
|
}
|
||||||
|
while (item != 'a' && item != 'y' && item != 'g' && item != 'c' && item != 'p');
|
||||||
|
curs_set(0);
|
||||||
|
UnlockStatusbar();
|
||||||
|
mpd_TagItems new_tagitem = IntoTagItem(item);
|
||||||
|
if (new_tagitem != Config.media_lib_primary_tag)
|
||||||
|
{
|
||||||
|
Config.media_lib_primary_tag = new_tagitem;
|
||||||
|
string item_type = IntoStr(Config.media_lib_primary_tag);
|
||||||
|
mLibArtists->SetTitle(item_type + "s");
|
||||||
|
mLibArtists->Reset();
|
||||||
|
mLibArtists->Clear(0);
|
||||||
|
mLibArtists->Display();
|
||||||
|
ToLower(item_type);
|
||||||
|
ShowMessage("Switched to list of " + item_type + " tag");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Keypressed(input, Key.SongInfo))
|
else if (Keypressed(input, Key.SongInfo))
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ void DefaultConfiguration(ncmpcpp_config &conf)
|
|||||||
conf.albums_in_tag_editor = false;
|
conf.albums_in_tag_editor = false;
|
||||||
conf.incremental_seeking = true;
|
conf.incremental_seeking = true;
|
||||||
conf.now_playing_lyrics = false;
|
conf.now_playing_lyrics = false;
|
||||||
|
conf.local_browser = false;
|
||||||
conf.set_window_title = true;
|
conf.set_window_title = true;
|
||||||
conf.mpd_connection_timeout = 15;
|
conf.mpd_connection_timeout = 15;
|
||||||
conf.crossfade_time = 5;
|
conf.crossfade_time = 5;
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ struct ncmpcpp_config
|
|||||||
bool albums_in_tag_editor;
|
bool albums_in_tag_editor;
|
||||||
bool incremental_seeking;
|
bool incremental_seeking;
|
||||||
bool now_playing_lyrics;
|
bool now_playing_lyrics;
|
||||||
|
bool local_browser;
|
||||||
|
|
||||||
int mpd_connection_timeout;
|
int mpd_connection_timeout;
|
||||||
int crossfade_time;
|
int crossfade_time;
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ Song::Song(mpd_Song *s, bool copy_ptr) : itsSong(s),
|
|||||||
isStream = 1;
|
isStream = 1;
|
||||||
|
|
||||||
// generate pseudo-hash
|
// generate pseudo-hash
|
||||||
for (int i = 0; i < strlen(itsSong->file); i++)
|
for (int i = 0; i < itsFile.length(); i++)
|
||||||
{
|
{
|
||||||
itsHash += itsSong->file[i];
|
itsHash += itsFile[i];
|
||||||
if (i%2)
|
if (i%3)
|
||||||
itsHash *= itsSong->file[i];
|
itsHash *= itsFile[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "browser.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "search_engine.h"
|
#include "search_engine.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|||||||
@@ -129,6 +129,21 @@ string DisplayTag(const Song &s, void *data, const Menu<Song> *)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReadTagsFromFile(mpd_Song *s)
|
||||||
|
{
|
||||||
|
TagLib::FileRef f(s->file);
|
||||||
|
if (f.isNull())
|
||||||
|
return;
|
||||||
|
s->artist = !f.tag()->artist().isEmpty() ? str_pool_get(f.tag()->artist().to8Bit(UNICODE).c_str()) : 0;
|
||||||
|
s->title = !f.tag()->title().isEmpty() ? str_pool_get(f.tag()->title().to8Bit(UNICODE).c_str()) : 0;
|
||||||
|
s->album = !f.tag()->album().isEmpty() ? str_pool_get(f.tag()->album().to8Bit(UNICODE).c_str()) : 0;
|
||||||
|
s->track = f.tag()->track() ? str_pool_get(IntoStr(f.tag()->track()).c_str()) : 0;
|
||||||
|
s->date = f.tag()->year() ? str_pool_get(IntoStr(f.tag()->year()).c_str()) : 0;
|
||||||
|
s->genre = !f.tag()->genre().isEmpty() ? str_pool_get(f.tag()->genre().to8Bit(UNICODE).c_str()) : 0;
|
||||||
|
s->comment = !f.tag()->comment().isEmpty() ? str_pool_get(f.tag()->comment().to8Bit(UNICODE).c_str()) : 0;
|
||||||
|
s->time = f.audioProperties()->length();
|
||||||
|
}
|
||||||
|
|
||||||
bool GetSongTags(Song &s)
|
bool GetSongTags(Song &s)
|
||||||
{
|
{
|
||||||
string path_to_file;
|
string path_to_file;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ string DisplayTag(const Song &, void *, const Menu<Song> *);
|
|||||||
|
|
||||||
SongSetFunction IntoSetFunction(mpd_TagItems);
|
SongSetFunction IntoSetFunction(mpd_TagItems);
|
||||||
|
|
||||||
|
void ReadTagsFromFile(mpd_Song *);
|
||||||
bool GetSongTags(Song &);
|
bool GetSongTags(Song &);
|
||||||
bool WriteTags(Song &);
|
bool WriteTags(Song &);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user