If listallinfo fails, usr lsinfo recursively
BUG: 379
This commit is contained in:
committed by
craig.p.drummond
parent
9029248314
commit
cf2e5fbe76
@@ -30,8 +30,8 @@
|
||||
HTTP server, set alwaysUseHttp to true in Cantata's config file. Refer to
|
||||
README for more details.
|
||||
16. Add CMake option to disable building of internal HTTP server.
|
||||
17. If listallinfo fails with MPD 0.18.x then prompt user to check MPD's
|
||||
max_output_buffer_size setting.
|
||||
17. If listallinfo fails, then attempt to retrieve music listing via lsinfo
|
||||
calls on each folder.
|
||||
18. Add CMake option to disable streams, dynamic, and online services. Refer to
|
||||
INSTALL file for details.
|
||||
19. Don't use QKeySequence::Delete to detect delete key event for play queue,
|
||||
|
||||
9
README
9
README
@@ -361,6 +361,14 @@ alwaysUseHttp=<Boolean>
|
||||
from media devices, or when connected to MPD via a standard socket.
|
||||
Default is false.
|
||||
|
||||
alwaysUseLsInfo=<Boolean>
|
||||
By default, Cantata uses MPD's listallinfo command to retrieve the whole
|
||||
music collection. This can fail (especially with MPD 0.18.x which needs
|
||||
more memory), and if it does Cantata will fall back to calling
|
||||
"lsinfo <dir>" for each directory. Setting this config item to true will
|
||||
cause Cantata to always use this alternative method.
|
||||
Default is false.
|
||||
|
||||
e.g.
|
||||
[General]
|
||||
iconTheme=oxygen
|
||||
@@ -373,6 +381,7 @@ undoSteps=20
|
||||
mpdPoll=true
|
||||
mpdListSize=5000
|
||||
alwaysUseHttp=true
|
||||
alwaysUseLsInfo=true
|
||||
|
||||
|
||||
7. CUE Files
|
||||
|
||||
@@ -863,6 +863,11 @@ QString Settings::lang()
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Settings::alwaysUseLsInfo()
|
||||
{
|
||||
return GET_BOOL("alwaysUseLsInfo", false);
|
||||
}
|
||||
|
||||
void Settings::removeConnectionDetails(const QString &v)
|
||||
{
|
||||
if (v==currentConnection()) {
|
||||
|
||||
@@ -209,6 +209,7 @@ public:
|
||||
#ifndef ENABLE_KDE_SUPPORT
|
||||
QString lang();
|
||||
#endif
|
||||
bool alwaysUseLsInfo();
|
||||
|
||||
void removeConnectionDetails(const QString &v);
|
||||
void saveConnectionDetails(const MPDConnectionDetails &v);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "mpdconnection.h"
|
||||
#include "mpdparseutils.h"
|
||||
#include "musiclibraryitemroot.h"
|
||||
#include "mpduser.h"
|
||||
#include "localize.h"
|
||||
#include "utils.h"
|
||||
@@ -53,6 +54,7 @@ void MPDConnection::enableDebug()
|
||||
static const int constSocketCommsTimeout=2000;
|
||||
static const int constMaxReadAttempts=4;
|
||||
static int maxFilesPerAddCommand=10000;
|
||||
static bool alwaysUseLsInfo=false;
|
||||
|
||||
#ifdef ENABLE_KDE_SUPPORT
|
||||
K_GLOBAL_STATIC(MPDConnection, conn)
|
||||
@@ -213,6 +215,7 @@ MPDConnection::MPDConnection()
|
||||
connect(PowerManagement::self(), SIGNAL(resuming()), this, SLOT(reconnect()));
|
||||
#endif
|
||||
maxFilesPerAddCommand=Settings::self()->mpdListSize();
|
||||
alwaysUseLsInfo=Settings::self()->alwaysUseLsInfo();
|
||||
}
|
||||
|
||||
MPDConnection::~MPDConnection()
|
||||
@@ -530,11 +533,11 @@ MPDConnection::Response MPDConnection::sendCommand(const QByteArray &command, bo
|
||||
}
|
||||
} else if (!response.getError(command).isEmpty()) {
|
||||
emit error(i18n("MPD reported the following error: %1", response.getError(command)));
|
||||
} else if ("listallinfo"==command && ver>=MPD_MAKE_VERSION(0,18,0)) {
|
||||
} /*else if ("listallinfo"==command && ver>=MPD_MAKE_VERSION(0,18,0)) {
|
||||
disconnectFromMPD();
|
||||
emit stateChanged(false);
|
||||
emit error(i18n("Failed to load library. Please increase \"max_output_buffer_size\" in MPD's config file."));
|
||||
} else {
|
||||
} */ else {
|
||||
disconnectFromMPD();
|
||||
emit stateChanged(false);
|
||||
emit error(i18n("Failed to send command. Disconnected from %1", details.description()), true);
|
||||
@@ -1207,24 +1210,29 @@ void MPDConnection::update()
|
||||
* Database commands
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get all files in the playlist with detailed info (artist, album,
|
||||
* title, time etc).
|
||||
*/
|
||||
void MPDConnection::loadLibrary()
|
||||
{
|
||||
emit updatingLibrary();
|
||||
Response response=sendCommand("listallinfo");
|
||||
Response response=alwaysUseLsInfo ? Response(false) : sendCommand("listallinfo", false);
|
||||
MusicLibraryItemRoot *root=0;
|
||||
if (response.ok) {
|
||||
emit musicLibraryUpdated(MPDParseUtils::parseLibraryItems(response.data, details.dir, ver), dbUpdate);
|
||||
root = new MusicLibraryItemRoot;
|
||||
MPDParseUtils::parseLibraryItems(response.data, details.dir, ver, root);
|
||||
} else { // MPD >=0.18 can fail listallinfo for large DBs, so get info dir by dir...
|
||||
root = new MusicLibraryItemRoot;
|
||||
if (!listDirInfo("/", root)) {
|
||||
delete root;
|
||||
root=0;
|
||||
}
|
||||
}
|
||||
|
||||
if (root) {
|
||||
root->applyGrouping();
|
||||
emit musicLibraryUpdated(root, dbUpdate);
|
||||
}
|
||||
emit updatedLibrary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the files and dir in the mpdmusic dir.
|
||||
*
|
||||
*/
|
||||
void MPDConnection::loadFolders()
|
||||
{
|
||||
emit updatingFileList();
|
||||
@@ -1451,6 +1459,24 @@ void MPDConnection::toggleStopAfterCurrent(bool afterCurrent)
|
||||
}
|
||||
}
|
||||
|
||||
bool MPDConnection::listDirInfo(const QString &dir, MusicLibraryItemRoot *root)
|
||||
{
|
||||
bool topLevel="/"==dir;
|
||||
Response response=sendCommand(topLevel ? "lsinfo /" : ("lsinfo "+encodeName(dir)));
|
||||
if (response.ok) {
|
||||
QSet<QString> childDirs;
|
||||
MPDParseUtils::parseLibraryItems(response.data, details.dir, ver, root, !topLevel, &childDirs);
|
||||
foreach (const QString &child, childDirs) {
|
||||
if (!listDirInfo(child, root)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MpdSocket::MpdSocket(QObject *parent)
|
||||
: QObject(parent)
|
||||
, tcp(0)
|
||||
|
||||
@@ -337,6 +337,7 @@ private:
|
||||
void parseIdleReturn(const QByteArray &data);
|
||||
bool doMoveInPlaylist(const QString &name, const QList<quint32> &items, quint32 pos, quint32 size);
|
||||
void toggleStopAfterCurrent(bool afterCurrent);
|
||||
bool listDirInfo(const QString &dir, MusicLibraryItemRoot *root);
|
||||
|
||||
private:
|
||||
Thread *thread;
|
||||
|
||||
@@ -409,10 +409,10 @@ void MPDParseUtils::setGroupMultiple(bool g)
|
||||
groupMultipleArtists=g;
|
||||
}
|
||||
|
||||
MusicLibraryItemRoot * MPDParseUtils::parseLibraryItems(const QByteArray &data, const QString &mpdDir, long mpdVersion)
|
||||
void MPDParseUtils::parseLibraryItems(const QByteArray &data, const QString &mpdDir, long mpdVersion,
|
||||
MusicLibraryItemRoot *rootItem, bool parsePlaylists, QSet<QString> *childDirs)
|
||||
{
|
||||
bool canSplitCue=mpdVersion>=MPD_MAKE_VERSION(0,17,0);
|
||||
MusicLibraryItemRoot * const rootItem = new MusicLibraryItemRoot;
|
||||
QByteArray currentItem;
|
||||
QList<QByteArray> lines = data.split('\n');
|
||||
int amountOfLines = lines.size();
|
||||
@@ -422,9 +422,13 @@ MusicLibraryItemRoot * MPDParseUtils::parseLibraryItems(const QByteArray &data,
|
||||
QString unknown=i18n("Unknown");
|
||||
|
||||
for (int i = 0; i < amountOfLines; i++) {
|
||||
currentItem += lines.at(i);
|
||||
QByteArray line=lines.at(i);
|
||||
if (childDirs && line.startsWith("directory: ")) {
|
||||
childDirs->insert(QString::fromUtf8(line.remove(0, 11)));
|
||||
}
|
||||
currentItem += line;
|
||||
currentItem += "\n";
|
||||
if (i == lines.size() - 1 || lines.at(i + 1).startsWith("file:") || lines.at(i + 1).startsWith("playlist:")) {
|
||||
if (i == amountOfLines - 1 || lines.at(i + 1).startsWith("file:") || lines.at(i + 1).startsWith("playlist:")) {
|
||||
Song currentSong = parseSong(currentItem, false);
|
||||
currentItem.clear();
|
||||
if (currentSong.file.isEmpty()) {
|
||||
@@ -432,6 +436,11 @@ MusicLibraryItemRoot * MPDParseUtils::parseLibraryItems(const QByteArray &data,
|
||||
}
|
||||
|
||||
if (Song::Playlist==currentSong.type) {
|
||||
// lsinfo / will return all stored playlists - but this is deprecated.
|
||||
if (!parsePlaylists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MusicLibraryItemAlbum *prevAlbum=albumItem;
|
||||
QString prevSongFile=songItem ? songItem->file() : QString();
|
||||
QList<Song> cueSongs; // List of songs from cue file
|
||||
@@ -603,10 +612,10 @@ MusicLibraryItemRoot * MPDParseUtils::parseLibraryItems(const QByteArray &data,
|
||||
albumItem->addGenre(currentSong.genre);
|
||||
artistItem->addGenre(currentSong.genre);
|
||||
rootItem->addGenre(currentSong.genre);
|
||||
} else if (childDirs) {
|
||||
|
||||
}
|
||||
}
|
||||
rootItem->applyGrouping();
|
||||
return rootItem;
|
||||
}
|
||||
|
||||
DirViewItemRoot * MPDParseUtils::parseDirViewItems(const QByteArray &data)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define MPD_PARSE_UTILS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QSet>
|
||||
|
||||
struct Song;
|
||||
class Playlist;
|
||||
@@ -60,7 +61,8 @@ namespace MPDParseUtils
|
||||
extern void setGroupSingle(bool g);
|
||||
extern bool groupMultiple();
|
||||
extern void setGroupMultiple(bool g);
|
||||
extern MusicLibraryItemRoot * parseLibraryItems(const QByteArray &data, const QString &mpdDir, long mpdVersion);
|
||||
extern void parseLibraryItems(const QByteArray &data, const QString &mpdDir, long mpdVersion,
|
||||
MusicLibraryItemRoot *rootItem, bool parsePlaylists=true, QSet<QString> *childDirs=0);
|
||||
extern DirViewItemRoot * parseDirViewItems(const QByteArray &data);
|
||||
extern QList<Output> parseOuputs(const QByteArray &data);
|
||||
extern QString addStreamName(const QString &url, const QString &name);
|
||||
|
||||
Reference in New Issue
Block a user