Store streams to xml file
This commit is contained in:
@@ -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
27
TODO
@@ -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?
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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+'/';
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user