add support for browsing local filesystem
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
bin_PROGRAMS = ncmpcpp
|
||||
ncmpcpp_SOURCES = color_parser.cpp help.cpp helpers.cpp libmpdclient.c \
|
||||
lyrics.cpp menu.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
|
||||
ncmpcpp_SOURCES = browser.cpp color_parser.cpp help.cpp helpers.cpp \
|
||||
libmpdclient.c lyrics.cpp menu.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
|
||||
|
||||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes)
|
||||
|
||||
# the library search path.
|
||||
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
|
||||
|
||||
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. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "mpdpp.h"
|
||||
|
||||
#include "help.h"
|
||||
#include "settings.h"
|
||||
|
||||
extern MPDConnection *Mpd;
|
||||
|
||||
extern ncmpcpp_keys Key;
|
||||
|
||||
namespace
|
||||
@@ -165,6 +169,8 @@ string GetKeybindings()
|
||||
result += " [.b]Keys - Browse screen\n -----------------------------------------[/b]\n";
|
||||
result += DisplayKeys(Key.Enter) + "Enter directory/Add item to playlist and play\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.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 int lock_statusbar_delay;
|
||||
extern int browsed_dir_scroll_begin;
|
||||
|
||||
extern time_t time_of_statusbar_lock;
|
||||
|
||||
extern string browsed_dir;
|
||||
|
||||
extern bool messages_allowed;
|
||||
extern bool block_progressbar_update;
|
||||
extern bool block_statusbar_update;
|
||||
@@ -220,28 +217,6 @@ bool CaseInsensitiveSorting::operator()(const Item &a, const Item &b)
|
||||
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)
|
||||
{
|
||||
bool bold = 0;
|
||||
@@ -395,27 +370,6 @@ string DisplayStringPair(const StringPair &pair, void *, const Menu<StringPair>
|
||||
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)
|
||||
{
|
||||
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);
|
||||
for (int i = v.length(); i < width; i++, v += space) { }
|
||||
if (!color.empty())
|
||||
result += open_col + color + close_col;
|
||||
{
|
||||
result += open_col;
|
||||
result += color;
|
||||
result += close_col;
|
||||
}
|
||||
result += v;
|
||||
if (!color.empty())
|
||||
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 *);
|
||||
|
||||
void UpdateItemList(Menu<Item> *);
|
||||
void UpdateSongList(Menu<Song> *);
|
||||
|
||||
bool Keypressed(int, const int *);
|
||||
@@ -55,13 +54,11 @@ string IntoStr(mpd_TagItems);
|
||||
string FindSharedDir(const string &, const string &);
|
||||
string TotalPlaylistLength();
|
||||
string DisplayStringPair(const StringPair &, void *, const Menu<StringPair> *);
|
||||
string DisplayItem(const Item &, void *, const Menu<Item> *);
|
||||
string DisplayColumns(string);
|
||||
string DisplaySongInColumns(const Song &, void *, const Menu<Song> *);
|
||||
string DisplaySong(const Song &, void * = &Config.song_list_format, const Menu<Song> * = NULL);
|
||||
string GetInfo(Song &);
|
||||
void ShowMessage(const string &, int = Config.message_delay_time);
|
||||
void GetDirectory(string, string = "/");
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -22,7 +22,14 @@
|
||||
|
||||
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;
|
||||
itsCurrentStats = 0;
|
||||
@@ -467,7 +474,7 @@ int MPDConnection::AddSong(const string &path)
|
||||
|
||||
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)
|
||||
|
||||
@@ -82,6 +82,9 @@ class MPDConnection
|
||||
bool Connected() const;
|
||||
void Disconnect();
|
||||
|
||||
const string & GetHostname() { return MPD_HOST; }
|
||||
int GetPort() { return MPD_PORT; }
|
||||
|
||||
void SetHostname(const string &);
|
||||
void SetPort(int port) { MPD_PORT = port; }
|
||||
void SetTimeout(int timeout) { MPD_TIMEOUT = timeout; }
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "mpdpp.h"
|
||||
#include "ncmpcpp.h"
|
||||
|
||||
#include "browser.h"
|
||||
#include "help.h"
|
||||
#include "helpers.h"
|
||||
#include "lyrics.h"
|
||||
@@ -923,7 +924,7 @@ int main(int argc, char *argv[])
|
||||
if (wCurrent == mBrowser && browsed_dir != "/")
|
||||
{
|
||||
mBrowser->Reset();
|
||||
goto GO_TO_PARENT_DIR;
|
||||
goto ENTER_BROWSER_SCREEN;
|
||||
}
|
||||
}
|
||||
else if (Keypressed(input, Key.Enter))
|
||||
@@ -938,7 +939,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
case csBrowser:
|
||||
{
|
||||
GO_TO_PARENT_DIR:
|
||||
ENTER_BROWSER_SCREEN:
|
||||
|
||||
const Item &item = mBrowser->Current();
|
||||
switch (item.type)
|
||||
@@ -1135,7 +1136,12 @@ int main(int argc, char *argv[])
|
||||
mSearcher->Current().second = s;
|
||||
}
|
||||
else
|
||||
mPlaylist->Current() = s;
|
||||
{
|
||||
if (wPrev == mPlaylist)
|
||||
mPlaylist->Current() = s;
|
||||
else if (wPrev == mBrowser)
|
||||
*mBrowser->Current().song = s;
|
||||
}
|
||||
}
|
||||
else
|
||||
ShowMessage("Error writing tags!");
|
||||
@@ -2025,7 +2031,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
Mpd->DeletePlaylist(name);
|
||||
ShowMessage("Playlist " + name + " deleted!");
|
||||
GetDirectory("/");
|
||||
if (!Config.local_browser)
|
||||
GetDirectory("/");
|
||||
}
|
||||
else
|
||||
ShowMessage("Aborted!");
|
||||
@@ -2122,7 +2129,7 @@ int main(int argc, char *argv[])
|
||||
UnlockStatusbar();
|
||||
}
|
||||
}
|
||||
if (browsed_dir == "/" && !mBrowser->Empty())
|
||||
if (!Config.local_browser && browsed_dir == "/" && !mBrowser->Empty())
|
||||
GetDirectory(browsed_dir);
|
||||
}
|
||||
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 + "'!");
|
||||
}
|
||||
}
|
||||
// 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))
|
||||
{
|
||||
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);
|
||||
ShowMessage("Playlist '" + old_name + "' renamed to '" + new_name + "'");
|
||||
GetDirectory("/");
|
||||
if (!Config.local_browser)
|
||||
GetDirectory("/");
|
||||
mPlaylistList->Clear(0);
|
||||
}
|
||||
}
|
||||
@@ -2724,6 +2711,8 @@ int main(int argc, char *argv[])
|
||||
if (s->GetDirectory() == EMPTY_TAG) // for streams
|
||||
continue;
|
||||
|
||||
Config.local_browser = !s->IsFromDB();
|
||||
|
||||
string option = DisplaySong(*s, &Config.song_list_format, mPlaylist);
|
||||
GetDirectory(s->GetDirectory());
|
||||
for (int i = 0; i < mBrowser->Size(); i++)
|
||||
@@ -2949,7 +2938,7 @@ int main(int argc, char *argv[])
|
||||
if (id != mDialog->Size()-1)
|
||||
{
|
||||
// refresh playlist's lists
|
||||
if (browsed_dir == "/")
|
||||
if (!Config.local_browser && browsed_dir == "/")
|
||||
GetDirectory("/");
|
||||
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;
|
||||
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();
|
||||
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
|
||||
if (wCurrent == mBrowser && Mpd->GetHostname()[0] == '/')
|
||||
{
|
||||
TraceMpdStatus();
|
||||
wFooter->ReadKey(item);
|
||||
Config.local_browser = !Config.local_browser;
|
||||
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');
|
||||
curs_set(0);
|
||||
UnlockStatusbar();
|
||||
mpd_TagItems new_tagitem = IntoTagItem(item);
|
||||
if (new_tagitem != Config.media_lib_primary_tag)
|
||||
else if (wCurrent == mLibArtists)
|
||||
{
|
||||
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");
|
||||
LockStatusbar();
|
||||
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();
|
||||
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))
|
||||
|
||||
@@ -202,6 +202,7 @@ void DefaultConfiguration(ncmpcpp_config &conf)
|
||||
conf.albums_in_tag_editor = false;
|
||||
conf.incremental_seeking = true;
|
||||
conf.now_playing_lyrics = false;
|
||||
conf.local_browser = false;
|
||||
conf.set_window_title = true;
|
||||
conf.mpd_connection_timeout = 15;
|
||||
conf.crossfade_time = 5;
|
||||
|
||||
@@ -142,6 +142,7 @@ struct ncmpcpp_config
|
||||
bool albums_in_tag_editor;
|
||||
bool incremental_seeking;
|
||||
bool now_playing_lyrics;
|
||||
bool local_browser;
|
||||
|
||||
int mpd_connection_timeout;
|
||||
int crossfade_time;
|
||||
|
||||
@@ -61,11 +61,11 @@ Song::Song(mpd_Song *s, bool copy_ptr) : itsSong(s),
|
||||
isStream = 1;
|
||||
|
||||
// generate pseudo-hash
|
||||
for (int i = 0; i < strlen(itsSong->file); i++)
|
||||
for (int i = 0; i < itsFile.length(); i++)
|
||||
{
|
||||
itsHash += itsSong->file[i];
|
||||
if (i%2)
|
||||
itsHash *= itsSong->file[i];
|
||||
itsHash += itsFile[i];
|
||||
if (i%3)
|
||||
itsHash *= itsFile[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "browser.h"
|
||||
#include "helpers.h"
|
||||
#include "search_engine.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)
|
||||
{
|
||||
string path_to_file;
|
||||
|
||||
@@ -40,6 +40,7 @@ string DisplayTag(const Song &, void *, const Menu<Song> *);
|
||||
|
||||
SongSetFunction IntoSetFunction(mpd_TagItems);
|
||||
|
||||
void ReadTagsFromFile(mpd_Song *);
|
||||
bool GetSongTags(Song &);
|
||||
bool WriteTags(Song &);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user