drop libmpd dependency in favor of its own libmpdclient wrapper
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
bin_PROGRAMS = ncmpcpp
|
||||
ncmpcpp_SOURCES = color_parser.cpp helpers.cpp lyrics.cpp menu.cpp misc.cpp \
|
||||
ncmpcpp.cpp scrollpad.cpp settings.cpp song.cpp status_checker.cpp window.cpp
|
||||
ncmpcpp_SOURCES = color_parser.cpp helpers.cpp libmpdclient.c lyrics.cpp \
|
||||
menu.cpp misc.cpp mpdpp.cpp ncmpcpp.cpp scrollpad.cpp settings.cpp song.cpp \
|
||||
status_checker.cpp window.cpp
|
||||
|
||||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes)
|
||||
|
||||
# the library search path.
|
||||
ncmpcpp_LDFLAGS = $(all_libraries)
|
||||
noinst_HEADERS = helpers.h lyrics.h menu.h scrollpad.h settings.h song.h \
|
||||
status_checker.h window.h
|
||||
noinst_HEADERS = helpers.h lyrics.h menu.h mpdpp.h scrollpad.h settings.h \
|
||||
song.h status_checker.h window.h
|
||||
|
||||
@@ -21,10 +21,7 @@
|
||||
#include "helpers.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define FOR_EACH_MPD_DATA(x) for (; (x); (x) = mpd_data_get_next(x))
|
||||
|
||||
extern MpdObj *conn;
|
||||
extern MpdData *browser;
|
||||
extern MPDConnection *Mpd;
|
||||
|
||||
extern ncmpcpp_config Config;
|
||||
|
||||
@@ -34,8 +31,8 @@ extern Menu *mSearcher;
|
||||
|
||||
extern Window *wFooter;
|
||||
|
||||
extern vector<Song *> vPlaylist;
|
||||
extern vector<BrowsedItem> vBrowser;
|
||||
extern SongList vPlaylist;
|
||||
extern ItemList vBrowser;
|
||||
|
||||
extern NcmpcppScreen current_screen;
|
||||
|
||||
@@ -64,9 +61,9 @@ extern string UNKNOWN_ARTIST;
|
||||
extern string UNKNOWN_TITLE;
|
||||
extern string UNKNOWN_ALBUM;
|
||||
|
||||
bool SortSongsByTrack(const Song &a, const Song &b)
|
||||
bool SortSongsByTrack(Song *a, Song *b)
|
||||
{
|
||||
return StrToInt(a.GetTrack()) < StrToInt(b.GetTrack());
|
||||
return StrToInt(a->GetTrack()) < StrToInt(b->GetTrack());
|
||||
}
|
||||
|
||||
bool CaseInsensitiveComparison(string a, string b)
|
||||
@@ -90,7 +87,7 @@ string TotalPlaylistLength()
|
||||
const int YEAR = 365*DAY;
|
||||
string result;
|
||||
int length = 0;
|
||||
for (vector<Song *>::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
for (SongList::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
length += (*it)->GetTotalLength();
|
||||
|
||||
int years = length/YEAR;
|
||||
@@ -363,14 +360,16 @@ void PrepareSearchEngine(Song &s)
|
||||
mSearcher->AddOption("Reset");
|
||||
}
|
||||
|
||||
void Search(vector<Song> &result, Song &s)
|
||||
void Search(SongList &result, Song &s)
|
||||
{
|
||||
result.clear();
|
||||
FreeSongList(result);
|
||||
|
||||
if (s.Empty())
|
||||
return;
|
||||
|
||||
MpdData *everything = mpd_database_get_complete(conn);
|
||||
SongList list;
|
||||
Mpd->GetDirectoryRecursive("/", list);
|
||||
|
||||
bool found = 1;
|
||||
|
||||
s.GetEmptyFields(1);
|
||||
@@ -403,10 +402,9 @@ void Search(vector<Song> &result, Song &s)
|
||||
s.SetComment(t);
|
||||
}
|
||||
|
||||
FOR_EACH_MPD_DATA(everything)
|
||||
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
|
||||
{
|
||||
Song new_song = everything->song;
|
||||
Song copy = new_song;
|
||||
Song copy = **it;
|
||||
|
||||
if (!search_case_sensitive)
|
||||
{
|
||||
@@ -476,10 +474,14 @@ void Search(vector<Song> &result, Song &s)
|
||||
}
|
||||
|
||||
if (found)
|
||||
result.push_back(new_song);
|
||||
{
|
||||
Song *ss = new Song(**it);
|
||||
result.push_back(ss);
|
||||
}
|
||||
|
||||
found = 1;
|
||||
}
|
||||
FreeSongList(list);
|
||||
s.GetEmptyFields(0);
|
||||
}
|
||||
|
||||
@@ -564,63 +566,53 @@ void GetDirectory(string dir)
|
||||
if (dir != "/")
|
||||
{
|
||||
mBrowser->AddOption("[..]");
|
||||
BrowsedItem parent;
|
||||
parent.type = MPD_DATA_TYPE_DIRECTORY;
|
||||
Item parent;
|
||||
parent.type = itDirectory;
|
||||
vBrowser.push_back(parent);
|
||||
}
|
||||
browser = mpd_database_get_directory(conn, (char *)dir.c_str());
|
||||
FOR_EACH_MPD_DATA(browser)
|
||||
Mpd->GetDirectory(dir, vBrowser);
|
||||
for (ItemList::iterator it = vBrowser.begin()+(dir != "/" ? 1 : 0); it != vBrowser.end(); it++)
|
||||
{
|
||||
switch (browser->type)
|
||||
switch (it->type)
|
||||
{
|
||||
case MPD_DATA_TYPE_PLAYLIST:
|
||||
case itPlaylist:
|
||||
{
|
||||
BrowsedItem playlist;
|
||||
playlist.type = MPD_DATA_TYPE_PLAYLIST;
|
||||
playlist.name = browser->playlist;
|
||||
vBrowser.push_back(playlist);
|
||||
mBrowser->AddOption("[red](playlist)[/red] " + string(browser->playlist));
|
||||
mBrowser->AddOption("[red](playlist)[/red] " + string(it->name));
|
||||
break;
|
||||
}
|
||||
case MPD_DATA_TYPE_DIRECTORY:
|
||||
case itDirectory:
|
||||
{
|
||||
string subdir = browser->directory;
|
||||
BrowsedItem directory;
|
||||
directory.type = MPD_DATA_TYPE_DIRECTORY;
|
||||
string directory;
|
||||
string subdir = it->name;
|
||||
if (dir == "/")
|
||||
directory.name = subdir.substr(browsed_dir.size()-1,subdir.size()-browsed_dir.size()+1);
|
||||
directory = subdir.substr(browsed_dir.size()-1,subdir.size()-browsed_dir.size()+1);
|
||||
else
|
||||
directory.name = subdir.substr(browsed_dir.size()+1,subdir.size()-browsed_dir.size()-1);
|
||||
vBrowser.push_back(directory);
|
||||
mBrowser->AddOption("[" + directory.name + "]");
|
||||
if (directory.name == browsed_subdir)
|
||||
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 MPD_DATA_TYPE_SONG:
|
||||
case itSong:
|
||||
{
|
||||
BrowsedItem song;
|
||||
song.type = MPD_DATA_TYPE_SONG;
|
||||
Song s = browser->song;
|
||||
song.name = s.GetFile();
|
||||
song.hash = s.GetHash();
|
||||
it->name = it->song->GetFile();
|
||||
Song *s = it->song;
|
||||
bool bold = 0;
|
||||
for (vector<Song *>::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
for (SongList::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
{
|
||||
if ((*it)->GetHash() == s.GetHash())
|
||||
if ((*it)->GetHash() == s->GetHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bold ? mBrowser->AddBoldOption(DisplaySong(s)) : mBrowser->AddOption(DisplaySong(s));
|
||||
vBrowser.push_back(song);
|
||||
bold ? mBrowser->AddBoldOption(DisplaySong(*s)) : mBrowser->AddOption(DisplaySong(*s));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mBrowser->Highlight(highlightme);
|
||||
mpd_data_free(browser);
|
||||
browsed_subdir.clear();
|
||||
|
||||
if (current_screen != csLibrary && current_screen == csBrowser)
|
||||
|
||||
@@ -24,20 +24,13 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "ncmpcpp.h"
|
||||
#include "mpdpp.h"
|
||||
#include "settings.h"
|
||||
#include "song.h"
|
||||
|
||||
struct BrowsedItem
|
||||
{
|
||||
BrowsedItem() : hash(0) { }
|
||||
string name;
|
||||
MpdDataType type;
|
||||
long long hash;
|
||||
};
|
||||
|
||||
extern ncmpcpp_config Config;
|
||||
|
||||
bool SortSongsByTrack(const Song &, const Song &);
|
||||
bool SortSongsByTrack(Song *, Song *);
|
||||
bool CaseInsensitiveComparison(string, string);
|
||||
void WindowTitle(const string &);
|
||||
string TotalPlaylistLength();
|
||||
@@ -46,7 +39,7 @@ void ShowMessage(const string &, int = Config.message_delay_time);
|
||||
void GetDirectory(string);
|
||||
bool GetSongInfo(Song &);
|
||||
void PrepareSearchEngine(Song &s);
|
||||
void Search(vector<Song> &, Song &);
|
||||
void Search(SongList &, Song &);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1955
src/libmpdclient.c
Normal file
1955
src/libmpdclient.c
Normal file
File diff suppressed because it is too large
Load Diff
670
src/libmpdclient.h
Normal file
670
src/libmpdclient.h
Normal file
@@ -0,0 +1,670 @@
|
||||
/* libmpdclient
|
||||
(c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
|
||||
This project's homepage is: http://www.musicpd.org
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Music Player Daemon nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LIBMPDCLIENT_H
|
||||
#define LIBMPDCLIENT_H
|
||||
|
||||
#ifdef WIN32
|
||||
# define __W32API_USE_DLLIMPORT__ 1
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdarg.h>
|
||||
#define MPD_BUFFER_MAX_LENGTH 50000
|
||||
#define MPD_ERRORSTR_MAX_LENGTH 1000
|
||||
#define MPD_WELCOME_MESSAGE "OK MPD "
|
||||
|
||||
#define MPD_ERROR_TIMEOUT 10 /* timeout trying to talk to mpd */
|
||||
#define MPD_ERROR_SYSTEM 11 /* system error */
|
||||
#define MPD_ERROR_UNKHOST 12 /* unknown host */
|
||||
#define MPD_ERROR_CONNPORT 13 /* problems connecting to port on host */
|
||||
#define MPD_ERROR_NOTMPD 14 /* mpd not running on port at host */
|
||||
#define MPD_ERROR_NORESPONSE 15 /* no response on attempting to connect */
|
||||
#define MPD_ERROR_SENDING 16 /* error sending command */
|
||||
#define MPD_ERROR_CONNCLOSED 17 /* connection closed by mpd */
|
||||
#define MPD_ERROR_ACK 18 /* ACK returned! */
|
||||
#define MPD_ERROR_BUFFEROVERRUN 19 /* Buffer was overrun! */
|
||||
|
||||
#define MPD_ACK_ERROR_UNK -1
|
||||
#define MPD_ERROR_AT_UNK -1
|
||||
|
||||
#define MPD_ACK_ERROR_NOT_LIST 1
|
||||
#define MPD_ACK_ERROR_ARG 2
|
||||
#define MPD_ACK_ERROR_PASSWORD 3
|
||||
#define MPD_ACK_ERROR_PERMISSION 4
|
||||
#define MPD_ACK_ERROR_UNKNOWN_CMD 5
|
||||
|
||||
#define MPD_ACK_ERROR_NO_EXIST 50
|
||||
#define MPD_ACK_ERROR_PLAYLIST_MAX 51
|
||||
#define MPD_ACK_ERROR_SYSTEM 52
|
||||
#define MPD_ACK_ERROR_PLAYLIST_LOAD 53
|
||||
#define MPD_ACK_ERROR_UPDATE_ALREADY 54
|
||||
#define MPD_ACK_ERROR_PLAYER_SYNC 55
|
||||
#define MPD_ACK_ERROR_EXIST 56
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum mpd_TagItems
|
||||
{
|
||||
MPD_TAG_ITEM_ARTIST,
|
||||
MPD_TAG_ITEM_ALBUM,
|
||||
MPD_TAG_ITEM_TITLE,
|
||||
MPD_TAG_ITEM_TRACK,
|
||||
MPD_TAG_ITEM_NAME,
|
||||
MPD_TAG_ITEM_GENRE,
|
||||
MPD_TAG_ITEM_DATE,
|
||||
MPD_TAG_ITEM_COMPOSER,
|
||||
MPD_TAG_ITEM_PERFORMER,
|
||||
MPD_TAG_ITEM_COMMENT,
|
||||
MPD_TAG_ITEM_DISC,
|
||||
MPD_TAG_ITEM_FILENAME,
|
||||
MPD_TAG_ITEM_ANY,
|
||||
MPD_TAG_NUM_OF_ITEM_TYPES
|
||||
} mpd_TagItems;
|
||||
|
||||
extern char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES];
|
||||
|
||||
/* internal stuff don't touch this struct */
|
||||
typedef struct _mpd_ReturnElement {
|
||||
char * name;
|
||||
char * value;
|
||||
} mpd_ReturnElement;
|
||||
|
||||
/* mpd_Connection
|
||||
* holds info about connection to mpd
|
||||
* use error, and errorStr to detect errors
|
||||
*/
|
||||
typedef struct _mpd_Connection {
|
||||
/* use this to check the version of mpd */
|
||||
int version[3];
|
||||
/* IMPORTANT, you want to get the error messages from here */
|
||||
char errorStr[MPD_ERRORSTR_MAX_LENGTH+1];
|
||||
int errorCode;
|
||||
int errorAt;
|
||||
/* this will be set to MPD_ERROR_* if there is an error, 0 if not */
|
||||
int error;
|
||||
/* DON'T TOUCH any of the rest of this stuff */
|
||||
int sock;
|
||||
char buffer[MPD_BUFFER_MAX_LENGTH+1];
|
||||
int buflen;
|
||||
int bufstart;
|
||||
int doneProcessing;
|
||||
int listOks;
|
||||
int doneListOk;
|
||||
int commandList;
|
||||
mpd_ReturnElement * returnElement;
|
||||
struct timeval timeout;
|
||||
char *request;
|
||||
} mpd_Connection;
|
||||
|
||||
/* mpd_newConnection
|
||||
* use this to open a new connection
|
||||
* you should use mpd_closeConnection, when your done with the connection,
|
||||
* even if an error has occurred
|
||||
* _timeout_ is the connection timeout period in seconds
|
||||
*/
|
||||
mpd_Connection * mpd_newConnection(const char * host, int port, float timeout);
|
||||
|
||||
void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout);
|
||||
|
||||
/* mpd_closeConnection
|
||||
* use this to close a connection and free'ing subsequent memory
|
||||
*/
|
||||
void mpd_closeConnection(mpd_Connection * connection);
|
||||
|
||||
/* mpd_clearError
|
||||
* clears error
|
||||
*/
|
||||
void mpd_clearError(mpd_Connection * connection);
|
||||
|
||||
/* STATUS STUFF */
|
||||
|
||||
/* use these with status.state to determine what state the player is in */
|
||||
#define MPD_STATUS_STATE_UNKNOWN 0
|
||||
#define MPD_STATUS_STATE_STOP 1
|
||||
#define MPD_STATUS_STATE_PLAY 2
|
||||
#define MPD_STATUS_STATE_PAUSE 3
|
||||
|
||||
/* us this with status.volume to determine if mpd has volume support */
|
||||
#define MPD_STATUS_NO_VOLUME -1
|
||||
|
||||
/* mpd_Status
|
||||
* holds info return from status command
|
||||
*/
|
||||
typedef struct mpd_Status {
|
||||
/* 0-100, or MPD_STATUS_NO_VOLUME when there is no volume support */
|
||||
int volume;
|
||||
/* 1 if repeat is on, 0 otherwise */
|
||||
int repeat;
|
||||
/* 1 if random is on, 0 otherwise */
|
||||
int random;
|
||||
/* playlist length */
|
||||
int playlistLength;
|
||||
/* playlist, use this to determine when the playlist has changed */
|
||||
long long playlist;
|
||||
/* use with MPD_STATUS_STATE_* to determine state of player */
|
||||
int state;
|
||||
/* crossfade setting in seconds */
|
||||
int crossfade;
|
||||
/* if a song is currently selected (always the case when state is
|
||||
* PLAY or PAUSE), this is the position of the currently
|
||||
* playing song in the playlist, beginning with 0
|
||||
*/
|
||||
int song;
|
||||
/* Song ID of the currently selected song */
|
||||
int songid;
|
||||
/* time in seconds that have elapsed in the currently playing/paused
|
||||
* song
|
||||
*/
|
||||
int elapsedTime;
|
||||
/* length in seconds of the currently playing/paused song */
|
||||
int totalTime;
|
||||
/* current bit rate in kbs */
|
||||
int bitRate;
|
||||
/* audio sample rate */
|
||||
unsigned int sampleRate;
|
||||
/* audio bits */
|
||||
int bits;
|
||||
/* audio channels */
|
||||
int channels;
|
||||
/* 1 if mpd is updating, 0 otherwise */
|
||||
int updatingDb;
|
||||
/* error */
|
||||
char * error;
|
||||
} mpd_Status;
|
||||
|
||||
void mpd_sendStatusCommand(mpd_Connection * connection);
|
||||
|
||||
/* mpd_getStatus
|
||||
* returns status info, be sure to free it with mpd_freeStatus()
|
||||
* call this after mpd_sendStatusCommand()
|
||||
*/
|
||||
mpd_Status * mpd_getStatus(mpd_Connection * connection);
|
||||
|
||||
/* mpd_freeStatus
|
||||
* free's status info malloc'd and returned by mpd_getStatus
|
||||
*/
|
||||
void mpd_freeStatus(mpd_Status * status);
|
||||
|
||||
typedef struct _mpd_Stats {
|
||||
int numberOfArtists;
|
||||
int numberOfAlbums;
|
||||
int numberOfSongs;
|
||||
unsigned long uptime;
|
||||
unsigned long dbUpdateTime;
|
||||
unsigned long playTime;
|
||||
unsigned long dbPlayTime;
|
||||
} mpd_Stats;
|
||||
|
||||
typedef struct _mpd_SearchStats {
|
||||
int numberOfSongs;
|
||||
unsigned long playTime;
|
||||
} mpd_SearchStats;
|
||||
|
||||
void mpd_sendStatsCommand(mpd_Connection * connection);
|
||||
|
||||
mpd_Stats * mpd_getStats(mpd_Connection * connection);
|
||||
|
||||
void mpd_freeStats(mpd_Stats * stats);
|
||||
|
||||
mpd_SearchStats * mpd_getSearchStats(mpd_Connection * connection);
|
||||
|
||||
void mpd_freeSearchStats(mpd_SearchStats * stats);
|
||||
|
||||
/* SONG STUFF */
|
||||
|
||||
#define MPD_SONG_NO_TIME -1
|
||||
#define MPD_SONG_NO_NUM -1
|
||||
#define MPD_SONG_NO_ID -1
|
||||
|
||||
/* mpd_Song
|
||||
* for storing song info returned by mpd
|
||||
*/
|
||||
typedef struct _mpd_Song {
|
||||
/* filename of song */
|
||||
char * file;
|
||||
/* artist, maybe NULL if there is no tag */
|
||||
char * artist;
|
||||
/* title, maybe NULL if there is no tag */
|
||||
char * title;
|
||||
/* album, maybe NULL if there is no tag */
|
||||
char * album;
|
||||
/* track, maybe NULL if there is no tag */
|
||||
char * track;
|
||||
/* name, maybe NULL if there is no tag; it's the name of the current
|
||||
* song, f.e. the icyName of the stream */
|
||||
char * name;
|
||||
/* date */
|
||||
char *date;
|
||||
|
||||
/* added by qball */
|
||||
/* Genre */
|
||||
char *genre;
|
||||
/* Composer */
|
||||
char *composer;
|
||||
/* Performer */
|
||||
char *performer;
|
||||
/* Disc */
|
||||
char *disc;
|
||||
/* Comment */
|
||||
char *comment;
|
||||
|
||||
/* length of song in seconds, check that it is not MPD_SONG_NO_TIME */
|
||||
int time;
|
||||
/* if plchanges/playlistinfo/playlistid used, is the position of the
|
||||
* song in the playlist */
|
||||
int pos;
|
||||
/* song id for a song in the playlist */
|
||||
int id;
|
||||
} mpd_Song;
|
||||
|
||||
/* mpd_newSong
|
||||
* use to allocate memory for a new mpd_Song
|
||||
* file, artist, etc all initialized to NULL
|
||||
* if your going to assign values to file, artist, etc
|
||||
* be sure to malloc or strdup the memory
|
||||
* use mpd_freeSong to free the memory for the mpd_Song, it will also
|
||||
* free memory for file, artist, etc, so don't do it yourself
|
||||
*/
|
||||
mpd_Song * mpd_newSong(void);
|
||||
|
||||
/* mpd_freeSong
|
||||
* use to free memory allocated by mpd_newSong
|
||||
* also it will free memory pointed to by file, artist, etc, so be careful
|
||||
*/
|
||||
void mpd_freeSong(mpd_Song * song);
|
||||
|
||||
/* mpd_songDup
|
||||
* works like strDup, but for a mpd_Song
|
||||
*/
|
||||
mpd_Song * mpd_songDup(mpd_Song * song);
|
||||
|
||||
/* DIRECTORY STUFF */
|
||||
|
||||
/* mpd_Directory
|
||||
* used to store info fro directory (right now that just the path)
|
||||
*/
|
||||
typedef struct _mpd_Directory {
|
||||
char * path;
|
||||
} mpd_Directory;
|
||||
|
||||
/* mpd_newDirectory
|
||||
* allocates memory for a new directory
|
||||
* use mpd_freeDirectory to free this memory
|
||||
*/
|
||||
mpd_Directory * mpd_newDirectory(void);
|
||||
|
||||
/* mpd_freeDirectory
|
||||
* used to free memory allocated with mpd_newDirectory, and it frees
|
||||
* path of mpd_Directory, so be careful
|
||||
*/
|
||||
void mpd_freeDirectory(mpd_Directory * directory);
|
||||
|
||||
/* mpd_directoryDup
|
||||
* works like strdup, but for mpd_Directory
|
||||
*/
|
||||
mpd_Directory * mpd_directoryDup(mpd_Directory * directory);
|
||||
|
||||
/* PLAYLISTFILE STUFF */
|
||||
|
||||
/* mpd_PlaylistFile
|
||||
* stores info about playlist file returned by lsinfo
|
||||
*/
|
||||
typedef struct _mpd_PlaylistFile {
|
||||
char * path;
|
||||
} mpd_PlaylistFile;
|
||||
|
||||
/* mpd_newPlaylistFile
|
||||
* allocates memory for new mpd_PlaylistFile, path is set to NULL
|
||||
* free this memory with mpd_freePlaylistFile
|
||||
*/
|
||||
mpd_PlaylistFile * mpd_newPlaylistFile(void);
|
||||
|
||||
/* mpd_freePlaylist
|
||||
* free memory allocated for freePlaylistFile, will also free
|
||||
* path, so be careful
|
||||
*/
|
||||
void mpd_freePlaylistFile(mpd_PlaylistFile * playlist);
|
||||
|
||||
/* mpd_playlistFileDup
|
||||
* works like strdup, but for mpd_PlaylistFile
|
||||
*/
|
||||
mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist);
|
||||
|
||||
/* INFO ENTITY STUFF */
|
||||
|
||||
/* the type of entity returned from one of the commands that generates info
|
||||
* use in conjunction with mpd_InfoEntity.type
|
||||
*/
|
||||
#define MPD_INFO_ENTITY_TYPE_DIRECTORY 0
|
||||
#define MPD_INFO_ENTITY_TYPE_SONG 1
|
||||
#define MPD_INFO_ENTITY_TYPE_PLAYLISTFILE 2
|
||||
|
||||
/* mpd_InfoEntity
|
||||
* stores info on stuff returned info commands
|
||||
*/
|
||||
typedef struct mpd_InfoEntity {
|
||||
/* the type of entity, use with MPD_INFO_ENTITY_TYPE_* to determine
|
||||
* what this entity is (song, directory, etc...)
|
||||
*/
|
||||
int type;
|
||||
/* the actual data you want, mpd_Song, mpd_Directory, etc */
|
||||
union {
|
||||
mpd_Directory * directory;
|
||||
mpd_Song * song;
|
||||
mpd_PlaylistFile * playlistFile;
|
||||
} info;
|
||||
} mpd_InfoEntity;
|
||||
|
||||
mpd_InfoEntity * mpd_newInfoEntity(void);
|
||||
|
||||
void mpd_freeInfoEntity(mpd_InfoEntity * entity);
|
||||
|
||||
/* INFO COMMANDS AND STUFF */
|
||||
|
||||
/* use this function to loop over after calling Info/Listall functions */
|
||||
mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection);
|
||||
|
||||
/* fetches the currently seeletect song (the song referenced by status->song
|
||||
* and status->songid*/
|
||||
void mpd_sendCurrentSongCommand(mpd_Connection * connection);
|
||||
|
||||
/* songNum of -1, means to display the whole list */
|
||||
void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum);
|
||||
|
||||
/* songId of -1, means to display the whole list */
|
||||
void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int songId);
|
||||
|
||||
/* use this to get the changes in the playlist since version _playlist_ */
|
||||
void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist);
|
||||
|
||||
/**
|
||||
* @param connection: A valid and connected mpd_Connection.
|
||||
* @param playlist: The playlist version you want the diff with.
|
||||
* A more bandwidth efficient version of the mpd_sendPlChangesCommand.
|
||||
* It only returns the pos+id of the changes song.
|
||||
*/
|
||||
void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection, long long playlist);
|
||||
|
||||
/* recursivel fetches all songs/dir/playlists in "dir* (no metadata is
|
||||
* returned) */
|
||||
void mpd_sendListallCommand(mpd_Connection * connection, const char * dir);
|
||||
|
||||
/* same as sendListallCommand, but also metadata is returned */
|
||||
void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir);
|
||||
|
||||
/* non-recursive version of ListallInfo */
|
||||
void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir);
|
||||
|
||||
#define MPD_TABLE_ARTIST MPD_TAG_ITEM_ARTIST
|
||||
#define MPD_TABLE_ALBUM MPD_TAG_ITEM_ALBUM
|
||||
#define MPD_TABLE_TITLE MPD_TAG_ITEM_TITLE
|
||||
#define MPD_TABLE_FILENAME MPD_TAG_ITEM_FILENAME
|
||||
|
||||
void mpd_sendSearchCommand(mpd_Connection * connection, int table,
|
||||
const char * str);
|
||||
|
||||
void mpd_sendFindCommand(mpd_Connection * connection, int table,
|
||||
const char * str);
|
||||
|
||||
/* LIST TAG COMMANDS */
|
||||
|
||||
/* use this function fetch next artist entry, be sure to free the returned
|
||||
* string. NULL means there are no more. Best used with sendListArtists
|
||||
*/
|
||||
char * mpd_getNextArtist(mpd_Connection * connection);
|
||||
|
||||
char * mpd_getNextAlbum(mpd_Connection * connection);
|
||||
|
||||
char * mpd_getNextTag(mpd_Connection *connection, int type);
|
||||
|
||||
/* list artist or albums by artist, arg1 should be set to the artist if
|
||||
* listing albums by a artist, otherwise NULL for listing all artists or albums
|
||||
*/
|
||||
void mpd_sendListCommand(mpd_Connection * connection, int table,
|
||||
const char * arg1);
|
||||
|
||||
/* SIMPLE COMMANDS */
|
||||
|
||||
void mpd_sendAddCommand(mpd_Connection * connection, const char * file);
|
||||
|
||||
int mpd_sendAddIdCommand(mpd_Connection *connection, const char *file);
|
||||
|
||||
void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum);
|
||||
|
||||
void mpd_sendDeleteIdCommand(mpd_Connection * connection, int songNum);
|
||||
|
||||
void mpd_sendSaveCommand(mpd_Connection * connection, const char * name);
|
||||
|
||||
void mpd_sendLoadCommand(mpd_Connection * connection, const char * name);
|
||||
|
||||
void mpd_sendRmCommand(mpd_Connection * connection, const char * name);
|
||||
|
||||
void mpd_sendRenameCommand(mpd_Connection *connection, const char *from,
|
||||
const char *to);
|
||||
|
||||
void mpd_sendShuffleCommand(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendClearCommand(mpd_Connection * connection);
|
||||
|
||||
/* use this to start playing at the beginning, useful when in random mode */
|
||||
#define MPD_PLAY_AT_BEGINNING -1
|
||||
|
||||
void mpd_sendPlayCommand(mpd_Connection * connection, int songNum);
|
||||
|
||||
void mpd_sendPlayIdCommand(mpd_Connection * connection, int songNum);
|
||||
|
||||
void mpd_sendStopCommand(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode);
|
||||
|
||||
void mpd_sendNextCommand(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendPrevCommand(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to);
|
||||
|
||||
void mpd_sendMoveIdCommand(mpd_Connection * connection, int from, int to);
|
||||
|
||||
void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2);
|
||||
|
||||
void mpd_sendSwapIdCommand(mpd_Connection * connection, int song1, int song2);
|
||||
|
||||
void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time);
|
||||
|
||||
void mpd_sendSeekIdCommand(mpd_Connection * connection, int song, int time);
|
||||
|
||||
void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode);
|
||||
|
||||
void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode);
|
||||
|
||||
void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange);
|
||||
|
||||
/* WARNING: don't use volume command, its depreacted */
|
||||
void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange);
|
||||
|
||||
void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds);
|
||||
|
||||
void mpd_sendUpdateCommand(mpd_Connection * connection, char * path);
|
||||
|
||||
/* returns the update job id, call this after a update command*/
|
||||
int mpd_getUpdateId(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass);
|
||||
|
||||
/* after executing a command, when your done with it to get its status
|
||||
* (you want to check connection->error for an error)
|
||||
*/
|
||||
void mpd_finishCommand(mpd_Connection * connection);
|
||||
|
||||
/* command list stuff, use this to do things like add files very quickly */
|
||||
void mpd_sendCommandListBegin(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendCommandListOkBegin(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendCommandListEnd(mpd_Connection * connection);
|
||||
|
||||
/* advance to the next listOk
|
||||
* returns 0 if advanced to the next list_OK,
|
||||
* returns -1 if it advanced to an OK or ACK */
|
||||
int mpd_nextListOkCommand(mpd_Connection * connection);
|
||||
|
||||
typedef struct _mpd_OutputEntity {
|
||||
int id;
|
||||
char * name;
|
||||
int enabled;
|
||||
} mpd_OutputEntity;
|
||||
|
||||
void mpd_sendOutputsCommand(mpd_Connection * connection);
|
||||
|
||||
mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId);
|
||||
|
||||
void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId);
|
||||
|
||||
void mpd_freeOutputElement(mpd_OutputEntity * output);
|
||||
|
||||
/**
|
||||
* @param connection a #mpd_Connection
|
||||
*
|
||||
* Queries mpd for the allowed commands
|
||||
*/
|
||||
void mpd_sendCommandsCommand(mpd_Connection * connection);
|
||||
|
||||
/**
|
||||
* @param connection a #mpd_Connection
|
||||
*
|
||||
* Queries mpd for the not allowed commands
|
||||
*/
|
||||
void mpd_sendNotCommandsCommand(mpd_Connection * connection);
|
||||
|
||||
/**
|
||||
* @param connection a #mpd_Connection
|
||||
*
|
||||
* returns the next supported command.
|
||||
*
|
||||
* @returns a string, needs to be free'ed
|
||||
*/
|
||||
char *mpd_getNextCommand(mpd_Connection *connection);
|
||||
|
||||
void mpd_sendUrlHandlersCommand(mpd_Connection * connection);
|
||||
|
||||
char *mpd_getNextHandler(mpd_Connection * connection);
|
||||
|
||||
void mpd_sendTagTypesCommand(mpd_Connection * connection);
|
||||
|
||||
char *mpd_getNextTagType(mpd_Connection * connection);
|
||||
|
||||
/**
|
||||
* @param connection a MpdConnection
|
||||
* @param path the path to the playlist.
|
||||
*
|
||||
* List the content, with full metadata, of a stored playlist.
|
||||
*
|
||||
*/
|
||||
void mpd_sendListPlaylistInfoCommand(mpd_Connection *connection, char *path);
|
||||
|
||||
/**
|
||||
* @param connection a MpdConnection
|
||||
* @param path the path to the playlist.
|
||||
*
|
||||
* List the content of a stored playlist.
|
||||
*
|
||||
*/
|
||||
void mpd_sendListPlaylistCommand(mpd_Connection *connection, char *path);
|
||||
|
||||
/**
|
||||
* @param connection a #mpd_Connection
|
||||
* @param exact if to match exact
|
||||
*
|
||||
* starts a search, use mpd_addConstraintSearch to add
|
||||
* a constraint to the search, and mpd_commitSearch to do the actual search
|
||||
*/
|
||||
void mpd_startSearch(mpd_Connection *connection, int exact);
|
||||
|
||||
/**
|
||||
* @param connection a #mpd_Connection
|
||||
* @param type
|
||||
* @param name
|
||||
*/
|
||||
void mpd_addConstraintSearch(mpd_Connection *connection, int type, const char *name);
|
||||
|
||||
/**
|
||||
* @param connection a #mpd_Connection
|
||||
*/
|
||||
void mpd_commitSearch(mpd_Connection *connection);
|
||||
|
||||
/**
|
||||
* @param connection a #mpd_Connection
|
||||
* @param type The type to search for
|
||||
*
|
||||
* starts a search for fields... f.e. get a list of artists would be:
|
||||
* @code
|
||||
* mpd_startFieldSearch(connection, MPD_TAG_ITEM_ARTIST);
|
||||
* mpd_commitSearch(connection);
|
||||
* @endcode
|
||||
*
|
||||
* or get a list of artist in genre "jazz" would be:
|
||||
* @code
|
||||
* mpd_startFieldSearch(connection, MPD_TAG_ITEM_ARTIST);
|
||||
* mpd_addConstraintSearch(connection, MPD_TAG_ITEM_GENRE, "jazz")
|
||||
* mpd_commitSearch(connection);
|
||||
* @endcode
|
||||
*
|
||||
* mpd_startSearch will return a list of songs (and you need mpd_getNextInfoEntity)
|
||||
* this one will return a list of only one field (the one specified with type) and you need
|
||||
* mpd_getNextTag to get the results
|
||||
*/
|
||||
void mpd_startFieldSearch(mpd_Connection *connection, int type);
|
||||
|
||||
void mpd_startPlaylistSearch(mpd_Connection *connection, int exact);
|
||||
|
||||
void mpd_startStatsSearch(mpd_Connection *connection);
|
||||
|
||||
void mpd_sendPlaylistClearCommand(mpd_Connection *connection, char *path);
|
||||
|
||||
void mpd_sendPlaylistAddCommand(mpd_Connection *connection,
|
||||
char *playlist, char *path);
|
||||
|
||||
void mpd_sendPlaylistMoveCommand(mpd_Connection *connection,
|
||||
char *playlist, int from, int to);
|
||||
|
||||
void mpd_sendPlaylistDeleteCommand(mpd_Connection *connection,
|
||||
char *playlist, int pos);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
624
src/mpdpp.cpp
Normal file
624
src/mpdpp.cpp
Normal file
@@ -0,0 +1,624 @@
|
||||
/***************************************************************************
|
||||
* 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 "mpdpp.h"
|
||||
|
||||
const string playlist_max_message = "playlist is at the max size";
|
||||
|
||||
MPDConnection::MPDConnection() : isConnected(0), MPD_HOST("localhost"), MPD_PORT(6600), MPD_TIMEOUT(30), itsUpdater(0), itsErrorHandler(0), itsQueueIndex(0), itsMaxPlaylistLength(-1)
|
||||
{
|
||||
itsConnection = 0;
|
||||
itsCurrentStats = 0;
|
||||
itsOldStats = 0;
|
||||
itsCurrentStatus = 0;
|
||||
itsOldStatus = 0;
|
||||
}
|
||||
|
||||
MPDConnection::~MPDConnection()
|
||||
{
|
||||
if (itsConnection)
|
||||
mpd_closeConnection(itsConnection);
|
||||
if (itsOldStats)
|
||||
mpd_freeStats(itsOldStats);
|
||||
if (itsCurrentStats)
|
||||
mpd_freeStats(itsCurrentStats);
|
||||
if (itsOldStatus)
|
||||
mpd_freeStatus(itsOldStatus);
|
||||
if (itsCurrentStatus)
|
||||
mpd_freeStatus(itsCurrentStatus);
|
||||
}
|
||||
|
||||
void MPDConnection::Connect()
|
||||
{
|
||||
if (!isConnected && !itsConnection)
|
||||
{
|
||||
itsConnection = mpd_newConnection(MPD_HOST.c_str(), MPD_PORT, MPD_TIMEOUT);
|
||||
isConnected = 1;
|
||||
CheckForErrors();
|
||||
}
|
||||
}
|
||||
|
||||
bool MPDConnection::Connected()
|
||||
{
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
void MPDConnection::Disconnect()
|
||||
{
|
||||
if (itsConnection)
|
||||
mpd_closeConnection(itsConnection);
|
||||
if (itsOldStats)
|
||||
mpd_freeStats(itsOldStats);
|
||||
if (itsCurrentStats)
|
||||
mpd_freeStats(itsCurrentStats);
|
||||
if (itsOldStatus)
|
||||
mpd_freeStatus(itsOldStatus);
|
||||
if (itsCurrentStatus)
|
||||
mpd_freeStatus(itsCurrentStatus);
|
||||
itsConnection = 0;
|
||||
itsCurrentStats = 0;
|
||||
itsOldStats = 0;
|
||||
itsCurrentStatus = 0;
|
||||
itsOldStatus = 0;
|
||||
isConnected = 0;
|
||||
itsMaxPlaylistLength = -1;
|
||||
itsQueueIndex = 0;
|
||||
itsQueue.clear();
|
||||
}
|
||||
|
||||
void MPDConnection::SendPassword()
|
||||
{
|
||||
mpd_sendPasswordCommand(itsConnection, MPD_PASSWORD.c_str());
|
||||
mpd_finishCommand(itsConnection);
|
||||
CheckForErrors();
|
||||
}
|
||||
|
||||
void MPDConnection::SetStatusUpdater(StatusUpdater updater, void *data)
|
||||
{
|
||||
itsUpdater = updater;
|
||||
itsStatusUpdaterUserdata = data;
|
||||
}
|
||||
|
||||
void MPDConnection::SetErrorHandler(ErrorHandler handler, void *data)
|
||||
{
|
||||
itsErrorHandler = handler;
|
||||
itsErrorHandlerUserdata = data;
|
||||
}
|
||||
|
||||
void MPDConnection::UpdateStatus()
|
||||
{
|
||||
CheckForErrors();
|
||||
|
||||
if (itsOldStatus)
|
||||
mpd_freeStatus(itsOldStatus);
|
||||
itsOldStatus = itsCurrentStatus;
|
||||
mpd_sendStatusCommand(itsConnection);
|
||||
itsCurrentStatus = mpd_getStatus(itsConnection);
|
||||
|
||||
if (!itsMaxPlaylistLength)
|
||||
itsMaxPlaylistLength = GetPlaylistLength();
|
||||
|
||||
CheckForErrors();
|
||||
|
||||
if (!isConnected)
|
||||
return;
|
||||
|
||||
MPDStatusChanges changes;
|
||||
|
||||
if (itsOldStats)
|
||||
mpd_freeStats(itsOldStats);
|
||||
itsOldStats = itsCurrentStats;
|
||||
mpd_sendStatsCommand(itsConnection);
|
||||
itsCurrentStats = mpd_getStats(itsConnection);
|
||||
|
||||
if (itsOldStatus == NULL)
|
||||
{
|
||||
changes.Playlist = 1;
|
||||
changes.SongID = 1;
|
||||
changes.Database = 1;
|
||||
changes.DBUpdating = 1;
|
||||
changes.Volume = 1;
|
||||
changes.ElapsedTime = 1;
|
||||
changes.Crossfade = 1;
|
||||
changes.Random = 1;
|
||||
changes.Repeat = 1;
|
||||
changes.PlayerState = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
changes.Playlist = itsOldStatus->playlist != itsCurrentStatus->playlist;
|
||||
changes.SongID = itsOldStatus->songid != itsCurrentStatus->songid;
|
||||
changes.Database = itsOldStats->dbUpdateTime != itsCurrentStats->dbUpdateTime;
|
||||
changes.DBUpdating = itsOldStatus->updatingDb != itsCurrentStatus->updatingDb;
|
||||
changes.Volume = itsOldStatus->volume != itsCurrentStatus->volume;
|
||||
changes.ElapsedTime = itsOldStatus->elapsedTime != itsCurrentStatus->elapsedTime;
|
||||
changes.Crossfade = itsOldStatus->crossfade != itsCurrentStatus->crossfade;
|
||||
changes.Random = itsOldStatus->random != itsCurrentStatus->random;
|
||||
changes.Repeat = itsOldStatus->repeat != itsCurrentStatus->repeat;
|
||||
changes.PlayerState = itsOldStatus->state != itsCurrentStatus->state;
|
||||
}
|
||||
if (itsUpdater)
|
||||
itsUpdater(this, changes, itsErrorHandlerUserdata);
|
||||
}
|
||||
|
||||
void MPDConnection::UpdateDirectory(const string &path) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendUpdateCommand(itsConnection, (char *) path.c_str());
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::Play() const
|
||||
{
|
||||
if (isConnected)
|
||||
PlayID(-1);
|
||||
}
|
||||
|
||||
void MPDConnection::Play(int pos) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendPlayCommand(itsConnection, pos);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::PlayID(int id) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendPlayIdCommand(itsConnection, id);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::Pause() const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendPauseCommand(itsConnection, itsCurrentStatus->state != psPause);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::Stop() const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendStopCommand(itsConnection);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::Next() const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendNextCommand(itsConnection);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::Prev() const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendPrevCommand(itsConnection);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::Move(int from, int to) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendMoveCommand(itsConnection, from, to);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::Seek(int where) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendSeekCommand(itsConnection, itsCurrentStatus->song, where);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::ClearPlaylist() const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendClearCommand(itsConnection);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::GetPlaylistChanges(long long id, SongList &v) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
if (id == -1)
|
||||
{
|
||||
id = 0;
|
||||
v.reserve(GetPlaylistLength());
|
||||
}
|
||||
mpd_sendPlChangesCommand(itsConnection, id);
|
||||
mpd_InfoEntity *item = NULL;
|
||||
while ((item = mpd_getNextInfoEntity(itsConnection)) != NULL)
|
||||
{
|
||||
if (item->type == MPD_INFO_ENTITY_TYPE_SONG)
|
||||
{
|
||||
Song *s = new Song(item->info.song);
|
||||
v.push_back(s);
|
||||
}
|
||||
mpd_freeInfoEntity(item);
|
||||
}
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
Song MPDConnection::GetSong(const string &path) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendListallInfoCommand(itsConnection, path.c_str());
|
||||
mpd_InfoEntity *item = NULL;
|
||||
item = mpd_getNextInfoEntity(itsConnection);
|
||||
Song result = item->info.song;
|
||||
mpd_freeInfoEntity(item);
|
||||
mpd_finishCommand(itsConnection);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return Song();
|
||||
}
|
||||
|
||||
int MPDConnection::GetCurrentSongPos() const
|
||||
{
|
||||
return isConnected && itsCurrentStatus ? (itsCurrentStatus->state == psPlay || itsCurrentStatus->state == psPause ? itsCurrentStatus->song : -1) : -1;
|
||||
}
|
||||
|
||||
Song MPDConnection::GetCurrentSong() const
|
||||
{
|
||||
if (isConnected && (GetState() == psPlay || GetState() == psPause))
|
||||
{
|
||||
mpd_sendCurrentSongCommand(itsConnection);
|
||||
mpd_InfoEntity *item = NULL;
|
||||
item = mpd_getNextInfoEntity(itsConnection);
|
||||
Song result = item->info.song;
|
||||
mpd_freeInfoEntity(item);
|
||||
mpd_finishCommand(itsConnection);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return Song();
|
||||
}
|
||||
|
||||
void MPDConnection::GetPlaylistContent(const string &path, SongList &v) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendListPlaylistInfoCommand(itsConnection, (char *) path.c_str());
|
||||
mpd_InfoEntity *item = NULL;
|
||||
while ((item = mpd_getNextInfoEntity(itsConnection)) != NULL)
|
||||
{
|
||||
if (item->type == MPD_INFO_ENTITY_TYPE_SONG)
|
||||
{
|
||||
Song *s = new Song(item->info.song);
|
||||
v.push_back(s);
|
||||
}
|
||||
mpd_freeInfoEntity(item);
|
||||
}
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::SetRepeat(bool mode) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendRepeatCommand(itsConnection, mode);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::SetRandom(bool mode) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendRandomCommand(itsConnection, mode);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::SetVolume(int vol) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendSetvolCommand(itsConnection, vol);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::SetCrossfade(int crossfade) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendCrossfadeCommand(itsConnection, crossfade);
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
int MPDConnection::AddSong(const string &path)
|
||||
{
|
||||
int id = -1;
|
||||
if (isConnected)
|
||||
{
|
||||
if (GetPlaylistLength() < itsMaxPlaylistLength)
|
||||
{
|
||||
id = mpd_sendAddIdCommand(itsConnection, path.c_str());
|
||||
mpd_finishCommand(itsConnection);
|
||||
UpdateStatus();
|
||||
}
|
||||
else
|
||||
if (itsErrorHandler)
|
||||
itsErrorHandler(this, MPD_ACK_ERROR_PLAYLIST_MAX, playlist_max_message, NULL);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
int MPDConnection::AddSong(const Song &s)
|
||||
{
|
||||
int id = -1;
|
||||
if (isConnected)
|
||||
{
|
||||
if (GetPlaylistLength() < itsMaxPlaylistLength)
|
||||
{
|
||||
id = mpd_sendAddIdCommand(itsConnection, s.GetFile().c_str());
|
||||
mpd_finishCommand(itsConnection);
|
||||
UpdateStatus();
|
||||
}
|
||||
else
|
||||
if (itsErrorHandler)
|
||||
itsErrorHandler(this, MPD_ACK_ERROR_PLAYLIST_MAX, playlist_max_message, NULL);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void MPDConnection::QueueAddSong(const string &path)
|
||||
{
|
||||
if (isConnected && GetPlaylistLength() < itsMaxPlaylistLength)
|
||||
{
|
||||
itsQueue[itsQueueIndex].type = qctAdd;
|
||||
itsQueue[itsQueueIndex++].path = path;
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::QueueAddSong(const Song &s)
|
||||
{
|
||||
itsQueue[itsQueueIndex].type = qctAdd;
|
||||
itsQueue[itsQueueIndex++].path = s.GetFile();
|
||||
}
|
||||
|
||||
void MPDConnection::QueueDeleteSong(int id)
|
||||
{
|
||||
itsQueue[itsQueueIndex].type = qctDelete;
|
||||
itsQueue[itsQueueIndex++].id = id;
|
||||
}
|
||||
|
||||
void MPDConnection::QueueDeleteSongId(int id)
|
||||
{
|
||||
itsQueue[itsQueueIndex].type = qctDeleteID;
|
||||
itsQueue[itsQueueIndex++].id = id;
|
||||
}
|
||||
|
||||
void MPDConnection::CommitQueue()
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
int playlist_length = GetPlaylistLength();
|
||||
mpd_sendCommandListBegin(itsConnection);
|
||||
for (std::map<int, QueueCommand>::const_iterator it = itsQueue.begin(); it != itsQueue.end(); it++)
|
||||
{
|
||||
switch (it->second.type)
|
||||
{
|
||||
case qctAdd:
|
||||
if (playlist_length < itsMaxPlaylistLength)
|
||||
{
|
||||
mpd_sendAddCommand(itsConnection, it->second.path.c_str());
|
||||
playlist_length++;
|
||||
}
|
||||
else
|
||||
if (itsErrorHandler)
|
||||
itsErrorHandler(this, MPD_ACK_ERROR_PLAYLIST_MAX, playlist_max_message, NULL);
|
||||
break;
|
||||
case qctDelete:
|
||||
mpd_sendDeleteCommand(itsConnection, it->second.id);
|
||||
break;
|
||||
case qctDeleteID:
|
||||
mpd_sendDeleteIdCommand(itsConnection, it->second.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mpd_sendCommandListEnd(itsConnection);
|
||||
mpd_finishCommand(itsConnection);
|
||||
UpdateStatus();
|
||||
}
|
||||
itsQueueIndex = 0;
|
||||
itsQueue.clear();
|
||||
}
|
||||
|
||||
void MPDConnection::GetArtists(TagList &v) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendListCommand(itsConnection, MPD_TABLE_ARTIST, NULL);
|
||||
char *item;
|
||||
while ((item = mpd_getNextArtist(itsConnection)) != NULL)
|
||||
{
|
||||
v.push_back(item);
|
||||
delete [] item;
|
||||
}
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::GetAlbums(string artist, TagList &v) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_sendListCommand(itsConnection, MPD_TABLE_ALBUM, artist.empty() ? NULL : artist.c_str());
|
||||
char *item;
|
||||
while ((item = mpd_getNextAlbum(itsConnection)) != NULL)
|
||||
{
|
||||
v.push_back(item);
|
||||
delete [] item;
|
||||
}
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::StartSearch(bool exact_match) const
|
||||
{
|
||||
if (isConnected)
|
||||
mpd_startSearch(itsConnection, exact_match);
|
||||
}
|
||||
|
||||
void MPDConnection::AddSearch(mpd_TagItems item, const string &str) const
|
||||
{
|
||||
if (isConnected)
|
||||
mpd_addConstraintSearch(itsConnection, item, str.c_str());
|
||||
}
|
||||
|
||||
void MPDConnection::CommitSearch(SongList &v) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_commitSearch(itsConnection);
|
||||
mpd_InfoEntity *item = NULL;
|
||||
while ((item = mpd_getNextInfoEntity(itsConnection)) != NULL)
|
||||
{
|
||||
if (item->type == MPD_INFO_ENTITY_TYPE_SONG)
|
||||
{
|
||||
Song *s = new Song(item->info.song);
|
||||
v.push_back(s);
|
||||
}
|
||||
mpd_freeInfoEntity(item);
|
||||
}
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::GetDirectory(const string &path, ItemList &v) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_InfoEntity *item = NULL;
|
||||
mpd_sendLsInfoCommand(itsConnection, path.c_str());
|
||||
while ((item = mpd_getNextInfoEntity(itsConnection)) != NULL)
|
||||
{
|
||||
Item i;
|
||||
switch (item->type)
|
||||
{
|
||||
case MPD_INFO_ENTITY_TYPE_DIRECTORY:
|
||||
i.name = item->info.directory->path;
|
||||
i.type = itDirectory;
|
||||
break;
|
||||
case MPD_INFO_ENTITY_TYPE_SONG:
|
||||
i.song = new Song(item->info.song);
|
||||
i.type = itSong;
|
||||
break;
|
||||
case MPD_INFO_ENTITY_TYPE_PLAYLISTFILE:
|
||||
i.name = item->info.playlistFile->path;
|
||||
i.type = itPlaylist;
|
||||
break;
|
||||
}
|
||||
v.push_back(i);
|
||||
mpd_freeInfoEntity(item);
|
||||
}
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void MPDConnection::GetDirectoryRecursive(const string &path, SongList &v) const
|
||||
{
|
||||
if (isConnected)
|
||||
{
|
||||
mpd_InfoEntity *item = NULL;
|
||||
mpd_sendListallInfoCommand(itsConnection, path.c_str());
|
||||
while ((item = mpd_getNextInfoEntity(itsConnection)) != NULL)
|
||||
{
|
||||
if (item->type == MPD_INFO_ENTITY_TYPE_SONG)
|
||||
{
|
||||
Song *s = new Song(item->info.song);
|
||||
v.push_back(s);
|
||||
}
|
||||
mpd_freeInfoEntity(item);
|
||||
}
|
||||
mpd_finishCommand(itsConnection);
|
||||
}
|
||||
}
|
||||
|
||||
int MPDConnection::CheckForErrors()
|
||||
{
|
||||
int errid = 0;
|
||||
if (itsConnection->error)
|
||||
{
|
||||
if (itsConnection->error == MPD_ERROR_ACK)
|
||||
{
|
||||
// this is to avoid setting too small max size as we check it before fetching current status
|
||||
if (itsConnection->errorCode == MPD_ACK_ERROR_PLAYLIST_MAX && itsMaxPlaylistLength == -1)
|
||||
itsMaxPlaylistLength = 0;
|
||||
|
||||
if (itsErrorHandler)
|
||||
itsErrorHandler(this, itsConnection->errorCode, itsConnection->errorStr, itsErrorHandlerUserdata);
|
||||
errid = itsConnection->errorCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
isConnected = 0; // the rest of errors are fatal to connection
|
||||
if (itsErrorHandler)
|
||||
itsErrorHandler(this, itsConnection->error, itsConnection->errorStr, itsErrorHandlerUserdata);
|
||||
errid = itsConnection->errorCode;
|
||||
}
|
||||
itsLastErrorMessage = itsConnection->errorStr;
|
||||
mpd_clearError(itsConnection);
|
||||
}
|
||||
return errid;
|
||||
}
|
||||
|
||||
void FreeSongList(SongList &l)
|
||||
{
|
||||
for (SongList::iterator i = l.begin(); i != l.end(); i++)
|
||||
delete *i;
|
||||
l.clear();
|
||||
}
|
||||
|
||||
void FreeItemList(ItemList &l)
|
||||
{
|
||||
for (ItemList::iterator i = l.begin(); i != l.end(); i++)
|
||||
delete i->song;
|
||||
l.clear();
|
||||
}
|
||||
|
||||
177
src/mpdpp.h
Normal file
177
src/mpdpp.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/***************************************************************************
|
||||
* 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_MPDPP_H
|
||||
#define HAVE_MPDPP_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "ncmpcpp.h"
|
||||
#include "song.h"
|
||||
|
||||
enum QueueCommandType { qctAdd, qctDelete, qctDeleteID };
|
||||
enum ItemType { itSong, itDirectory, itPlaylist };
|
||||
enum PlayerState { psUnknown, psStop, psPlay, psPause };
|
||||
|
||||
struct MPDStatusChanges
|
||||
{
|
||||
MPDStatusChanges() : Playlist(0), SongID(0), Database(0), DBUpdating(0), Volume(0), ElapsedTime(0), Crossfade(0), Random(0), Repeat(0), PlayerState(0) { }
|
||||
bool Playlist;
|
||||
bool SongID;
|
||||
bool Database;
|
||||
bool DBUpdating;
|
||||
bool Volume;
|
||||
bool ElapsedTime;
|
||||
bool Crossfade;
|
||||
bool Random;
|
||||
bool Repeat;
|
||||
bool PlayerState;
|
||||
};
|
||||
|
||||
struct QueueCommand
|
||||
{
|
||||
QueueCommand() : id(0) { }
|
||||
QueueCommandType type;
|
||||
string path;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct Item
|
||||
{
|
||||
Item() : song(0) { }
|
||||
Song *song;
|
||||
ItemType type;
|
||||
string name;
|
||||
};
|
||||
|
||||
typedef std::vector<Item> ItemList;
|
||||
typedef std::vector<Song *> SongList;
|
||||
typedef std::vector<string> TagList;
|
||||
|
||||
void FreeSongList(SongList &);
|
||||
void FreeItemList(ItemList &);
|
||||
|
||||
class MPDConnection
|
||||
{
|
||||
typedef void (*StatusUpdater) (MPDConnection *, MPDStatusChanges, void *);
|
||||
typedef void (*ErrorHandler) (MPDConnection *, int, string, void *);
|
||||
|
||||
public:
|
||||
MPDConnection();
|
||||
~MPDConnection();
|
||||
|
||||
void Connect();
|
||||
bool Connected();
|
||||
void Disconnect();
|
||||
|
||||
void SetHostname(string hostname) { MPD_HOST = hostname; }
|
||||
void SetPort(int port) { MPD_PORT = port; }
|
||||
void SetTimeout(int timeout) { MPD_TIMEOUT = timeout; }
|
||||
void SetPassword(string password) { MPD_PASSWORD = password; }
|
||||
void SendPassword();
|
||||
|
||||
void SetStatusUpdater(StatusUpdater, void *);
|
||||
void SetErrorHandler(ErrorHandler, void *);
|
||||
void UpdateStatus();
|
||||
void UpdateDirectory(const string &) const;
|
||||
|
||||
void Play() const;
|
||||
void Play(int) const;
|
||||
void PlayID(int) const;
|
||||
void Pause() const;
|
||||
void Stop() const;
|
||||
void Next() const;
|
||||
void Prev() const;
|
||||
void Move(int, int) const;
|
||||
void Seek(int) const;
|
||||
void ClearPlaylist() const;
|
||||
|
||||
PlayerState GetState() const { return isConnected && itsCurrentStatus ? (PlayerState)itsCurrentStatus->state : psUnknown; }
|
||||
bool GetRepeat() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->repeat : 0; }
|
||||
bool GetRandom() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->random : 0; }
|
||||
bool GetDBIsUpdating() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->updatingDb : 0; }
|
||||
int GetVolume() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->volume : 0; }
|
||||
int GetCrossfade() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->crossfade : 0; }
|
||||
long long GetPlaylistID() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->playlist : -1; }
|
||||
long long GetOldPlaylistID() const { return isConnected && itsOldStatus ? itsOldStatus->playlist : -1; }
|
||||
int GetElapsedTime() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->elapsedTime : -1; }
|
||||
|
||||
unsigned int GetMaxPlaylistLength() { return itsMaxPlaylistLength; }
|
||||
int GetPlaylistLength() const { return isConnected && itsCurrentStatus ? itsCurrentStatus->playlistLength : -1; }
|
||||
void GetPlaylistChanges(long long, SongList &) const;
|
||||
|
||||
string GetLastErrorMessage() const { return itsLastErrorMessage; }
|
||||
|
||||
Song GetCurrentSong() const;
|
||||
int GetCurrentSongPos() const;
|
||||
Song GetSong(const string &) const;
|
||||
void GetPlaylistContent(const string &, SongList &) const;
|
||||
|
||||
void SetRepeat(bool) const;
|
||||
void SetRandom(bool) const;
|
||||
void SetVolume(int) const;
|
||||
void SetCrossfade(int) const;
|
||||
|
||||
int AddSong(const string &); // returns id of added song
|
||||
int AddSong(const Song &); // returns id of added song
|
||||
void QueueAddSong(const string &);
|
||||
void QueueAddSong(const Song &);
|
||||
void QueueDeleteSong(int);
|
||||
void QueueDeleteSongId(int);
|
||||
void CommitQueue();
|
||||
|
||||
void StartSearch(bool) const;
|
||||
void AddSearch(mpd_TagItems, const string &) const;
|
||||
void CommitSearch(SongList &v) const;
|
||||
|
||||
void GetArtists(TagList &) const;
|
||||
void GetAlbums(string, TagList &) const;
|
||||
void GetDirectory(const string &, ItemList &) const;
|
||||
void GetDirectoryRecursive(const string &, SongList &) const;
|
||||
|
||||
private:
|
||||
int CheckForErrors();
|
||||
string itsLastErrorMessage;
|
||||
|
||||
mpd_Connection *itsConnection;
|
||||
bool isConnected;
|
||||
|
||||
string MPD_HOST;
|
||||
int MPD_PORT;
|
||||
int MPD_TIMEOUT;
|
||||
string MPD_PASSWORD;
|
||||
|
||||
mpd_Stats *itsOldStats;
|
||||
mpd_Stats *itsCurrentStats;
|
||||
mpd_Status *itsCurrentStatus;
|
||||
mpd_Status *itsOldStatus;
|
||||
|
||||
StatusUpdater itsUpdater;
|
||||
void *itsStatusUpdaterUserdata;
|
||||
ErrorHandler itsErrorHandler;
|
||||
void *itsErrorHandlerUserdata;
|
||||
|
||||
std::map<int, QueueCommand> itsQueue;
|
||||
int itsQueueIndex;
|
||||
unsigned int itsMaxPlaylistLength;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
431
src/ncmpcpp.cpp
431
src/ncmpcpp.cpp
@@ -19,14 +19,13 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "ncmpcpp.h"
|
||||
#include "mpdpp.h"
|
||||
#include "status_checker.h"
|
||||
#include "helpers.h"
|
||||
#include "settings.h"
|
||||
#include "song.h"
|
||||
#include "lyrics.h"
|
||||
|
||||
#define FOR_EACH_MPD_DATA(x) for (; (x); (x) = mpd_data_get_next(x))
|
||||
|
||||
#define BLOCK_STATUSBAR_UPDATE \
|
||||
if (Config.statusbar_visibility) \
|
||||
block_statusbar_update = 1; \
|
||||
@@ -59,18 +58,14 @@
|
||||
const string tag_screen_keydesc = "\tE e : Show song's tags\n";
|
||||
#endif
|
||||
|
||||
char *MPD_HOST = getenv("MPD_HOST");
|
||||
int MPD_PORT = getenv("MPD_PORT") ? atoi(getenv("MPD_PORT")) : 6600;
|
||||
char *MPD_PASSWORD = getenv("MPD_PASSWORD");
|
||||
|
||||
ncmpcpp_config Config;
|
||||
|
||||
vector<Song *> vPlaylist;
|
||||
vector<Song> vSearched;
|
||||
vector<BrowsedItem> vBrowser;
|
||||
SongList vPlaylist;
|
||||
SongList vSearched;
|
||||
ItemList vBrowser;
|
||||
|
||||
vector<string> vArtists;
|
||||
vector<Song> vSongs;
|
||||
TagList vArtists;
|
||||
SongList vSongs;
|
||||
|
||||
vector<int> vFoundPositions;
|
||||
int found_pos = 0;
|
||||
@@ -90,9 +85,7 @@ Scrollpad *sLyrics;
|
||||
Window *wHeader;
|
||||
Window *wFooter;
|
||||
|
||||
MpdObj *conn;
|
||||
MpdData *playlist;
|
||||
MpdData *browser;
|
||||
MPDConnection *Mpd;
|
||||
|
||||
time_t block_delay;
|
||||
time_t timer;
|
||||
@@ -153,16 +146,24 @@ int main(int argc, char *argv[])
|
||||
ReadConfiguration(Config);
|
||||
DefineEmptyTags();
|
||||
|
||||
conn = mpd_new(MPD_HOST, MPD_PORT, MPD_PASSWORD);
|
||||
Mpd = new MPDConnection;
|
||||
|
||||
mpd_set_connection_timeout(conn, Config.mpd_connection_timeout);
|
||||
if (getenv("MPD_HOST"))
|
||||
Mpd->SetHostname(getenv("MPD_HOST"));
|
||||
if (getenv("MPD_PORT"))
|
||||
Mpd->SetPort(atoi(getenv("MPD_PORT")));
|
||||
if (getenv("MPD_PASSWORD"))
|
||||
Mpd->SetPassword(getenv("MPD_PASSWORD"));
|
||||
|
||||
if (mpd_connect(conn) != MPD_OK)
|
||||
Mpd->Connect();
|
||||
|
||||
if (!Mpd->Connected())
|
||||
{
|
||||
printf("Cannot connect to mpd.\n");
|
||||
printf("Cannot connect to mpd (%s)\n", Mpd->GetLastErrorMessage().c_str());
|
||||
return -1;
|
||||
}
|
||||
mpd_send_password(conn);
|
||||
|
||||
Mpd->SendPassword();
|
||||
|
||||
setlocale(LC_ALL,"");
|
||||
initscr();
|
||||
@@ -285,9 +286,6 @@ int main(int argc, char *argv[])
|
||||
wFooter = new Window(0, footer_start_y, COLS, footer_height, "", Config.statusbar_color, brNone);
|
||||
wFooter->Display();
|
||||
|
||||
mpd_signal_connect_error(conn, (ErrorCallback)NcmpcppErrorCallback, NULL);
|
||||
mpd_signal_connect_status_changed(conn, (StatusChangedCallback)NcmpcppStatusChanged, NULL);
|
||||
|
||||
wCurrent = mPlaylist;
|
||||
current_screen = csPlaylist;
|
||||
|
||||
@@ -307,8 +305,21 @@ int main(int argc, char *argv[])
|
||||
sLyrics->Timeout(ncmpcpp_window_timeout);
|
||||
wFooter->Timeout(ncmpcpp_window_timeout);
|
||||
|
||||
Mpd->SetStatusUpdater(NcmpcppStatusChanged, NULL);
|
||||
Mpd->SetErrorHandler(NcmpcppErrorCallback, NULL);
|
||||
|
||||
while (!main_exit)
|
||||
{
|
||||
if (!Mpd->Connected())
|
||||
{
|
||||
ShowMessage("Attempting to reconnect...");
|
||||
Mpd->Disconnect();
|
||||
Mpd->Connect();
|
||||
if (Mpd->Connected())
|
||||
ShowMessage("Connected!");
|
||||
messages_allowed = 0;
|
||||
}
|
||||
|
||||
TraceMpdStatus();
|
||||
|
||||
block_playlist_update = 0;
|
||||
@@ -394,8 +405,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (current_screen == csLibrary && !block_library_update)
|
||||
{
|
||||
MpdData *data;
|
||||
|
||||
if (wCurrent == mLibAlbums && mLibAlbums->Empty())
|
||||
{
|
||||
mLibAlbums->HighlightColor(Config.main_color);
|
||||
@@ -405,53 +414,48 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (wCurrent == mLibArtists)
|
||||
{
|
||||
TagList list;
|
||||
mLibAlbums->Clear();
|
||||
data = mpd_database_get_albums(conn, (char *) mLibArtists->GetCurrentOption().c_str());
|
||||
FOR_EACH_MPD_DATA(data)
|
||||
mLibAlbums->AddOption(data->tag);
|
||||
mpd_data_free(data);
|
||||
|
||||
if (mLibAlbums->Empty())
|
||||
{
|
||||
mLibAlbums->WriteXY(0, 0, "No albums found.");
|
||||
vSongs.clear();
|
||||
mLibSongs->Clear();
|
||||
mpd_database_search_start(conn, 1);
|
||||
mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption().c_str());
|
||||
mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ALBUM, mLibAlbums->GetCurrentOption().c_str());
|
||||
data = mpd_database_search_commit(conn);
|
||||
FOR_EACH_MPD_DATA(data)
|
||||
vSongs.push_back(data->song);
|
||||
mpd_data_free(data);
|
||||
}
|
||||
Mpd->GetAlbums(mLibArtists->GetCurrentOption(), list);
|
||||
for (TagList::const_iterator it = list.begin(); it != list.end(); it++)
|
||||
mLibAlbums->AddOption(*it);
|
||||
}
|
||||
|
||||
vSongs.clear();
|
||||
mLibSongs->Clear(0);
|
||||
mpd_database_search_start(conn, 1);
|
||||
mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption().c_str());
|
||||
mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ALBUM, mLibAlbums->GetCurrentOption().c_str());
|
||||
data = mpd_database_search_commit(conn);
|
||||
FOR_EACH_MPD_DATA(data)
|
||||
vSongs.push_back(data->song);
|
||||
mpd_data_free(data);
|
||||
|
||||
sort(vSongs.begin(), vSongs.end(), SortSongsByTrack);
|
||||
|
||||
bool bold = 0;
|
||||
for (vector<Song>::const_iterator it = vSongs.begin(); it != vSongs.end(); it++)
|
||||
if (mLibAlbums->Empty())
|
||||
{
|
||||
for (vector<Song *>::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
mLibAlbums->WriteXY(0, 0, "No albums found.");
|
||||
mLibSongs->Clear(0);
|
||||
FreeSongList(vSongs);
|
||||
Mpd->StartSearch(1);
|
||||
Mpd->AddSearch(MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption());
|
||||
Mpd->CommitSearch(vSongs);
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeSongList(vSongs);
|
||||
mLibSongs->Clear(0);
|
||||
Mpd->StartSearch(1);
|
||||
Mpd->AddSearch(MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption());
|
||||
Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, mLibAlbums->GetCurrentOption());
|
||||
Mpd->CommitSearch(vSongs);
|
||||
}
|
||||
sort(vSongs.begin(), vSongs.end(), SortSongsByTrack);
|
||||
bool bold = 0;
|
||||
|
||||
for (SongList::const_iterator it = vSongs.begin(); it != vSongs.end(); it++)
|
||||
{
|
||||
for (SongList::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
{
|
||||
if (it->GetHash() == (*j)->GetHash())
|
||||
if ((*it)->GetHash() == (*j)->GetHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bold ? mLibSongs->AddBoldOption(DisplaySong(*it, Config.song_library_format)) : mLibSongs->AddOption(DisplaySong(*it, Config.song_library_format));
|
||||
bold ? mLibSongs->AddBoldOption(DisplaySong(**it, Config.song_library_format)) : mLibSongs->AddOption(DisplaySong(**it, Config.song_library_format));
|
||||
bold = 0;
|
||||
}
|
||||
|
||||
mLibAlbums->Refresh();
|
||||
mLibSongs->Hide();
|
||||
mLibSongs->Display();
|
||||
@@ -494,6 +498,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (input)
|
||||
@@ -574,11 +580,14 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
header_update_status = 1;
|
||||
int mpd_state = mpd_player_get_state(conn);
|
||||
if (mpd_state == MPD_PLAYER_PLAY || mpd_state == MPD_PLAYER_PAUSE)
|
||||
NcmpcppStatusChanged(conn, MPD_CST_ELAPSED_TIME); // restore status
|
||||
PlayerState mpd_state = Mpd->GetState();
|
||||
MPDStatusChanges changes;
|
||||
if (mpd_state == psPlay || mpd_state == psPause)
|
||||
changes.ElapsedTime = 1; // restore status
|
||||
else
|
||||
NcmpcppStatusChanged(conn, MPD_CST_STATE);
|
||||
changes.PlayerState = 1;
|
||||
|
||||
NcmpcppStatusChanged(Mpd, changes, NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -589,7 +598,7 @@ int main(int argc, char *argv[])
|
||||
case csPlaylist:
|
||||
{
|
||||
if (!mPlaylist->Empty())
|
||||
mpd_player_play_id(conn, vPlaylist[mPlaylist->GetChoice()-1]->GetID());
|
||||
Mpd->PlayID(vPlaylist[mPlaylist->GetChoice()-1]->GetID());
|
||||
break;
|
||||
}
|
||||
case csBrowser:
|
||||
@@ -597,7 +606,7 @@ int main(int argc, char *argv[])
|
||||
int ci = mBrowser->GetChoice()-1;
|
||||
switch (vBrowser[ci].type)
|
||||
{
|
||||
case MPD_DATA_TYPE_DIRECTORY:
|
||||
case itDirectory:
|
||||
{
|
||||
found_pos = 0;
|
||||
vFoundPositions.clear();
|
||||
@@ -624,49 +633,38 @@ int main(int argc, char *argv[])
|
||||
GetDirectory(vBrowser[ci].name);
|
||||
break;
|
||||
}
|
||||
case MPD_DATA_TYPE_SONG:
|
||||
case itSong:
|
||||
{
|
||||
string &file = vBrowser[ci].name;
|
||||
mpd_Song *test = mpd_database_get_fileinfo(conn, (char *) file.c_str());
|
||||
if (test)
|
||||
Song s = Mpd->GetSong(vBrowser[ci].name);
|
||||
int id = Mpd->AddSong(s);
|
||||
if (id >= 0)
|
||||
{
|
||||
mpd_playlist_add(conn, (char *) file.c_str());
|
||||
Song s = test;
|
||||
if (s.GetHash() == vPlaylist.back()->GetHash())
|
||||
mpd_player_play_id(conn, vPlaylist.back()->GetID());
|
||||
Mpd->PlayID(id);
|
||||
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
|
||||
mBrowser->Refresh();
|
||||
}
|
||||
mpd_freeSong(test);
|
||||
mBrowser->Refresh();
|
||||
break;
|
||||
}
|
||||
case MPD_DATA_TYPE_PLAYLIST:
|
||||
case itPlaylist:
|
||||
{
|
||||
int howmany = 0;
|
||||
SongList list;
|
||||
ShowMessage("Loading and playing playlist " + vBrowser[ci].name + "...");
|
||||
MpdData *list = mpd_database_get_playlist_content(conn, (char *) vBrowser[ci].name.c_str());
|
||||
Song tmp;
|
||||
if (list)
|
||||
tmp = list->song;
|
||||
FOR_EACH_MPD_DATA(list)
|
||||
{
|
||||
howmany++;
|
||||
mpd_playlist_queue_add(conn, list->song->file);
|
||||
}
|
||||
mpd_data_free(list);
|
||||
mpd_playlist_queue_commit(conn);
|
||||
int new_id;
|
||||
Mpd->GetPlaylistContent(vBrowser[ci].name, list);
|
||||
for(SongList::const_iterator it = list.begin(); it != list.end(); it++)
|
||||
Mpd->QueueAddSong(**it);
|
||||
Mpd->CommitQueue();
|
||||
|
||||
try
|
||||
{
|
||||
new_id = vPlaylist.at(mPlaylist->MaxChoice()-howmany)->GetID();
|
||||
Song *s = vPlaylist.at(vPlaylist.size()-list.size());
|
||||
if (s->GetHash() == list.at(0)->GetHash())
|
||||
Mpd->PlayID(s->GetID());
|
||||
}
|
||||
catch (std::out_of_range)
|
||||
{
|
||||
new_id = -1;
|
||||
ShowMessage("Couldn't play playlist!");
|
||||
}
|
||||
if (new_id >= 0)
|
||||
if (vPlaylist[mPlaylist->MaxChoice()-howmany]->GetHash() == tmp.GetHash())
|
||||
mpd_player_play_id(conn, new_id);
|
||||
FreeSongList(list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -768,12 +766,12 @@ int main(int argc, char *argv[])
|
||||
f.tag()->setComment(NCMPCPP_TO_WSTRING(s.GetComment()));
|
||||
s.GetEmptyFields(0);
|
||||
f.save();
|
||||
mpd_database_update_dir(conn, (char *) s.GetDirectory().c_str());
|
||||
Mpd->UpdateDirectory(s.GetDirectory());
|
||||
if (prev_screen == csSearcher)
|
||||
{
|
||||
int upid = mSearcher->GetChoice()-search_engine_static_option-1;
|
||||
vSearched[upid] = s;
|
||||
mSearcher->UpdateOption(upid+1, DisplaySong(s));
|
||||
*vSearched[upid] = s;
|
||||
mSearcher->UpdateOption(mSearcher->GetChoice(), DisplaySong(s));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -923,17 +921,17 @@ int main(int argc, char *argv[])
|
||||
mSearcher->AddStaticBoldOption("[white]Search results:[/white] [green]Found " + IntoStr(vSearched.size()) + (vSearched.size() > 1 ? " songs" : " song") + "[/green]");
|
||||
mSearcher->AddSeparator();
|
||||
|
||||
for (vector<Song>::const_iterator it = vSearched.begin(); it != vSearched.end(); it++)
|
||||
for (SongList::const_iterator it = vSearched.begin(); it != vSearched.end(); it++)
|
||||
{
|
||||
for (vector<Song *>::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
for (SongList::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
{
|
||||
if ((*j)->GetHash() == it->GetHash())
|
||||
if ((*j)->GetHash() == (*it)->GetHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bold ? mSearcher->AddBoldOption(DisplaySong(*it)) : mSearcher->AddOption(DisplaySong(*it));
|
||||
bold ? mSearcher->AddBoldOption(DisplaySong(**it)) : mSearcher->AddOption(DisplaySong(**it));
|
||||
bold = 0;
|
||||
}
|
||||
|
||||
@@ -958,17 +956,13 @@ int main(int argc, char *argv[])
|
||||
default:
|
||||
{
|
||||
int ci = mSearcher->GetRealChoice()-1;
|
||||
const string &file = vSearched[ci-1].GetFile();
|
||||
mpd_Song *test = mpd_database_get_fileinfo(conn, (char *) file.c_str());
|
||||
if (test)
|
||||
Song s = Mpd->GetSong(vSearched[ci-1]->GetFile());
|
||||
int id = Mpd->AddSong(s);
|
||||
if (id >= 0)
|
||||
{
|
||||
mpd_playlist_add(conn, (char *) file.c_str());
|
||||
Song s = test;
|
||||
if (s.GetHash() == vPlaylist.back()->GetHash())
|
||||
mpd_player_play_id(conn, vPlaylist.back()->GetID());
|
||||
Mpd->PlayID(id);
|
||||
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
|
||||
}
|
||||
mpd_freeSong(test);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -979,64 +973,52 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
Start_Point_For_KEY_SPACE: // same code for KEY_SPACE, but without playing.
|
||||
|
||||
MpdData *data;
|
||||
SongList list;
|
||||
|
||||
if (wCurrent == mLibArtists)
|
||||
{
|
||||
const string &artist = mLibArtists->GetCurrentOption();
|
||||
ShowMessage("Adding all songs artist's: " + artist);
|
||||
mpd_database_search_start(conn, 1);
|
||||
mpd_database_search_add_constraint(conn, MPD_TAG_ITEM_ARTIST, (char *) artist.c_str());
|
||||
data = mpd_database_search_commit(conn);
|
||||
int howmany = 0;
|
||||
Song tmp;
|
||||
if (data)
|
||||
tmp = data->song;
|
||||
FOR_EACH_MPD_DATA(data)
|
||||
{
|
||||
howmany++;
|
||||
mpd_playlist_queue_add(conn, data->song->file);
|
||||
}
|
||||
mpd_data_free(data);
|
||||
mpd_playlist_queue_commit(conn);
|
||||
Mpd->StartSearch(1);
|
||||
Mpd->AddSearch(MPD_TAG_ITEM_ARTIST, artist);
|
||||
Mpd->CommitSearch(list);
|
||||
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
|
||||
Mpd->QueueAddSong(**it);
|
||||
Mpd->CommitQueue();
|
||||
|
||||
if (input == ENTER)
|
||||
{
|
||||
int new_id;
|
||||
try
|
||||
{
|
||||
new_id = vPlaylist.at(mPlaylist->MaxChoice()-howmany)->GetID();
|
||||
Song *s = vPlaylist.at(vPlaylist.size()-list.size());
|
||||
if (s->GetHash() == list.at(0)->GetHash())
|
||||
Mpd->PlayID(s->GetID());
|
||||
}
|
||||
catch (std::out_of_range)
|
||||
{
|
||||
new_id = -1;
|
||||
ShowMessage("Couldn't play!");
|
||||
}
|
||||
if (new_id >= 0)
|
||||
if (vPlaylist[mPlaylist->MaxChoice()-howmany]->GetHash() == tmp.GetHash())
|
||||
mpd_player_play_id(conn, new_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (wCurrent == mLibAlbums)
|
||||
{
|
||||
int howmany = 0;
|
||||
ShowMessage("Adding songs from album: " + mLibAlbums->GetCurrentOption());
|
||||
for (vector<Song>::const_iterator it = vSongs.begin(); it != vSongs.end(); it++, howmany++)
|
||||
mpd_playlist_queue_add(conn, (char *) it->GetFile().c_str());
|
||||
mpd_playlist_queue_commit(conn);
|
||||
for (SongList::const_iterator it = vSongs.begin(); it != vSongs.end(); it++)
|
||||
Mpd->QueueAddSong(**it);
|
||||
Mpd->CommitQueue();
|
||||
if (input == ENTER)
|
||||
{
|
||||
int new_id;
|
||||
try
|
||||
{
|
||||
new_id = vPlaylist.at(mPlaylist->MaxChoice()-howmany)->GetID();
|
||||
Song *s = vPlaylist.at(vPlaylist.size()-vSongs.size());
|
||||
if (s->GetHash() == vSongs.at(0)->GetHash())
|
||||
Mpd->PlayID(s->GetID());
|
||||
}
|
||||
catch (std::out_of_range)
|
||||
{
|
||||
new_id = -1;
|
||||
ShowMessage("Couldn't play!");
|
||||
}
|
||||
if (new_id >= 0)
|
||||
if (vPlaylist[mPlaylist->MaxChoice()-howmany]->GetHash() == vSongs.begin()->GetHash())
|
||||
mpd_player_play_id(conn, new_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1044,19 +1026,26 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
if (!vSongs.empty())
|
||||
{
|
||||
Song &s = vSongs[mLibSongs->GetChoice()-1];
|
||||
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
|
||||
mpd_playlist_add(conn, (char *) s.GetFile().c_str());
|
||||
if (input == ENTER && s.GetHash() == vPlaylist.back()->GetHash())
|
||||
mpd_player_play_id(conn, vPlaylist.back()->GetID());
|
||||
Song &s = *vSongs[mLibSongs->GetChoice()-1];
|
||||
int id = Mpd->AddSong(s);
|
||||
if (id >= 0)
|
||||
{
|
||||
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
|
||||
if (input == ENTER)
|
||||
Mpd->PlayID(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeSongList(list);
|
||||
|
||||
if (input == KEY_SPACE)
|
||||
wCurrent->Go(DOWN);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1067,39 +1056,38 @@ int main(int argc, char *argv[])
|
||||
int ci = mBrowser->GetChoice()-1;
|
||||
switch (vBrowser[ci].type)
|
||||
{
|
||||
case MPD_DATA_TYPE_DIRECTORY:
|
||||
case itDirectory:
|
||||
{
|
||||
string getdir = browsed_dir == "/" ? vBrowser[ci].name : browsed_dir + "/" + vBrowser[ci].name;
|
||||
MpdData *queue = mpd_database_get_directory_recursive(conn, (char *) getdir.c_str());
|
||||
|
||||
FOR_EACH_MPD_DATA(queue)
|
||||
mpd_playlist_queue_add(conn, queue->song->file);
|
||||
mpd_data_free(queue);
|
||||
SongList list;
|
||||
Mpd->GetDirectoryRecursive(getdir, list);
|
||||
|
||||
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
|
||||
Mpd->QueueAddSong(**it);
|
||||
|
||||
FreeSongList(list);
|
||||
ShowMessage("Added folder: " + getdir);
|
||||
mpd_playlist_queue_commit(conn);
|
||||
Mpd->CommitQueue();
|
||||
break;
|
||||
}
|
||||
case MPD_DATA_TYPE_SONG:
|
||||
case itSong:
|
||||
{
|
||||
mpd_Song *test = mpd_database_get_fileinfo(conn, (char *) vBrowser[ci].name.c_str());
|
||||
if (test)
|
||||
{
|
||||
mpd_playlist_queue_add(conn, (char *) vBrowser[ci].name.c_str());
|
||||
Song s = test;
|
||||
Song s = Mpd->GetSong(vBrowser[ci].name);
|
||||
int id = Mpd->AddSong(s);
|
||||
if (id >= 0)
|
||||
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
|
||||
mpd_playlist_queue_commit(conn);
|
||||
}
|
||||
mpd_freeSong(test);
|
||||
break;
|
||||
}
|
||||
case MPD_DATA_TYPE_PLAYLIST:
|
||||
case itPlaylist:
|
||||
{
|
||||
ShowMessage("Loading playlist " + vBrowser[ci].name + "...");
|
||||
MpdData *list = mpd_database_get_playlist_content(conn, (char *) vBrowser[ci].name.c_str());
|
||||
FOR_EACH_MPD_DATA(list)
|
||||
mpd_playlist_queue_add(conn, list->song->file);
|
||||
mpd_data_free(list);
|
||||
mpd_playlist_queue_commit(conn);
|
||||
SongList list;
|
||||
Mpd->GetPlaylistContent(vBrowser[ci].name, list);
|
||||
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
|
||||
Mpd->QueueAddSong(**it);
|
||||
FreeSongList(list);
|
||||
Mpd->CommitQueue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1111,10 +1099,9 @@ int main(int argc, char *argv[])
|
||||
if (id < 0)
|
||||
break;
|
||||
|
||||
mpd_playlist_queue_add(conn, (char *)vSearched[id].GetFile().c_str());
|
||||
Song &s = vSearched[id];
|
||||
Song &s = *vSearched[id];
|
||||
Mpd->AddSong(s);
|
||||
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
|
||||
mpd_playlist_queue_commit(conn);
|
||||
mSearcher->Go(DOWN);
|
||||
}
|
||||
if (current_screen == csLibrary)
|
||||
@@ -1147,7 +1134,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
case '+': // volume up
|
||||
{
|
||||
mpd_status_set_volume(conn, mpd_status_get_volume(conn)+1);
|
||||
Mpd->SetVolume(Mpd->GetVolume()+1);
|
||||
break;
|
||||
}
|
||||
case KEY_LEFT:
|
||||
@@ -1176,7 +1163,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
case '-': //volume down
|
||||
{
|
||||
mpd_status_set_volume(conn, mpd_status_get_volume(conn)-1);
|
||||
Mpd->SetVolume(Mpd->GetVolume()-1);
|
||||
break;
|
||||
}
|
||||
case KEY_DC: // delete position from list
|
||||
@@ -1197,7 +1184,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
id = mPlaylist->GetChoice()-1;
|
||||
|
||||
mpd_playlist_queue_delete_pos(conn, id);
|
||||
Mpd->QueueDeleteSong(id);
|
||||
delete vPlaylist[id];
|
||||
vPlaylist.erase(vPlaylist.begin()+id);
|
||||
mPlaylist->DeleteOption(id+1);
|
||||
@@ -1207,16 +1194,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
mPlaylist->ReadKey(input);
|
||||
}
|
||||
mpd_playlist_queue_commit(conn);
|
||||
Mpd->CommitQueue();
|
||||
mPlaylist->Timeout(ncmpcpp_window_timeout);
|
||||
dont_change_now_playing = 0;
|
||||
block_playlist_update = 0;
|
||||
}
|
||||
if (current_screen == csBrowser)
|
||||
{
|
||||
BLOCK_STATUSBAR_UPDATE;
|
||||
int id = mBrowser->GetChoice()-1;
|
||||
if (vBrowser[id].type == MPD_DATA_TYPE_PLAYLIST)
|
||||
if (vBrowser[id].type == itPlaylist)
|
||||
{
|
||||
block_statusbar_update = 1;
|
||||
wFooter->WriteXY(0, Config.statusbar_visibility, "Delete playlist " + vBrowser[id].name + " ? [y/n] ", 1);
|
||||
@@ -1231,7 +1217,7 @@ int main(int argc, char *argv[])
|
||||
block_statusbar_update = 0;
|
||||
if (in == 'y')
|
||||
{
|
||||
mpd_database_delete_playlist(conn, (char *) vBrowser[id].name.c_str());
|
||||
//mpd_database_delete_playlist(conn, (char *) vBrowser[id].name.c_str());
|
||||
ShowMessage("Playlist " + vBrowser[id].name + " deleted!");
|
||||
GetDirectory("/");
|
||||
}
|
||||
@@ -1245,20 +1231,20 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
case '<':
|
||||
{
|
||||
mpd_player_prev(conn);
|
||||
Mpd->Prev();
|
||||
break;
|
||||
}
|
||||
case '>':
|
||||
{
|
||||
mpd_player_next(conn);
|
||||
Mpd->Next();
|
||||
break;
|
||||
}
|
||||
case 'P': // pause
|
||||
{
|
||||
mpd_player_pause(conn);
|
||||
Mpd->Pause();
|
||||
break;
|
||||
}
|
||||
case 'S': // save playlist
|
||||
/*case 'S': // save playlist
|
||||
{
|
||||
string playlist_name;
|
||||
BLOCK_STATUSBAR_UPDATE;
|
||||
@@ -1285,10 +1271,10 @@ int main(int argc, char *argv[])
|
||||
if (browsed_dir == "/" && !vBrowser.empty())
|
||||
GetDirectory(browsed_dir);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
case 's': // stop
|
||||
{
|
||||
mpd_player_stop(conn);
|
||||
Mpd->Stop();
|
||||
break;
|
||||
}
|
||||
case 'm': // move song up
|
||||
@@ -1315,7 +1301,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
mPlaylist->UpdateOption(pos, DisplaySong(*vPlaylist[pos-1]));
|
||||
mPlaylist->UpdateOption(pos+1, DisplaySong(*vPlaylist[pos]));
|
||||
mpd_playlist_move_pos(conn, pos, pos-1);
|
||||
Mpd->Move(pos, pos-1);
|
||||
mPlaylist->Go(UP);
|
||||
}
|
||||
break;
|
||||
@@ -1324,7 +1310,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
block_playlist_update = 1;
|
||||
int pos = mPlaylist->GetChoice()-1;
|
||||
if (pos+1 < mpd_playlist_get_playlist_length(conn) && !mPlaylist->Empty() && current_screen == csPlaylist)
|
||||
if (pos+1 < vPlaylist.size() && !mPlaylist->Empty() && current_screen == csPlaylist)
|
||||
{
|
||||
std::swap<Song *>(vPlaylist[pos+1], vPlaylist[pos]);
|
||||
if (pos == now_playing)
|
||||
@@ -1344,7 +1330,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
mPlaylist->UpdateOption(pos+2, DisplaySong(*vPlaylist[pos+1]));
|
||||
mPlaylist->UpdateOption(pos+1, DisplaySong(*vPlaylist[pos]));
|
||||
mpd_playlist_move_pos(conn, pos, pos+1);
|
||||
Mpd->Move(pos, pos+1);
|
||||
mPlaylist->Go(DOWN);
|
||||
}
|
||||
break;
|
||||
@@ -1359,7 +1345,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
int songpos, in;
|
||||
|
||||
songpos = mpd_status_get_elapsed_song_time(conn);
|
||||
songpos = Mpd->GetElapsedTime();
|
||||
Song &s = *vPlaylist[now_playing];
|
||||
|
||||
while (1)
|
||||
@@ -1391,7 +1377,7 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
break;
|
||||
}
|
||||
mpd_player_seek(conn, songpos);
|
||||
Mpd->Seek(songpos);
|
||||
|
||||
block_progressbar_update = 0;
|
||||
UNBLOCK_STATUSBAR_UPDATE;
|
||||
@@ -1401,9 +1387,9 @@ int main(int argc, char *argv[])
|
||||
case 'U': case 'u': // update database
|
||||
{
|
||||
if (current_screen == csBrowser)
|
||||
mpd_database_update_dir(conn, (char *) browsed_dir.c_str());
|
||||
Mpd->UpdateDirectory(browsed_dir);
|
||||
else
|
||||
mpd_database_update_dir(conn, "/");
|
||||
Mpd->UpdateDirectory("/");
|
||||
break;
|
||||
}
|
||||
case 'O': case 'o': // go to playing song
|
||||
@@ -1414,22 +1400,22 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
case 'r': // switch repeat state
|
||||
{
|
||||
mpd_player_set_repeat(conn, !mpd_player_get_repeat(conn));
|
||||
Mpd->SetRepeat(!Mpd->GetRepeat());
|
||||
break;
|
||||
}
|
||||
case 'Z':
|
||||
{
|
||||
mpd_playlist_shuffle(conn);
|
||||
//mpd_playlist_shuffle(conn);
|
||||
break;
|
||||
}
|
||||
case 'z': //switch random state
|
||||
{
|
||||
mpd_player_set_random(conn, !mpd_player_get_random(conn));
|
||||
Mpd->SetRandom(!Mpd->GetRandom());
|
||||
break;
|
||||
}
|
||||
case 'x': // switch crossfade state
|
||||
{
|
||||
mpd_status_set_crossfade(conn, (mpd_status_get_crossfade(conn) ? 0 : Config.crossfade_time));
|
||||
Mpd->SetCrossfade(Mpd->GetCrossfade() ? 0 : Config.crossfade_time);
|
||||
break;
|
||||
}
|
||||
case 'E': case 'e': // edit song's tags
|
||||
@@ -1455,9 +1441,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
case csBrowser:
|
||||
{
|
||||
if (vBrowser[id].type == MPD_DATA_TYPE_SONG)
|
||||
if (vBrowser[id].type == itSong)
|
||||
{
|
||||
Song edited = mpd_database_get_fileinfo(conn, vBrowser[id].name.c_str());
|
||||
Song edited = Mpd->GetSong(vBrowser[id].name.c_str());
|
||||
if (GetSongInfo(edited))
|
||||
{
|
||||
wCurrent = mTagEditor;
|
||||
@@ -1474,7 +1460,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
if (id >= search_engine_static_option && !vSearched.empty())
|
||||
{
|
||||
if (GetSongInfo(vSearched[id-search_engine_static_option]))
|
||||
if (GetSongInfo(*vSearched[id-search_engine_static_option]))
|
||||
{
|
||||
wCurrent = mTagEditor;
|
||||
wPrev = mSearcher;
|
||||
@@ -1490,7 +1476,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
if (!vSongs.empty() && wCurrent == mLibSongs)
|
||||
{
|
||||
if (GetSongInfo(vSongs[id]))
|
||||
if (GetSongInfo(*vSongs[id]))
|
||||
{
|
||||
wPrev = wCurrent;
|
||||
wCurrent = mTagEditor;
|
||||
@@ -1517,7 +1503,7 @@ int main(int argc, char *argv[])
|
||||
position = wFooter->GetString(3, TraceMpdStatus);
|
||||
newpos = atoi(position.c_str());
|
||||
if (newpos > 0 && newpos < 100 && !position.empty())
|
||||
mpd_player_seek(conn, vPlaylist[now_playing]->GetTotalLength()*newpos/100.0);
|
||||
Mpd->Seek(vPlaylist[now_playing]->GetTotalLength()*newpos/100.0);
|
||||
UNBLOCK_STATUSBAR_UPDATE;
|
||||
break;
|
||||
}
|
||||
@@ -1528,25 +1514,25 @@ int main(int argc, char *argv[])
|
||||
ShowMessage("Nothing is playing now!");
|
||||
break;
|
||||
}
|
||||
for (vector<Song *>::iterator it = vPlaylist.begin(); it != vPlaylist.begin()+now_playing; it++)
|
||||
mpd_playlist_queue_delete_id(conn, (*it)->GetID());
|
||||
for (vector<Song *>::iterator it = vPlaylist.begin()+now_playing+1; it != vPlaylist.end(); it++)
|
||||
mpd_playlist_queue_delete_id(conn, (*it)->GetID());
|
||||
for (SongList::iterator it = vPlaylist.begin(); it != vPlaylist.begin()+now_playing; it++)
|
||||
Mpd->QueueDeleteSongId((*it)->GetID());
|
||||
for (SongList::iterator it = vPlaylist.begin()+now_playing+1; it != vPlaylist.end(); it++)
|
||||
Mpd->QueueDeleteSongId((*it)->GetID());
|
||||
ShowMessage("Deleting all songs except now playing one...");
|
||||
mpd_playlist_queue_commit(conn);
|
||||
Mpd->CommitQueue();
|
||||
ShowMessage("Songs deleted!");
|
||||
break;
|
||||
}
|
||||
case 'c': // clear playlist
|
||||
{
|
||||
ShowMessage("Clearing playlist...");
|
||||
mpd_playlist_clear(conn);
|
||||
Mpd->ClearPlaylist();
|
||||
ShowMessage("Cleared playlist!");
|
||||
break;
|
||||
}
|
||||
case '/': case '?': // find forward/backward
|
||||
{
|
||||
if (current_screen != csHelp && current_screen != csSearcher || (current_screen == csSearcher && !vSearched.empty()))
|
||||
if ((current_screen != csHelp && current_screen != csSearcher) || (current_screen == csSearcher && !vSearched.empty()))
|
||||
{
|
||||
string how = input == '/' ? "forward" : "backward";
|
||||
found_pos = 0;
|
||||
@@ -1624,7 +1610,7 @@ int main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
if ((wCurrent == mPlaylist && !vPlaylist.empty())
|
||||
|| (wCurrent == mBrowser && vBrowser[mBrowser->GetChoice()-1].type == MPD_DATA_TYPE_SONG)
|
||||
|| (wCurrent == mBrowser && vBrowser[mBrowser->GetChoice()-1].type == itSong)
|
||||
|| (wCurrent == mSearcher && !vSearched.empty() && mSearcher->GetChoice() > search_engine_static_option)
|
||||
|| (wCurrent == mLibSongs))
|
||||
{
|
||||
@@ -1635,13 +1621,15 @@ int main(int argc, char *argv[])
|
||||
s = *vPlaylist[mPlaylist->GetChoice()-1];
|
||||
break;
|
||||
case csBrowser:
|
||||
s = mpd_database_get_fileinfo(conn, vBrowser[mBrowser->GetChoice()-1].name.c_str());
|
||||
s = Mpd->GetSong(vBrowser[mBrowser->GetChoice()-1].name.c_str());
|
||||
break;
|
||||
case csSearcher:
|
||||
s = vSearched[mSearcher->GetChoice()-search_engine_static_option-1];
|
||||
s = *vSearched[mSearcher->GetChoice()-search_engine_static_option-1];
|
||||
break;
|
||||
case csLibrary:
|
||||
s = vSongs[mLibSongs->GetChoice()-1];
|
||||
s = *vSongs[mLibSongs->GetChoice()-1];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1707,11 +1695,11 @@ int main(int argc, char *argv[])
|
||||
bool bold = 0;
|
||||
for (int i = 0; i < vBrowser.size(); i++)
|
||||
{
|
||||
if (vBrowser[i].type == MPD_DATA_TYPE_SONG)
|
||||
if (vBrowser[i].type == itSong)
|
||||
{
|
||||
for (vector<Song *>::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
for (SongList::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
{
|
||||
if ((*it)->GetHash() == vBrowser[i].hash)
|
||||
if ((*it)->GetHash() == vBrowser[i].song->GetHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
@@ -1750,11 +1738,11 @@ int main(int argc, char *argv[])
|
||||
wCurrent->WriteXY(0, 0, "Updating list...");
|
||||
bool bold = 0;
|
||||
int i = search_engine_static_option;
|
||||
for (vector<Song>::const_iterator it = vSearched.begin(); it != vSearched.end(); it++, i++)
|
||||
for (SongList::const_iterator it = vSearched.begin(); it != vSearched.end(); it++, i++)
|
||||
{
|
||||
for (vector<Song *>::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
for (SongList::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
{
|
||||
if ((*j)->GetHash() == it->GetHash())
|
||||
if ((*j)->GetHash() == (*it)->GetHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
@@ -1776,15 +1764,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (mLibArtists->Empty())
|
||||
{
|
||||
MpdData *data = mpd_database_get_artists(conn);
|
||||
|
||||
FOR_EACH_MPD_DATA(data)
|
||||
vArtists.push_back(data->tag);
|
||||
mpd_data_free(data);
|
||||
|
||||
Mpd->GetArtists(vArtists);
|
||||
sort(vArtists.begin(), vArtists.end(), CaseInsensitiveComparison);
|
||||
|
||||
for (vector<string>::const_iterator it = vArtists.begin(); it != vArtists.end(); it++)
|
||||
for (TagList::const_iterator it = vArtists.begin(); it != vArtists.end(); it++)
|
||||
mLibArtists->AddOption(*it);
|
||||
}
|
||||
|
||||
@@ -1808,8 +1790,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
mpd_disconnect(conn);
|
||||
mpd_free(conn);
|
||||
Mpd->Disconnect();
|
||||
curs_set(1);
|
||||
endwin();
|
||||
printf("\n");
|
||||
|
||||
@@ -44,7 +44,7 @@ const bool UNICODE = 0;
|
||||
# include "tag.h"
|
||||
#endif
|
||||
|
||||
#include "libmpd/libmpd.h"
|
||||
#include "libmpdclient.h"
|
||||
|
||||
#include <clocale>
|
||||
#include <ctime>
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
|
||||
#define FOR_EACH_MPD_DATA(x) for (; (x); (x) = mpd_data_get_next(x))
|
||||
|
||||
extern MpdObj *conn;
|
||||
extern MpdData *playlist;
|
||||
extern MPDConnection *Mpd;
|
||||
|
||||
extern ncmpcpp_config Config;
|
||||
|
||||
@@ -39,11 +38,11 @@ extern Menu *mLibSongs;
|
||||
extern Window *wHeader;
|
||||
extern Window *wFooter;
|
||||
|
||||
extern vector<Song *> vPlaylist;
|
||||
extern vector<Song> vSearched;
|
||||
extern vector<BrowsedItem> vBrowser;
|
||||
extern SongList vPlaylist;
|
||||
extern SongList vSearched;
|
||||
extern ItemList vBrowser;
|
||||
|
||||
extern vector<string> vArtists;
|
||||
extern TagList vArtists;
|
||||
|
||||
extern time_t block_delay;
|
||||
extern time_t timer;
|
||||
@@ -86,7 +85,7 @@ string playlist_stats;
|
||||
|
||||
void TraceMpdStatus()
|
||||
{
|
||||
mpd_status_update(conn);
|
||||
Mpd->UpdateStatus();
|
||||
now = time(NULL);
|
||||
|
||||
if (now == timer+Config.playlist_disable_highlight_delay && current_screen == csPlaylist)
|
||||
@@ -107,25 +106,27 @@ void TraceMpdStatus()
|
||||
else
|
||||
block_progressbar_update = !allow_statusbar_unblock;
|
||||
|
||||
switch (mpd_player_get_state(conn))
|
||||
MPDStatusChanges changes;
|
||||
switch (Mpd->GetState())
|
||||
{
|
||||
case MPD_PLAYER_STOP:
|
||||
NcmpcppStatusChanged(conn, MPD_CST_STATE);
|
||||
case psStop:
|
||||
changes.PlayerState = 1;
|
||||
break;
|
||||
case MPD_PLAYER_PLAY: case MPD_PLAYER_PAUSE:
|
||||
NcmpcppStatusChanged(conn, MPD_CST_ELAPSED_TIME); // restore status
|
||||
case psPlay: case psPause:
|
||||
changes.ElapsedTime = 1; // restore status
|
||||
break;
|
||||
}
|
||||
NcmpcppStatusChanged(Mpd, changes, NULL);
|
||||
}
|
||||
//wHeader->WriteXY(0,1, IntoStr(now_playing), 1);
|
||||
}
|
||||
|
||||
void NcmpcppErrorCallback(MpdObj *conn, int errorid, char *msg, void *userdata)
|
||||
void NcmpcppErrorCallback(MPDConnection *Mpd, int errorid, string msg, void *data)
|
||||
{
|
||||
ShowMessage(msg);
|
||||
}
|
||||
|
||||
void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
void NcmpcppStatusChanged(MPDConnection *Mpd, MPDStatusChanges changed, void *data)
|
||||
{
|
||||
int sx, sy;
|
||||
wFooter->DisableBB();
|
||||
@@ -133,47 +134,45 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
wFooter->Bold(1);
|
||||
wFooter->GetXY(sx, sy);
|
||||
|
||||
if ((now_playing != mpd_player_get_current_song_pos(conn) || what & MPD_CST_SONGID) && !dont_change_now_playing)
|
||||
if ((now_playing != Mpd->GetCurrentSongPos() || changed.SongID) && !dont_change_now_playing)
|
||||
{
|
||||
old_playing = now_playing;
|
||||
now_playing = mpd_player_get_current_song_pos(conn);
|
||||
now_playing = Mpd->GetCurrentSongPos();
|
||||
mPlaylist->BoldOption(old_playing+1, 0);
|
||||
mPlaylist->BoldOption(now_playing+1, 1);
|
||||
}
|
||||
|
||||
if (what & MPD_CST_PLAYLIST)
|
||||
if (changed.Playlist)
|
||||
{
|
||||
playlist_old_id = mpd_playlist_get_old_playlist_id(conn);
|
||||
playlist_old_id = Mpd->GetOldPlaylistID();
|
||||
|
||||
if (!block_playlist_update)
|
||||
{
|
||||
int playlist_length = mpd_playlist_get_playlist_length(conn);
|
||||
SongList list;
|
||||
|
||||
int playlist_length = Mpd->GetPlaylistLength();
|
||||
|
||||
if (playlist_length != vPlaylist.size())
|
||||
{
|
||||
if (playlist_length < vPlaylist.size())
|
||||
{
|
||||
mPlaylist->Clear(playlist_length < mPlaylist->GetHeight() && current_screen == csPlaylist);
|
||||
for (vector<Song *>::iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
delete *it;
|
||||
vPlaylist.clear();
|
||||
playlist = mpd_playlist_get_changes(conn, -1);
|
||||
FreeSongList(vPlaylist);
|
||||
Mpd->GetPlaylistChanges(-1, list);
|
||||
}
|
||||
else
|
||||
playlist = mpd_playlist_get_changes(conn, playlist_old_id);
|
||||
Mpd->GetPlaylistChanges(playlist_old_id, list);
|
||||
|
||||
vPlaylist.reserve(playlist_length);
|
||||
|
||||
FOR_EACH_MPD_DATA(playlist)
|
||||
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
|
||||
{
|
||||
Song *s = new Song(playlist->song);
|
||||
vPlaylist.push_back(s);
|
||||
if (now_playing != s->GetPosition())
|
||||
mPlaylist->AddOption(DisplaySong(*s));
|
||||
vPlaylist.push_back(*it);
|
||||
if (now_playing != (*it)->GetPosition())
|
||||
mPlaylist->AddOption(DisplaySong(**it));
|
||||
else
|
||||
mPlaylist->AddBoldOption(DisplaySong(*s));
|
||||
mPlaylist->AddBoldOption(DisplaySong(**it));
|
||||
}
|
||||
mpd_data_free(playlist);
|
||||
|
||||
if (current_screen == csPlaylist)
|
||||
{
|
||||
@@ -189,23 +188,26 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
mPlaylist->BoldOption(old_playing+1, 0);
|
||||
mPlaylist->BoldOption(now_playing+1, 1);
|
||||
|
||||
playlist = mpd_playlist_get_changes(conn, -1);
|
||||
Mpd->GetPlaylistChanges(-1, list);
|
||||
|
||||
for (vector<Song *>::iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++, i++)
|
||||
SongList::iterator j = list.begin();
|
||||
|
||||
for (SongList::iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++, i++)
|
||||
{
|
||||
Song ss = playlist->song;
|
||||
ss.GetEmptyFields(1);
|
||||
|
||||
(*j)->GetEmptyFields(1);
|
||||
(*it)->GetEmptyFields(1);
|
||||
if (**it != ss)
|
||||
if (**it != **j)
|
||||
{
|
||||
(*it)->GetEmptyFields(0);
|
||||
ss.GetEmptyFields(0);
|
||||
**it = ss;
|
||||
mPlaylist->UpdateOption(i, DisplaySong(ss));
|
||||
(*j)->GetEmptyFields(0);
|
||||
Song *s = new Song(**j);
|
||||
**it = *s;
|
||||
mPlaylist->UpdateOption(i, DisplaySong(*s));
|
||||
}
|
||||
playlist = mpd_data_get_next(playlist);
|
||||
j++;
|
||||
}
|
||||
mpd_data_free(playlist);
|
||||
FreeSongList(list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,11 +225,11 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
bool bold = 0;
|
||||
for (int i = 0; i < vBrowser.size(); i++)
|
||||
{
|
||||
if (vBrowser[i].type == MPD_DATA_TYPE_SONG)
|
||||
if (vBrowser[i].type == itSong)
|
||||
{
|
||||
for (vector<Song *>::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
for (SongList::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
|
||||
{
|
||||
if ((*it)->GetHash() == vBrowser[i].hash)
|
||||
if ((*it)->GetHash() == vBrowser[i].song->GetHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
@@ -242,11 +244,11 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
{
|
||||
bool bold = 0;
|
||||
int i = search_engine_static_option;
|
||||
for (vector<Song>::const_iterator it = vSearched.begin(); it != vSearched.end(); it++, i++)
|
||||
for (SongList::const_iterator it = vSearched.begin(); it != vSearched.end(); it++, i++)
|
||||
{
|
||||
for (vector<Song *>::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
for (SongList::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
|
||||
{
|
||||
if ((*j)->GetHash() == it->GetHash())
|
||||
if ((*j)->GetHash() == (*it)->GetHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
@@ -258,7 +260,7 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
}
|
||||
block_library_update = 0;
|
||||
}
|
||||
if(what & MPD_CST_DATABASE)
|
||||
if (changed.Database)
|
||||
{
|
||||
GetDirectory(browsed_dir);
|
||||
if (!mLibArtists->Empty())
|
||||
@@ -266,12 +268,9 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
ShowMessage("Updating artists' list...");
|
||||
mLibArtists->Clear(0);
|
||||
vArtists.clear();
|
||||
MpdData *data = mpd_database_get_artists(conn);
|
||||
FOR_EACH_MPD_DATA(data)
|
||||
vArtists.push_back(data->tag);
|
||||
mpd_data_free(data);
|
||||
Mpd->GetArtists(vArtists);
|
||||
sort(vArtists.begin(), vArtists.end(), CaseInsensitiveComparison);
|
||||
for (vector<string>::const_iterator it = vArtists.begin(); it != vArtists.end(); it++)
|
||||
for (TagList::const_iterator it = vArtists.begin(); it != vArtists.end(); it++)
|
||||
mLibArtists->AddOption(*it);
|
||||
if (current_screen == csLibrary)
|
||||
{
|
||||
@@ -282,24 +281,23 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
}
|
||||
block_library_update = 0;
|
||||
}
|
||||
if (what & MPD_CST_STATE)
|
||||
if (changed.PlayerState)
|
||||
{
|
||||
int mpd_state = mpd_player_get_state(conn);
|
||||
PlayerState mpd_state = Mpd->GetState();
|
||||
switch (mpd_state)
|
||||
{
|
||||
case MPD_PLAYER_PLAY:
|
||||
case psPlay:
|
||||
{
|
||||
Song &s = *vPlaylist[now_playing];
|
||||
player_state = "Playing: ";
|
||||
mPlaylist->BoldOption(now_playing+1, 1);
|
||||
break;
|
||||
}
|
||||
case MPD_PLAYER_PAUSE:
|
||||
case psPause:
|
||||
{
|
||||
player_state = "[Paused] ";
|
||||
break;
|
||||
}
|
||||
case MPD_PLAYER_STOP:
|
||||
case psStop:
|
||||
{
|
||||
WindowTitle("ncmpc++ ver. "VERSION);
|
||||
wFooter->SetColor(Config.progressbar_color);
|
||||
@@ -314,16 +312,32 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
if (!block_statusbar_update && Config.statusbar_visibility)
|
||||
wFooter->WriteXY(0, 1, player_state, player_state.empty());
|
||||
}
|
||||
if ((what & MPD_CST_ELAPSED_TIME))
|
||||
if (changed.SongID)
|
||||
{
|
||||
mpd_Song *current = mpd_playlist_get_current_song(conn);
|
||||
if (!player_state.empty() && current)
|
||||
if (!vPlaylist.empty() && now_playing >= 0)
|
||||
{
|
||||
if (!mPlaylist->Empty())
|
||||
{
|
||||
if (old_playing >= 0)
|
||||
mPlaylist->BoldOption(old_playing+1, 0);
|
||||
mPlaylist->BoldOption(now_playing+1, 1);
|
||||
}
|
||||
if (!Mpd->GetElapsedTime())
|
||||
mvwhline(wFooter->RawWin(), 0, 0, 0, wFooter->GetWidth());
|
||||
}
|
||||
playing_song_scroll_begin = 0;
|
||||
|
||||
if (Mpd->GetState() == psPlay)
|
||||
changed.ElapsedTime = 1;
|
||||
}
|
||||
if (changed.ElapsedTime)
|
||||
{
|
||||
Song s = Mpd->GetCurrentSong();
|
||||
if (!player_state.empty() && !s.Empty())
|
||||
{
|
||||
Song s = current;
|
||||
|
||||
WindowTitle(DisplaySong(s, Config.song_window_title_format));
|
||||
|
||||
int elapsed = mpd_status_get_elapsed_song_time(conn);
|
||||
int elapsed = Mpd->GetElapsedTime();
|
||||
|
||||
if (!block_statusbar_update && Config.statusbar_visibility)
|
||||
{
|
||||
@@ -376,29 +390,29 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
wFooter->WriteXY(0, 1, "", 1);
|
||||
}
|
||||
}
|
||||
if (what & MPD_CST_REPEAT)
|
||||
if (changed.Repeat)
|
||||
{
|
||||
mpd_repeat = (mpd_player_get_repeat(conn) ? "r" : "");
|
||||
mpd_repeat = (Mpd->GetRepeat() ? "r" : "");
|
||||
ShowMessage("Repeat is " + (string)(mpd_repeat.empty() ? "off" : "on"));
|
||||
header_update_status = 1;
|
||||
|
||||
}
|
||||
if (what & MPD_CST_RANDOM)
|
||||
if (changed.Random)
|
||||
{
|
||||
mpd_random = mpd_player_get_random(conn) ? "z" : "";
|
||||
mpd_random = Mpd->GetRandom() ? "z" : "";
|
||||
ShowMessage("Random is " + (string)(mpd_random.empty() ? "off" : "on"));
|
||||
header_update_status = 1;
|
||||
}
|
||||
if (what & MPD_CST_CROSSFADE)
|
||||
if (changed.Crossfade)
|
||||
{
|
||||
int crossfade = mpd_status_get_crossfade(conn);
|
||||
int crossfade = Mpd->GetCrossfade();
|
||||
mpd_crossfade = crossfade ? "x" : "";
|
||||
ShowMessage("Crossfade set to " + IntoStr(crossfade) + " seconds");
|
||||
header_update_status = 1;
|
||||
}
|
||||
if (what & MPD_CST_UPDATING)
|
||||
if (changed.DBUpdating)
|
||||
{
|
||||
mpd_db_updating = mpd_status_db_is_updating(conn) ? "U" : "";
|
||||
mpd_db_updating = Mpd->GetDBIsUpdating() ? "U" : "";
|
||||
ShowMessage(mpd_db_updating.empty() ? "Database update finished!" : "Database update started!");
|
||||
header_update_status = 1;
|
||||
}
|
||||
@@ -424,24 +438,9 @@ void NcmpcppStatusChanged(MpdObj *conn, ChangedStatusType what)
|
||||
wHeader->EnableBB();
|
||||
header_update_status = 0;
|
||||
}
|
||||
if (what & MPD_CST_SONGID)
|
||||
if ((changed.Volume) && Config.header_visibility)
|
||||
{
|
||||
if (!vPlaylist.empty() && now_playing >= 0)
|
||||
{
|
||||
if (!mPlaylist->Empty())
|
||||
{
|
||||
if (old_playing >= 0)
|
||||
mPlaylist->BoldOption(old_playing+1, 0);
|
||||
mPlaylist->BoldOption(now_playing+1, 1);
|
||||
}
|
||||
if (!mpd_status_get_elapsed_song_time(conn))
|
||||
mvwhline(wFooter->RawWin(), 0, 0, 0, wFooter->GetWidth());
|
||||
}
|
||||
playing_song_scroll_begin = 0;
|
||||
}
|
||||
if ((what & MPD_CST_VOLUME) && Config.header_visibility)
|
||||
{
|
||||
int vol = mpd_status_get_volume(conn);
|
||||
int vol = Mpd->GetVolume();
|
||||
volume_state = " Volume: " + IntoStr(vol) + "%";
|
||||
wHeader->SetColor(Config.volume_color);
|
||||
wHeader->WriteXY(wHeader->GetWidth()-volume_state.length(), 0, volume_state);
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
#define HAVE_STATUS_CHECKER_H
|
||||
|
||||
#include "ncmpcpp.h"
|
||||
#include "mpdpp.h"
|
||||
|
||||
void TraceMpdStatus();
|
||||
void NcmpcppStatusChanged(MpdObj *, ChangedStatusType);
|
||||
void NcmpcppErrorCallback(MpdObj *, int, char *, void *);
|
||||
void NcmpcppStatusChanged(MPDConnection *, MPDStatusChanges, void *);
|
||||
void NcmpcppErrorCallback(MPDConnection *, int, string, void *);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user