Commit 3700393d authored by Matthieu Gallien's avatar Matthieu Gallien 🎵
Browse files

integrate back some code to access UPnP shares

parent d9acbac4
......@@ -22,6 +22,7 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND)
trackslistener.cpp
elisaapplication.cpp
audiowrapper.cpp
viewpagesmodel.cpp
MediaServer.qml
Theme.qml
......@@ -85,6 +86,9 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND)
upnp/didlparser.cpp
upnp/upnplistener.cpp
upnp/upnpdiscoverallmusic.cpp
upnp/upnpalbummodel.cpp
upnp/remoteserverentry.cpp
upnp/abstractalbummodel.cpp
)
endif()
......
......@@ -439,15 +439,14 @@ ApplicationWindow {
width: viewModeView.width
}
model: ListModel {
model: ViewPagesModel {
id: pageModel
Component.onCompleted:
{
insert(0, {"name": i18nc("Title of the view of the playlist", "Now Playing")})
insert(1, {"name": i18nc("Title of the view of all albums", "Albums")})
insert(2, {"name": i18nc("Title of the view of all artists", "Artists")})
}
deviceId: 'urn:schemas-upnp-org:device:MediaServer:1'
browseFlag: globalBrowseFlag
filter: globalFilter
sortCriteria: globalSortCriteria
}
itemDelegate: Rectangle {
......
......@@ -263,6 +263,12 @@ bool MusicAlbum::isEmpty() const
return d->mTracks.isEmpty();
}
void MusicAlbum::clear()
{
d->mTracks.clear();
d->mTracksCount = 0;
}
void MusicAlbum::removeTrackFromIndex(int index)
{
if (index < 0 || index >= tracksCount()) {
......
......@@ -102,6 +102,8 @@ public:
bool isEmpty() const;
void clear();
void removeTrackFromIndex(int index);
void insertTrack(const MusicAudioTrack &newTrack, int index);
......
This diff is collapsed.
/*
* Copyright 2015-2016 Matthieu Gallien <matthieu_gallien@yahoo.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef ABSTRACTALBUMMODEL_H
#define ABSTRACTALBUMMODEL_H
#include <QtCore/QAbstractItemModel>
#include <QtCore/QVector>
#include <QtCore/QHash>
#include <QtCore/QString>
#include "musicalbum.h"
#include "musicaudiotrack.h"
class AbstractAlbumModelPrivate;
class MusicStatistics;
class AbstractAlbumModel : public QAbstractItemModel
{
Q_OBJECT
Q_PROPERTY(MusicStatistics* musicDatabase
READ musicDatabase
WRITE setMusicDatabase
NOTIFY musicDatabaseChanged)
public:
enum ItemClass {
Container = 0,
Album = 1,
Artist = 2,
AudioTrack = 3,
};
enum ColumnsRoles {
TitleRole = Qt::UserRole + 1,
DurationRole = TitleRole + 1,
CreatorRole = DurationRole + 1,
ArtistRole = CreatorRole + 1,
AlbumRole = ArtistRole + 1,
TrackNumberRole = AlbumRole + 1,
RatingRole = TrackNumberRole + 1,
ImageRole = RatingRole + 1,
ResourceRole = ImageRole + 1,
ItemClassRole = ResourceRole + 1,
CountRole = ItemClassRole + 1,
IdRole = CountRole + 1,
IsPlayingRole = IdRole + 1,
};
explicit AbstractAlbumModel(QObject *parent = 0);
virtual ~AbstractAlbumModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
MusicStatistics* musicDatabase() const;
Q_SIGNALS:
void musicDatabaseChanged();
void newAlbum(const MusicAlbum &album);
void newAudioTrack(const MusicAudioTrack &audioTrack);
void refreshContent();
public Q_SLOTS:
void setMusicDatabase(MusicStatistics* musicDatabase);
void albumsList(const QVector<MusicAlbum> &allAlbums);
void tracksList(const QHash<QString, QVector<MusicAudioTrack> > &tracks, const QHash<QString, QString> &covers);
private Q_SLOTS:
private:
QVariant internalDataAlbum(const MusicAlbum &albumData, int role) const;
QVariant internalDataTrack(const MusicAudioTrack &track, const QModelIndex &index, int role) const;
void initDatabase();
AbstractAlbumModelPrivate *d;
};
Q_DECLARE_METATYPE(AbstractAlbumModel::ItemClass)
#endif // ABSTRACTALBUMMODEL_H
/*
* Copyright 2015 Matthieu Gallien <matthieu_gallien@yahoo.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "remoteserverentry.h"
#include "upnpcontrolcontentdirectory.h"
#include "upnpdevicedescription.h"
#include "upnpservicedescription.h"
#include "upnpdevicedescriptionparser.h"
#include "upnpalbummodel.h"
#include <QtCore/QDebug>
RemoteServerEntry::RemoteServerEntry(QSharedPointer<UpnpDeviceDescription> device,
QSharedPointer<UpnpDeviceDescriptionParser> deviceParser,
QObject *parent)
: QObject(parent), mIsReady(false), mDevice(device), mDeviceParser(deviceParser), mAlbumModel(new UpnpAlbumModel)
{
connect(mDeviceParser.data(), &UpnpDeviceDescriptionParser::descriptionParsed, this, &RemoteServerEntry::descriptionParsed);
mNewService.reset(new UpnpControlContentDirectory());
}
UpnpControlContentDirectory *RemoteServerEntry::contentDirectory() const
{
return mNewService.data();
}
void RemoteServerEntry::setContentDirectory(UpnpControlContentDirectory *value)
{
Q_UNUSED(value);
}
bool RemoteServerEntry::isReady() const
{
return mIsReady;
}
void RemoteServerEntry::setIsReady(bool value)
{
mIsReady = value;
Q_EMIT isReadyChanged();
}
UpnpAlbumModel *RemoteServerEntry::albumModel() const
{
return mAlbumModel.data();
}
void RemoteServerEntry::descriptionParsed(const QString &UDN)
{
Q_UNUSED(UDN);
mDeviceParser.clear();
const auto &allServices = mDevice->servicesName();
auto serviceIndex = allServices.indexOf(QStringLiteral("urn:schemas-upnp-org:service:ContentDirectory:1"));
if (serviceIndex == -1) {
return;
}
mNewService->setDescription(mDevice->serviceByIndex(serviceIndex).data());
mAlbumModel->setContentDirectory(mNewService.data());
setIsReady(true);
Q_EMIT contentDirectoryChanged();
}
#include "moc_remoteserverentry.cpp"
/*
* Copyright 2015 Matthieu Gallien <matthieu_gallien@yahoo.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef REMOTESERVERENTRY_H
#define REMOTESERVERENTRY_H
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
class UpnpControlContentDirectory;
class UpnpDeviceDescription;
class UpnpDeviceDescriptionParser;
class UpnpAlbumModel;
class RemoteServerEntry : public QObject
{
Q_OBJECT
Q_PROPERTY(UpnpControlContentDirectory* contentDirectory
READ contentDirectory
WRITE setContentDirectory
NOTIFY contentDirectoryChanged)
Q_PROPERTY(UpnpAlbumModel* albumModel
READ albumModel
NOTIFY albumModelChanged)
Q_PROPERTY(bool isReady
READ isReady
WRITE setIsReady
NOTIFY isReadyChanged)
public:
explicit RemoteServerEntry(QSharedPointer<UpnpDeviceDescription> device,
QSharedPointer<UpnpDeviceDescriptionParser> deviceParser,
QObject *parent = 0);
UpnpControlContentDirectory* contentDirectory() const;
void setContentDirectory(UpnpControlContentDirectory *value);
bool isReady() const;
void setIsReady(bool value);
UpnpAlbumModel* albumModel() const;
Q_SIGNALS:
void contentDirectoryChanged();
void isReadyChanged();
void albumModelChanged();
public Q_SLOTS:
private Q_SLOTS:
void descriptionParsed(const QString &UDN);
private:
bool mIsReady;
QSharedPointer<UpnpDeviceDescription> mDevice;
QSharedPointer<UpnpDeviceDescriptionParser> mDeviceParser;
QSharedPointer<UpnpAlbumModel> mAlbumModel;
QSharedPointer<UpnpControlContentDirectory> mNewService;
};
#endif // REMOTESERVERENTRY_H
/*
* Copyright 2015-2016 Matthieu Gallien <matthieu_gallien@yahoo.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "upnpalbummodel.h"
#include "musicstatistics.h"
#include "didlparser.h"
#include "upnp/upnpcontrolcontentdirectory.h"
#include <QtXml/QDomDocument>
#include <QtCore/QVector>
#include <QtCore/QUrl>
#include <QtCore/QPointer>
#include <QtCore/QDebug>
class UpnpAlbumModelPrivate
{
public:
UpnpControlContentDirectory *mContentDirectory = nullptr;
bool mUseLocalIcons = false;
DidlParser mDidlParser;
QString mBrowseFlag;
QString mFilter;
QString mSortCriteria;
QVector<QString> mChilds;
QHash<QString, QPointer<DidlParser>> mAlbumParsers;
QString mServerName;
};
UpnpAlbumModel::UpnpAlbumModel(QObject *parent) : AbstractAlbumModel(parent), d(new UpnpAlbumModelPrivate)
{
d->mDidlParser.setSearchCriteria(QStringLiteral("upnp:class = \"object.container.album.musicAlbum\""));
d->mDidlParser.setParentId(QStringLiteral("0"));
connect(&d->mDidlParser, &DidlParser::isDataValidChanged, this, &UpnpAlbumModel::contentChanged);
}
UpnpAlbumModel::~UpnpAlbumModel()
{
delete d;
}
bool UpnpAlbumModel::canFetchMore(const QModelIndex &parent) const
{
if (!parent.isValid()) {
return false;
}
if (parent.internalId() != 0) {
return false;
}
if (!d->mAlbumParsers.contains(d->mChilds[parent.row()])) {
return true;
}
auto childParser = d->mAlbumParsers[d->mChilds[parent.row()]];
if (!childParser) {
return true;
}
return false;
}
void UpnpAlbumModel::fetchMore(const QModelIndex &parent)
{
if (!d->mAlbumParsers.contains(d->mChilds[parent.row()])) {
d->mAlbumParsers[d->mChilds[parent.row()]] = new DidlParser(this);
auto newParser = d->mAlbumParsers[d->mChilds[parent.row()]];
newParser->setBrowseFlag(d->mDidlParser.browseFlag());
newParser->setFilter(d->mDidlParser.filter());
newParser->setSortCriteria(d->mDidlParser.sortCriteria());
newParser->setContentDirectory(d->mDidlParser.contentDirectory());
newParser->setParentId(d->mChilds[parent.row()]);
connect(newParser, &DidlParser::isDataValidChanged, this, &UpnpAlbumModel::contentChanged);
newParser->browse();
}
}
QVariant UpnpAlbumModel::internalDataTrack(const QModelIndex &index, int role, DidlParser *currentParser) const
{
ColumnsRoles convertedRole = static_cast<ColumnsRoles>(role);
if (index.row() < 0 || index.row() >= currentParser->newMusicTrackIds().size()) {
return {};
}
switch(convertedRole)
{
case ColumnsRoles::TitleRole:
return currentParser->newMusicTracks()[index.row()].title();
case ColumnsRoles::DurationRole:
if (currentParser->newMusicTracks()[index.row()].duration().hour() == 0) {
return currentParser->newMusicTracks()[index.row()].duration().toString(QStringLiteral("mm:ss"));
} else {
return currentParser->newMusicTracks()[index.row()].duration().toString();
}
case ColumnsRoles::CreatorRole:
return currentParser->newMusicTracks()[index.row()].artist();
case ColumnsRoles::ArtistRole:
return currentParser->newMusicTracks()[index.row()].artist();
case ColumnsRoles::AlbumRole:
return currentParser->newMusicTracks()[index.row()].albumName();
case ColumnsRoles::TrackNumberRole:
return currentParser->newMusicTracks()[index.row()].trackNumber();
case ColumnsRoles::RatingRole:
return 0;
case ColumnsRoles::ImageRole:
return data(index.parent(), role);
case ColumnsRoles::ResourceRole:
return currentParser->newMusicTracks()[index.row()].resourceURI();
case ColumnsRoles::ItemClassRole:
return {};
case ColumnsRoles::CountRole:
return {};
case ColumnsRoles::IdRole:
return currentParser->newMusicTracks()[index.row()].id();
case ColumnsRoles::IsPlayingRole:
return false;
}
return {};
}
UpnpControlContentDirectory *UpnpAlbumModel::contentDirectory() const
{
return d->mContentDirectory;
}
DidlParser *UpnpAlbumModel::didlParser() const
{
return &d->mDidlParser;
}
const QString &UpnpAlbumModel::browseFlag() const
{
return d->mBrowseFlag;
}
const QString &UpnpAlbumModel::filter() const
{
return d->mFilter;
}
const QString &UpnpAlbumModel::sortCriteria() const
{
return d->mSortCriteria;
}
QString UpnpAlbumModel::serverName() const
{
return d->mServerName;
}
bool UpnpAlbumModel::useLocalIcons() const
{
return d->mUseLocalIcons;
}
void UpnpAlbumModel::setContentDirectory(UpnpControlContentDirectory *directory)
{
if (directory) {
beginResetModel();
}
if (d->mContentDirectory) {
disconnect(d->mContentDirectory, &UpnpControlContentDirectory::systemUpdateIDChanged,
&d->mDidlParser, &DidlParser::systemUpdateIDChanged);
}
d->mContentDirectory = directory;
if (!d->mContentDirectory) {
Q_EMIT contentDirectoryChanged();
return;
}
connect(d->mContentDirectory, &UpnpControlContentDirectory::systemUpdateIDChanged,
&d->mDidlParser, &DidlParser::systemUpdateIDChanged);
d->mDidlParser.setContentDirectory(directory);
d->mDidlParser.setBrowseFlag(browseFlag());
d->mDidlParser.setFilter(filter());
d->mDidlParser.setSortCriteria(sortCriteria());
d->mDidlParser.search();
endResetModel();
Q_EMIT contentDirectoryChanged();
}
void UpnpAlbumModel::setBrowseFlag(const QString &flag)
{
d->mBrowseFlag = flag;
Q_EMIT browseFlagChanged();
}
void UpnpAlbumModel::setFilter(const QString &flag)
{
d->mFilter = flag;
Q_EMIT filterChanged();
}
void UpnpAlbumModel::setSortCriteria(const QString &criteria)
{
d->mSortCriteria = criteria;
Q_EMIT sortCriteriaChanged();
}
void UpnpAlbumModel::setServerName(QString serverName)
{
if (d->mServerName == serverName)
return;
d->mServerName = serverName;
emit serverNameChanged();
}
void UpnpAlbumModel::setUseLocalIcons(bool useLocalIcons)
{
if (d->mUseLocalIcons == useLocalIcons)
return;
d->mUseLocalIcons = useLocalIcons;