Store streams to xml file

This commit is contained in:
craig
2011-12-10 12:35:28 +00:00
parent ee2ac1d5f2
commit e2a41bef33
8 changed files with 101 additions and 151 deletions

View File

@@ -98,6 +98,7 @@ SET( CANTATA_MOC_HDRS
models/dirviewproxymodel.h
models/albumsmodel.h
models/streamfetcher.h
models/streamsmodel.h
mpd/mpdconnection.h
widgets/fancytabwidget.h
widgets/treeview.h

27
TODO
View File

@@ -1,14 +1,29 @@
Lyrics
Add next/prev provide buttons - so that can try others.
* Add next/prev provider buttons to lyrics page - so that can try others.
Need better repeat icon.
* Need better repeat icon.
Streams
* Streams
- For KDE, need to use getSaveUrl, etc. and use KIO::NetAccess to obatain file.
- Handle xspf/spiff playlists
- Handle more than 1st entry?? Not sure
- Check that MPD an handle protocols
- Check that MPD can handle protocols before adding
- Store list in XML file in ~/.config/cantata/streams.xml
Sidebar
* Library browser
- Add option to show as list
Iron Maiden
/15 Albums/
-> Click
Killers
/8 Tracks/
....
- Have artist icons
* Sidebar
- Allow to collapse current item
- Add option to select available tabs
* When displaying search results, should expand items to show matched entry
* Use KMessageWidget to display errors?

View File

@@ -210,17 +210,6 @@ QStringList Settings::lyricProviders()
return GET_STRINGLIST("lyricProviders", def);
}
QList<QUrl> Settings::streamUrls()
{
QList<QUrl> urls;
QStringList list=GET_STRINGLIST("streamUrls", QStringList());
foreach (const QString &u, list) {
urls.append(QUrl(u));
}
return urls;
}
QString Settings::page()
{
return GET_STRING("page", QString());
@@ -323,16 +312,6 @@ void Settings::saveLyricProviders(const QStringList &p)
SET_VALUE("lyricProviders", p);
}
void Settings::saveStreamUrls(const QList<QUrl> &u)
{
QStringList list;
foreach (const QUrl &url, u) {
list.append(url.toString());
}
SET_VALUE("streamUrls", list);
}
void Settings::savePage(const QString &v)
{
SET_VALUE("page", v);

View File

@@ -32,8 +32,6 @@ class Wallet;
#else
#include <QtCore/QSettings>
#endif
#include <QtCore/QList>
#include <QtCore/QUrl>
class QTimer;
@@ -64,7 +62,6 @@ public:
int albumCoverSize();
int sidebar();
QStringList lyricProviders();
QList<QUrl> streamUrls();
QString page();
void saveConnectionHost(const QString &v);
@@ -84,7 +81,6 @@ public:
void saveAlbumCoverSize(int v);
void saveSidebar(int v);
void saveLyricProviders(const QStringList &p);
void saveStreamUrls(const QList<QUrl> &u);
void savePage(const QString &v);
void save(bool force=false);
#ifdef ENABLE_KDE_SUPPORT

View File

@@ -26,7 +26,6 @@
#include "mpdconnection.h"
#include <QtGui/QIcon>
#include <QtGui/QToolButton>
#include <QtCore/QFile>
#ifdef ENABLE_KDE_SUPPORT
#include <KDE/KAction>
#include <KDE/KLocale>
@@ -126,7 +125,7 @@ void StreamsPage::refresh()
void StreamsPage::save()
{
model.save();
model.save(true);
}
void StreamsPage::addSelectionToPlaylist()
@@ -165,48 +164,7 @@ void StreamsPage::importXml()
return;
}
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
#ifdef ENABLE_KDE_SUPPORT
KMessageBox::error(this, i18n("Failed to open <i>%1</i>!", fileName));
#else
QMessageBox::critical(this, tr("Error"), tr("Failed to open <i>%1</i>!").arg(fileName));
#endif
return;
}
QString xml;
QTextStream stream(&file);
while (!stream.atEnd()) {
xml+=stream.readLine()+'\n';
}
// int before=model.rowCount();
// if (model.importXml(xml)) {
// int now=model.rowCount();
// if (now==before) {
// #ifdef ENABLE_KDE_SUPPORT
// KMessageBox::information(this, i18n("No new streams imported."));
// #else
// QMessageBox::information(this, tr("Information"), tr("No new streams imported."));
// #endif
// } else if (now==(before+1)) {
// #ifdef ENABLE_KDE_SUPPORT
// KMessageBox::information(this, i18n("1 new stream imported."));
// #else
// QMessageBox::information(this, tr("Information"), tr("1 new stream imported."));
// #endif
// } else if (now>before) {
// #ifdef ENABLE_KDE_SUPPORT
// KMessageBox::information(this, i18n("%1 new streams imported.").arg(now-before));
// #else
// QMessageBox::information(this, tr("Information"), tr("%1 new streams imported.").arg(now-before));
// #endif
// }
// } else {
if (!model.import(xml)) {
if (!model.import(fileName)) {
#ifdef ENABLE_KDE_SUPPORT
KMessageBox::error(this, i18n("Failed to import <i>%1</i>!<br/>Please check this is of the correct type.", fileName));
#else
@@ -227,17 +185,13 @@ void StreamsPage::exportXml()
return;
}
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
if (!model.save(fileName)) {
#ifdef ENABLE_KDE_SUPPORT
KMessageBox::error(this, i18n("Failed to create <i>%1</i>!", fileName));
#else
QMessageBox::critical(this, tr("Error"), tr("Failed to create <i>%1</i>!").arg(fileName));
#endif
return;
}
QTextStream(&file) << model.toXml();
}
void StreamsPage::add()

View File

@@ -50,9 +50,9 @@
QString MusicLibraryModel::cacheDir(const QString &sub, bool create)
{
QString env = qgetenv("XDG_CACHE_HOME");
QString dir = (env.isEmpty() ? QDir::homePath() + "/.cache/" : env) + PACKAGE_NAME"/";
QString dir = (env.isEmpty() ? QDir::homePath() + "/.cache" : env) + QLatin1String("/"PACKAGE_NAME"/");
if(!sub.isEmpty()) {
dir+=sub;;
dir+=sub;
}
if (!dir.endsWith("/")) {
dir=dir+'/';

View File

@@ -23,16 +23,35 @@
#include <QtCore/QModelIndex>
#include <QtCore/QDataStream>
#include <QtCore/QTextStream>
#include <QtCore/QMimeData>
#include <QtCore/QStringList>
#include <QtCore/QTimer>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
#include "streamsmodel.h"
#include "settings.h"
#include "playlisttablemodel.h"
#include "config.h"
static QString configDir()
{
QString env = qgetenv("XDG_CONFIG_HOME");
QString dir = (env.isEmpty() ? QDir::homePath() + "/.config/" : env) + QLatin1String("/"PACKAGE_NAME"/");
QDir d(dir);
return d.exists() || d.mkpath(dir) ? QDir::toNativeSeparators(dir) : QString();
}
static QString getInternalFile()
{
return configDir()+"streams.xml";
}
StreamsModel::StreamsModel()
: QAbstractListModel(0)
, timer(0)
{
reload();
}
@@ -75,44 +94,39 @@ static const QLatin1String constNameQuery("CantataStreamName");
void StreamsModel::reload()
{
beginResetModel();
QList<QUrl> urls=Settings::self()->streamUrls();
items.clear();
itemMap.clear();
foreach (const QUrl &u, urls) {
QUrl url(u);
QString name=url.queryItemValue(constNameQuery);
if (!name.isEmpty()) {
url.removeQueryItem(constNameQuery);
QString str=url.toString();
if (str.endsWith("&")) {
str=str.left(str.length()-1);
url=QUrl(str);
}
items.append(Stream(name, url));
itemMap.insert(url.toString(), name);
}
}
load(getInternalFile(), true);
endResetModel();
}
void StreamsModel::save()
void StreamsModel::save(bool force)
{
QList<QUrl> urls;
foreach (const Stream &s, items) {
QUrl u(s.url);
u.addQueryItem(constNameQuery, s.name);
urls.append(u);
if (force) {
if (timer) {
timer->stop();
}
persist();
} else {
if (!timer) {
timer=new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(persist()));
}
timer->start(30*1000);
}
Settings::self()->saveStreamUrls(urls);
}
#include <QDebug>
bool StreamsModel::import(const QString &str)
bool StreamsModel::load(const QString &filename, bool isInternal)
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return false;
}
QDomDocument doc;
bool valid=false;
bool firstInsert=true;
doc.setContent(str);
bool firstInsert=!isInternal;
doc.setContent(&file);
QDomElement root = doc.documentElement();
if ("cantata" == root.tagName() && root.hasAttribute("version") && "1.0" == root.attribute("version")) {
QDomElement stream = root.firstChildElement("stream");
@@ -144,51 +158,25 @@ bool StreamsModel::import(const QString &str)
}
}
if (!valid) {
// Is it an Amarok .js file???
QStringList lines=str.split('\n', QString::SkipEmptyParts);
foreach (QString line, lines) {
if(-1!=line.indexOf("Station") && 4==line.count('\"') && -1!=line.indexOf("http://")) {
QStringList parts=line.split('\"');
if (parts[3].startsWith("http://")) {
valid=true;
QString name=parts[1];
QString origName=name;
QUrl url=QUrl(parts[3]);
if (!entryExists(QString(), url)) {
int i=1;
for (; i<100 && entryExists(name); ++i) {
name=origName+QLatin1String("_")+QString::number(i);
}
if (i<100) {
if (firstInsert) {
beginResetModel();
firstInsert=false;
}
items.append(Stream(name, url));
itemMap.insert(url.toString(), name);
}
}
}
}
}
}
if (valid) {
save();
Settings::self()->save();
endResetModel();
if (!isInternal) {
if (!firstInsert) {
endResetModel();
}
save();
}
}
return valid;
}
QString StreamsModel::toXml()
bool StreamsModel::save(const QString &filename)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return false;
}
QDomDocument doc;
QDomElement root = doc.createElement("cantata");
root.setAttribute("version", "1.0");
@@ -200,7 +188,8 @@ QString StreamsModel::toXml()
root.appendChild(stream);
}
return doc.toString();
QTextStream(&file) << doc.toString();
return true;
}
bool StreamsModel::add(const QString &name, const QString &url)
@@ -306,3 +295,8 @@ QMimeData * StreamsModel::mimeData(const QModelIndexList &indexes) const
mimeData->setData(PlaylistTableModel::constFileNameMimeType, encodedData);
return mimeData;
}
void StreamsModel::persist()
{
save(getInternalFile());
}

View File

@@ -28,8 +28,12 @@
#include <QtCore/QUrl>
#include <QtCore/QHash>
class QTimer;
class StreamsModel : public QAbstractListModel
{
Q_OBJECT
public:
struct Stream
{
@@ -44,9 +48,9 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &, int) const;
void reload();
void save();
QString toXml();
bool import(const QString &str);
void save(bool force=false);
bool save(const QString &filename);
bool import(const QString &filename) { return load(filename, false); }
bool add(const QString &name, const QString &url);
void edit(const QModelIndex &index, const QString &name, const QString &url);
void remove(const QModelIndex &index);
@@ -55,9 +59,16 @@ public:
Qt::ItemFlags flags(const QModelIndex &index) const;
QMimeData * mimeData(const QModelIndexList &indexes) const;
private:
bool load(const QString &filename, bool isInternal);
private Q_SLOTS:
void persist();
private:
QHash<QString, QString> itemMap;
QList<Stream> items;
QTimer *timer;
};
#endif