diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,13 +129,13 @@ DESCRIPTION "File management libraries used for file browsing." TYPE RECOMMENDED) -find_package(UPNPQT CONFIG QUIET) -set_package_properties(UPNPQT PROPERTIES +find_package(UpnpLibQt CONFIG QUIET) +set_package_properties(UpnpLibQt PROPERTIES DESCRIPTION "UPNP layer build with Qt 5. UPnP support is currently broken. You should probably avoid this dependency." - URL "https://gitlab.com/homeautomationqt/upnp-player-qt" + URL "https://cgit.kde.org/scratch/mgallien/upnp-lib-qt.git" TYPE OPTIONAL) -if (UPNPQT_FOUND) +if (UpnpLibQt_FOUND) message(WARNING "UPnP support is experimental and may not work.") endif() diff --git a/config-upnp-qt.h.cmake b/config-upnp-qt.h.cmake --- a/config-upnp-qt.h.cmake +++ b/config-upnp-qt.h.cmake @@ -6,7 +6,7 @@ #cmakedefine01 KF5Crash_FOUND -#cmakedefine01 UPNPQT_FOUND +#cmakedefine01 UpnpLibQt_FOUND #cmakedefine01 Qt5DBus_FOUND diff --git a/elisa.categories b/elisa.categories --- a/elisa.categories +++ b/elisa.categories @@ -4,3 +4,4 @@ org.kde.elisa.player.vlc elisa (vlc) DEFAULT_SEVERITY [INFO] IDENTIFIER [orgKdeElisaPlayerVlc] org.kde.elisa.player.qtMultimedia elisa (qtmultimedia) DEFAULT_SEVERITY [INFO] IDENTIFIER [orgKdeElisaPlayerQtMultimedia] org.kde.elisa.baloo elisa (baloo) DEFAULT_SEVERITY [INFO] IDENTIFIER [orgKdeElisaBaloo] +org.kde.elisa.upnp elisa (UPnP) DEFAULT_SEVERITY [INFO] IDENTIFIER [orgKdeElisaUpnp] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,7 @@ models/trackmetadatamodel.cpp models/trackcontextmetadatamodel.cpp models/viewsmodel.cpp + models/upnpalbummodel.cpp ) ecm_qt_declare_logging_category(elisaLib_SOURCES @@ -135,15 +136,21 @@ ) endif() -if (UPNPQT_FOUND) +if (UpnpLibQt_FOUND) + ecm_qt_declare_logging_category(elisaLib_SOURCES + HEADER "upnpLogging.h" + IDENTIFIER "orgKdeElisaUpnp" + CATEGORY_NAME "org.kde.elisa.upnp" + DEFAULT_SEVERITY Info + ) + set(elisaLib_SOURCES ${elisaLib_SOURCES} upnp/upnpcontrolcontentdirectory.cpp upnp/upnpcontentdirectorymodel.cpp upnp/upnpcontrolconnectionmanager.cpp upnp/upnpcontrolmediaserver.cpp upnp/didlparser.cpp - upnp/upnplistener.cpp upnp/upnpdiscoverallmusic.cpp ) endif() @@ -258,6 +265,13 @@ ) endif() +if (UpnpLibQt_FOUND) + target_link_libraries(elisaLib + LINK_PUBLIC + UPNP::UpnpLibQt + ) +endif() + generate_export_header(elisaLib BASE_NAME ElisaLib EXPORT_FILE_NAME elisaLib_export.h) set_target_properties(elisaLib PROPERTIES diff --git a/src/databaseinterface.h b/src/databaseinterface.h --- a/src/databaseinterface.h +++ b/src/databaseinterface.h @@ -334,6 +334,21 @@ using ListGenreDataType = QList; + class NetworkServiceDataType : public DataType + { + public: + + using DataType::DataType; + + QString title() const + { + return operator[](key_type::TitleRole).toString(); + } + + }; + + using ListNetworkServiceDataType = QList; + enum PropertyType { DatabaseId, DisplayRole, diff --git a/src/elisaqmlplugin.cpp b/src/elisaqmlplugin.cpp --- a/src/elisaqmlplugin.cpp +++ b/src/elisaqmlplugin.cpp @@ -17,20 +17,12 @@ #include "elisaqmlplugin.h" -#if defined UPNPQT_FOUND && UPNPQT_FOUND -#include "upnp/upnpcontrolconnectionmanager.h" -#include "upnp/upnpcontrolmediaserver.h" -#include "upnp/upnpcontrolcontentdirectory.h" -#include "upnp/upnpcontentdirectorymodel.h" -#include "upnpdevicedescription.h" -#include "upnp/didlparser.h" -#include "upnp/upnpdiscoverallmusic.h" - -#include "upnpssdpengine.h" -#include "upnpabstractservice.h" -#include "upnpcontrolabstractdevice.h" -#include "upnpcontrolabstractservice.h" -#include "upnpbasictypes.h" +#include "config-upnp-qt.h" + +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + +#include + #endif #include "elisautils.h" @@ -155,7 +147,9 @@ qRegisterMetaType("ModelDataLoader::ListAlbumDataType"); qRegisterMetaType("ModelDataLoader::ListArtistDataType"); qRegisterMetaType("ModelDataLoader::ListGenreDataType"); + qRegisterMetaType("ModelDataLoader::ListNetworkServiceDataType"); qRegisterMetaType("ModelDataLoader::AlbumDataType"); + qRegisterMetaType("ModelDataLoader::NetworkServiceDataType"); qRegisterMetaType("TracksListener::ListTrackDataType"); qRegisterMetaType>(); qRegisterMetaType(); @@ -174,6 +168,7 @@ qRegisterMetaType("TracksListener::TrackDataType"); qRegisterMetaType("ViewManager::ViewsType"); qRegisterMetaType("ViewManager::SortOrder"); + qRegisterMetaType("UpnpDiscoveryResult"); qmlRegisterUncreatableType(uri, 1, 0, "ElisaApplication", QStringLiteral("only one and done in c++")); qmlRegisterUncreatableMetaObject(ElisaUtils::staticMetaObject, uri, 1, 0, "ElisaUtils", QStringLiteral("Namespace ElisaUtils")); diff --git a/src/elisautils.h b/src/elisautils.h --- a/src/elisautils.h +++ b/src/elisautils.h @@ -54,6 +54,7 @@ Composer, Track, FileName, + NetworkService, Unknown, Radio, }; diff --git a/src/mediaplaylist.cpp b/src/mediaplaylist.cpp --- a/src/mediaplaylist.cpp +++ b/src/mediaplaylist.cpp @@ -695,6 +695,7 @@ case ElisaUtils::Lyricist: case ElisaUtils::Composer: case ElisaUtils::Unknown: + case ElisaUtils::NetworkService: break; } @@ -742,6 +743,7 @@ case ElisaUtils::Lyricist: case ElisaUtils::Composer: case ElisaUtils::Unknown: + case ElisaUtils::NetworkService: break; } diff --git a/src/modeldataloader.h b/src/modeldataloader.h --- a/src/modeldataloader.h +++ b/src/modeldataloader.h @@ -29,6 +29,8 @@ #include class ModelDataLoaderPrivate; +class UpnpSsdpEngine; +class UpnpDiscoverAllMusic; class ELISALIB_EXPORT ModelDataLoader : public QObject { @@ -42,8 +44,10 @@ using ListGenreDataType = DatabaseInterface::ListGenreDataType; using ListTrackDataType = DatabaseInterface::ListTrackDataType; using ListRadioDataType = DatabaseInterface::ListRadioDataType; + using ListNetworkServiceDataType = DatabaseInterface::ListNetworkServiceDataType; using TrackDataType = DatabaseInterface::TrackDataType; using AlbumDataType = DatabaseInterface::AlbumDataType; + using NetworkServiceDataType = DatabaseInterface::NetworkServiceDataType; using FilterType = ElisaUtils::FilterType; @@ -53,6 +57,10 @@ void setDatabase(DatabaseInterface *database); + void setSsdpDiscoveryEngine(UpnpSsdpEngine *ssdpDiscoveryEngine); + + void setUpnpDiscoverAllMusic(UpnpDiscoverAllMusic *discoveryEngine); + Q_SIGNALS: void allAlbumsData(const ModelDataLoader::ListAlbumDataType &allData); @@ -97,6 +105,10 @@ void radioRemoved(qulonglong radioId); + void networkServicesAdded(const ModelDataLoader::ListNetworkServiceDataType &newData); + + void networkServiceRemoved(const ModelDataLoader::NetworkServiceDataType &removedService); + public Q_SLOTS: void loadData(ElisaUtils::PlayListEntryType dataType); @@ -126,6 +138,12 @@ void deleteRadioData(qulonglong radioId); + void newUpnpContentDirectoryService(const QString &name); + + void removedUpnpContentDirectoryService(const QString &name); + + void networkChanged(); + private: void databaseTracksAdded(const ListTrackDataType &newData); diff --git a/src/modeldataloader.cpp b/src/modeldataloader.cpp --- a/src/modeldataloader.cpp +++ b/src/modeldataloader.cpp @@ -17,8 +17,17 @@ #include "modeldataloader.h" +#include "config-upnp-qt.h" + #include "filescanner.h" +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + +#include "upnp/upnpdiscoverallmusic.h" +#include + +#endif + #include class ModelDataLoaderPrivate @@ -45,6 +54,11 @@ qulonglong mDatabaseId = 0; +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + UpnpSsdpEngine *mSsdpDiscoveryEngine = nullptr; + + UpnpDiscoverAllMusic *mDiscoveryEngine = nullptr; +#endif }; ModelDataLoader::ModelDataLoader(QObject *parent) : QObject(parent), d(std::make_unique()) @@ -87,6 +101,31 @@ this, &ModelDataLoader::databaseRadioRemoved); } +void ModelDataLoader::setSsdpDiscoveryEngine(UpnpSsdpEngine *ssdpDiscoveryEngine) +{ + if (d->mSsdpDiscoveryEngine != ssdpDiscoveryEngine) { + d->mSsdpDiscoveryEngine = ssdpDiscoveryEngine; + } +} + +void ModelDataLoader::setUpnpDiscoverAllMusic(UpnpDiscoverAllMusic *discoveryEngine) +{ + if (d->mDiscoveryEngine != discoveryEngine) { + if (d->mDiscoveryEngine) { + disconnect(d->mDiscoveryEngine); + } + + d->mDiscoveryEngine = discoveryEngine; + + connect(d->mDiscoveryEngine, &UpnpDiscoverAllMusic::newUpnpContentDirectoryService, + this, &ModelDataLoader::newUpnpContentDirectoryService); + connect(d->mDiscoveryEngine, &UpnpDiscoverAllMusic::removedUpnpContentDirectoryService, + this, &ModelDataLoader::removedUpnpContentDirectoryService); + connect(d->mDiscoveryEngine, &UpnpDiscoverAllMusic::networkChanged, + this, &ModelDataLoader::networkChanged); + } +} + void ModelDataLoader::loadData(ElisaUtils::PlayListEntryType dataType) { if (!d->mDatabase) { @@ -113,6 +152,14 @@ case ElisaUtils::Track: Q_EMIT allTracksData(d->mDatabase->allTracksData()); break; + case ElisaUtils::NetworkService: +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + if (d->mSsdpDiscoveryEngine) { + d->mSsdpDiscoveryEngine->searchAllUpnpDevice(); + } +#endif + Q_EMIT networkServicesAdded({}); + break; case ElisaUtils::FileName: case ElisaUtils::Unknown: break; @@ -149,6 +196,7 @@ case ElisaUtils::FileName: case ElisaUtils::Unknown: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: break; } } @@ -175,6 +223,7 @@ case ElisaUtils::FileName: case ElisaUtils::Unknown: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: break; } } @@ -201,6 +250,7 @@ case ElisaUtils::FileName: case ElisaUtils::Unknown: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: break; } } @@ -228,6 +278,7 @@ case ElisaUtils::FileName: case ElisaUtils::Unknown: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: break; } } @@ -256,6 +307,7 @@ case ElisaUtils::Lyricist: case ElisaUtils::FileName: case ElisaUtils::Unknown: + case ElisaUtils::NetworkService: break; } } @@ -284,6 +336,7 @@ case ElisaUtils::Lyricist: case ElisaUtils::Unknown: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: break; } } @@ -309,6 +362,7 @@ case ElisaUtils::FileName: case ElisaUtils::Unknown: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: break; } } @@ -334,10 +388,39 @@ case ElisaUtils::FileName: case ElisaUtils::Unknown: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: break; } } +void ModelDataLoader::newUpnpContentDirectoryService(const QString &name) +{ + NetworkServiceDataType newService; + + newService[NetworkServiceDataType::key_type::TitleRole] = name; + + Q_EMIT networkServicesAdded({newService}); +} + +void ModelDataLoader::removedUpnpContentDirectoryService(const QString &name) +{ + qDebug() << "ModelDataLoader::removedUpnpContentDirectoryService" << name; + NetworkServiceDataType removedService; + + removedService[NetworkServiceDataType::key_type::TitleRole] = name; + + Q_EMIT networkServiceRemoved(removedService); +} + +void ModelDataLoader::networkChanged() +{ +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + if (d->mSsdpDiscoveryEngine) { + d->mSsdpDiscoveryEngine->searchAllUpnpDevice(); + } +#endif +} + void ModelDataLoader::databaseTracksAdded(const ListTrackDataType &newData) { switch(d->mFilterType) { diff --git a/src/models/datamodel.h b/src/models/datamodel.h --- a/src/models/datamodel.h +++ b/src/models/datamodel.h @@ -68,6 +68,10 @@ using GenreDataType = DatabaseInterface::GenreDataType; + using ListNetworkServiceDataType = DatabaseInterface::ListNetworkServiceDataType; + + using NetworkServiceDataType = DatabaseInterface::NetworkServiceDataType; + using FilterType = ElisaUtils::FilterType; explicit DataModel(QObject *parent = nullptr); @@ -139,6 +143,10 @@ void albumModified(const DataModel::AlbumDataType &modifiedAlbum); + void networkServicesAdded(ListNetworkServiceDataType newData); + + void networkServiceRemoved(const DataModel::NetworkServiceDataType &removedService); + void initialize(MusicListenersManager *manager, DatabaseInterface *database, ElisaUtils::PlayListEntryType modelType, ElisaUtils::FilterType filter, const QString &genre, const QString &artist, qulonglong databaseId); diff --git a/src/models/datamodel.cpp b/src/models/datamodel.cpp --- a/src/models/datamodel.cpp +++ b/src/models/datamodel.cpp @@ -42,6 +42,8 @@ DataModel::ListGenreDataType mAllGenreData; + DataModel::ListNetworkServiceDataType mAllNetworkServicesData; + ModelDataLoader mDataLoader; ElisaUtils::PlayListEntryType mModelType = ElisaUtils::Unknown; @@ -125,7 +127,9 @@ return result; } - const auto dataCount = d->mModelType == ElisaUtils::Radio ? d->mAllRadiosData.size() : d->mAllTrackData.size() + d->mAllAlbumData.size() + d->mAllArtistData.size() + d->mAllGenreData.size(); + const auto dataCount = d->mAllTrackData.size() + d->mAllAlbumData.size() + + d->mAllArtistData.size() + d->mAllGenreData.size() + d->mAllRadiosData.size() + + d->mAllNetworkServicesData.size(); Q_ASSERT(index.isValid()); Q_ASSERT(index.column() == 0); @@ -154,6 +158,9 @@ case ElisaUtils::Radio: result = d->mAllRadiosData[index.row()][GenreDataType::key_type::TitleRole]; break; + case ElisaUtils::NetworkService: + result = d->mAllNetworkServicesData[index.row()][NetworkServiceDataType::key_type::TitleRole]; + break; case ElisaUtils::Lyricist: case ElisaUtils::Composer: case ElisaUtils::FileName: @@ -182,6 +189,7 @@ case ElisaUtils::Composer: case ElisaUtils::FileName: case ElisaUtils::Radio: + case ElisaUtils::NetworkService: case ElisaUtils::Unknown: break; } @@ -205,6 +213,7 @@ case ElisaUtils::Lyricist: case ElisaUtils::Composer: case ElisaUtils::FileName: + case ElisaUtils::NetworkService: case ElisaUtils::Unknown: break; } @@ -232,6 +241,7 @@ case ElisaUtils::Composer: case ElisaUtils::FileName: case ElisaUtils::Unknown: + case ElisaUtils::NetworkService: break; } } @@ -319,6 +329,11 @@ return; } + if (manager && manager->ssdpEngine() && manager->upnpServiceDiscovery()) { + d->mDataLoader.setSsdpDiscoveryEngine(manager->ssdpEngine()); + d->mDataLoader.setUpnpDiscoverAllMusic(manager->upnpServiceDiscovery()); + } + switch(d->mFilterType) { case ElisaUtils::NoFilter: @@ -442,6 +457,10 @@ this, &DataModel::radioModified); connect(&d->mDataLoader, &ModelDataLoader::radioRemoved, this, &DataModel::radioRemoved); + connect(&d->mDataLoader, &ModelDataLoader::networkServicesAdded, + this, &DataModel::networkServicesAdded); + connect(&d->mDataLoader, &ModelDataLoader::networkServiceRemoved, + this, &DataModel::networkServiceRemoved); } void DataModel::tracksAdded(ListTrackDataType newData) @@ -831,6 +850,53 @@ Q_EMIT dataChanged(index(albumIndex, 0), index(albumIndex, 0)); } +void DataModel::networkServicesAdded(DataModel::ListNetworkServiceDataType newData) +{ + if (newData.isEmpty() && d->mModelType == ElisaUtils::NetworkService) { + setBusy(false); + } + + if (newData.isEmpty() || d->mModelType != ElisaUtils::NetworkService) { + return; + } + + if (d->mAllNetworkServicesData.isEmpty()) { + beginInsertRows({}, d->mAllNetworkServicesData.size(), newData.size() - 1); + d->mAllNetworkServicesData.swap(newData); + endInsertRows(); + + setBusy(false); + } else { + beginInsertRows({}, d->mAllNetworkServicesData.size(), d->mAllNetworkServicesData.size() + newData.size() - 1); + d->mAllNetworkServicesData.append(newData); + endInsertRows(); + } +} + +void DataModel::networkServiceRemoved(const DataModel::NetworkServiceDataType &removedService) +{ + if (d->mModelType != ElisaUtils::NetworkService) { + return; + } + + auto removedDataIterator = d->mAllNetworkServicesData.end(); + + removedDataIterator = std::find_if(d->mAllNetworkServicesData.begin(), d->mAllNetworkServicesData.end(), + [removedService](auto networkService) { return networkService.title() == removedService.title(); }); + + if (removedDataIterator == d->mAllNetworkServicesData.end()) { + return; + } + + int dataIndex = removedDataIterator - d->mAllNetworkServicesData.begin(); + + beginRemoveRows({}, dataIndex, dataIndex); + + d->mAllNetworkServicesData.erase(removedDataIterator); + + endRemoveRows(); +} + void DataModel::cleanedDatabase() { beginResetModel(); diff --git a/src/upnp/upnpcontentdirectorymodel.h b/src/models/upnpalbummodel.h copy from src/upnp/upnpcontentdirectorymodel.h copy to src/models/upnpalbummodel.h --- a/src/upnp/upnpcontentdirectorymodel.h +++ b/src/models/upnpalbummodel.h @@ -1,39 +1,50 @@ /* - * Copyright 2015 Matthieu Gallien + * Copyright 2015-2016 Matthieu Gallien * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public + * 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 program is distributed in the hope that it will be useful, + * 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 - * Lesser General Public License for more details. + * Library General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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 UPNPCONTENTDIRECTORYMODEL_H -#define UPNPCONTENTDIRECTORYMODEL_H +#ifndef UPNPALBUMMODEL_H +#define UPNPALBUMMODEL_H -#include "upnpQt_export.h" +#include -#include +#include "musicaudiotrack.h" -#include - -class UpnpContentDirectoryModelPrivate; +class UpnpAlbumModelPrivate; class UpnpSsdpEngine; class UpnpControlAbstractDevice; class UpnpControlContentDirectory; class UpnpDiscoveryResult; +class QDomNode; +class DidlParser; -class UPNPQT_EXPORT UpnpContentDirectoryModel : public QAbstractItemModel +class UpnpAlbumModel : public QAbstractItemModel { Q_OBJECT + Q_PROPERTY(UpnpControlContentDirectory* contentDirectory + READ contentDirectory + WRITE setContentDirectory + NOTIFY contentDirectoryChanged) + + Q_PROPERTY(DidlParser* didlParser + READ didlParser + NOTIFY didlParserChanged) + Q_PROPERTY(QString browseFlag READ browseFlag WRITE setBrowseFlag @@ -49,10 +60,10 @@ WRITE setSortCriteria NOTIFY sortCriteriaChanged) - Q_PROPERTY(UpnpControlContentDirectory* contentDirectory - READ contentDirectory - WRITE setContentDirectory - NOTIFY contentDirectoryChanged) + Q_PROPERTY(QString serverName + READ serverName + WRITE setServerName + NOTIFY serverNameChanged) Q_PROPERTY(bool useLocalIcons READ useLocalIcons @@ -64,18 +75,18 @@ enum ItemClass { Container = 0, Album = 1, - AudioTrack = 2, + Artist = 2, + AudioTrack = 3, }; - Q_ENUM(ItemClass) - enum ColumnsRoles { TitleRole = Qt::UserRole + 1, DurationRole = TitleRole + 1, CreatorRole = DurationRole + 1, ArtistRole = CreatorRole + 1, AlbumRole = ArtistRole + 1, - RatingRole = AlbumRole + 1, + TrackNumberRole = AlbumRole + 1, + RatingRole = TrackNumberRole + 1, ImageRole = RatingRole + 1, ResourceRole = ImageRole + 1, ItemClassRole = ResourceRole + 1, @@ -85,16 +96,18 @@ IsPlayingRole = ParentIdRole + 1, }; - Q_ENUM(ColumnsRoles) + explicit UpnpAlbumModel(QObject *parent = nullptr); - explicit UpnpContentDirectoryModel(QObject *parent = nullptr); - - ~UpnpContentDirectoryModel() override; + virtual ~UpnpAlbumModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QHash roleNames() const override; + bool canFetchMore(const QModelIndex &parent) const override; + + void fetchMore(const QModelIndex &parent) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -105,63 +118,69 @@ int columnCount(const QModelIndex &parent = QModelIndex()) const override; - bool canFetchMore(const QModelIndex &parent) const override; + UpnpControlContentDirectory* contentDirectory() const; - void fetchMore(const QModelIndex &parent) override; + DidlParser* didlParser() const; const QString& browseFlag() const; - void setBrowseFlag(const QString &flag); - const QString& filter() const; - void setFilter(const QString &flag); - const QString& sortCriteria() const; - void setSortCriteria(const QString &criteria); - - UpnpControlContentDirectory* contentDirectory() const; - - void setContentDirectory(UpnpControlContentDirectory *directory); + QString serverName() const; bool useLocalIcons() const; - void setUseLocalIcons(bool value); - - Q_INVOKABLE QString objectIdByIndex(const QModelIndex &index) const; +Q_SIGNALS: - Q_INVOKABLE QVariant getUrl(const QModelIndex &index) const; + void contentDirectoryChanged(); - Q_INVOKABLE QModelIndex indexFromId(const QString &id) const; + void musicDatabaseChanged(); -Q_SIGNALS: + void didlParserChanged(); void browseFlagChanged(); void filterChanged(); void sortCriteriaChanged(); - void contentDirectoryChanged(); + void newAudioTrack(const MusicAudioTrack &audioTrack); + + void serverNameChanged(); void useLocalIconsChanged(); public Q_SLOTS: - void browseFinished(const QString &result, int numberReturned, int totalMatches, int systemUpdateID, bool success); + void setContentDirectory(UpnpControlContentDirectory *directory); + + void setBrowseFlag(const QString &flag); + + void setFilter(const QString &flag); + + void setSortCriteria(const QString &criteria); + + void setServerName(QString serverName); + + void setUseLocalIcons(bool useLocalIcons); private Q_SLOTS: + void contentChanged(const QString &parentId); + private: - QModelIndex indexFromInternalId(quintptr internalId) const; + QVariant internalDataAlbum(const QModelIndex &index, int role, DidlParser *currentParser) const; - std::unique_ptr d; + QVariant internalDataTrack(const QModelIndex &index, int role, DidlParser *currentParser) const; + UpnpAlbumModelPrivate *d; }; -Q_DECLARE_METATYPE(UpnpContentDirectoryModel::ItemClass) -#endif // UPNPCONTENTDIRECTORYMODEL_H +Q_DECLARE_METATYPE(UpnpAlbumModel::ItemClass) + +#endif // UPNPALBUMMODEL_H diff --git a/src/models/upnpalbummodel.cpp b/src/models/upnpalbummodel.cpp new file mode 100644 --- /dev/null +++ b/src/models/upnpalbummodel.cpp @@ -0,0 +1,459 @@ +/* + * Copyright 2015-2016 Matthieu Gallien + * + * 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 "upnp/didlparser.h" +#include "upnp/upnpcontrolcontentdirectory.h" + +#include + +#include +#include +#include +#include + +class UpnpAlbumModelPrivate +{ +public: + + UpnpControlContentDirectory *mContentDirectory = nullptr; + + bool mUseLocalIcons = false; + + DidlParser mDidlParser; + + QString mBrowseFlag; + + QString mFilter; + + QString mSortCriteria; + + QVector mChilds; + + QHash> mAlbumParsers; + + QString mServerName; +}; + +UpnpAlbumModel::UpnpAlbumModel(QObject *parent) : QAbstractItemModel(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; +} + +int UpnpAlbumModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return d->mDidlParser.newMusicTrackIds().size(); + } + + if (!d->mAlbumParsers.contains(d->mChilds[parent.row()])) { + return 0; + } + + auto childParser = d->mAlbumParsers[d->mChilds[parent.row()]]; + + if (!childParser) { + return 0; + } + + return childParser->newMusicTrackIds().size(); +} + +QHash UpnpAlbumModel::roleNames() const +{ + QHash roles; + + roles[static_cast(ColumnsRoles::TitleRole)] = "title"; + roles[static_cast(ColumnsRoles::DurationRole)] = "duration"; + roles[static_cast(ColumnsRoles::ArtistRole)] = "artist"; + roles[static_cast(ColumnsRoles::AlbumRole)] = "album"; + roles[static_cast(ColumnsRoles::TrackNumberRole)] = "trackNumber"; + roles[static_cast(ColumnsRoles::RatingRole)] = "rating"; + roles[static_cast(ColumnsRoles::ImageRole)] = "image"; + roles[static_cast(ColumnsRoles::ItemClassRole)] = "itemClass"; + roles[static_cast(ColumnsRoles::CountRole)] = "count"; + roles[static_cast(ColumnsRoles::IsPlayingRole)] = "isPlaying"; + + return roles; +} + +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(); + } +} + +Qt::ItemFlags UpnpAlbumModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) { + return Qt::NoItemFlags; + } + + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +QVariant UpnpAlbumModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return {}; + } + + if (index.column() != 0) { + return {}; + } + + if (index.row() < 0) { + return {}; + } + + if (index.row() >= d->mDidlParser.newMusicTrackIds().size()) { + return {}; + } + + if (index.internalId() != 0) { + if (!d->mAlbumParsers.contains(d->mChilds[index.internalId() - 1])) { + return 0; + } + + auto childParser = d->mAlbumParsers[d->mChilds[index.internalId() - 1]]; + + if (!childParser) { + return 0; + } + + return internalDataTrack(index, role, childParser); + } + + return internalDataAlbum(index, role, &d->mDidlParser); +} + +QVariant UpnpAlbumModel::internalDataAlbum(const QModelIndex &index, int role, DidlParser *currentParser) const +{ + ColumnsRoles convertedRole = static_cast(role); + + //const auto &albumId = currentParser->newMusicTrackIds()[index.row()]; + const auto &albumId = index.row(); + + switch(convertedRole) + { + case ColumnsRoles::TitleRole: + return currentParser->newMusicTracks()[albumId].title(); + case ColumnsRoles::DurationRole: + return {}; + case ColumnsRoles::CreatorRole: + return {}; + case ColumnsRoles::ArtistRole: + return currentParser->newMusicTracks()[albumId].artist(); + case ColumnsRoles::AlbumRole: + return {}; + case ColumnsRoles::RatingRole: + return {}; + case ColumnsRoles::ImageRole: + if (currentParser->newMusicTracks()[albumId].albumCover().isValid()) { + return currentParser->newMusicTracks()[albumId].albumCover(); + } else { + if (d->mUseLocalIcons) { + return QUrl(QStringLiteral("qrc:/media-optical-audio.svg")); + } else { + return QUrl(QStringLiteral("image://icon/media-optical-audio")); + } + } + case ColumnsRoles::ResourceRole: + return currentParser->newMusicTracks()[albumId].resourceURI(); + case ColumnsRoles::ItemClassRole: + return {}; + case ColumnsRoles::CountRole: + //return currentParser->newMusicTracks()[albumId].mTracksCount; + return 1; + case ColumnsRoles::IdRole: + return {}; + //return currentParser->newMusicTracks()[albumId].mId; + case ColumnsRoles::ParentIdRole: + return {}; + //return currentParser->newMusicTracks()[albumId].mParentId; + case ColumnsRoles::IsPlayingRole: + return {}; + case ColumnsRoles::TrackNumberRole: + return {}; + } + + return {}; +} + +QVariant UpnpAlbumModel::internalDataTrack(const QModelIndex &index, int role, DidlParser *currentParser) const +{ + ColumnsRoles convertedRole = static_cast(role); + + if (index.row() < 0 || index.row() >= currentParser->newMusicTrackIds().size()) { + return {}; + } + + //const auto &musicTrackId = currentParser->newMusicTrackIds()[index.row()]; + const auto &musicTrackId = index.row(); + + switch(convertedRole) + { + case ColumnsRoles::TitleRole: + return currentParser->newMusicTracks()[musicTrackId].title(); + case ColumnsRoles::DurationRole: + if (currentParser->newMusicTracks()[musicTrackId].duration().hour() == 0) { + return currentParser->newMusicTracks()[musicTrackId].duration().toString(QStringLiteral("mm:ss")); + } else { + return currentParser->newMusicTracks()[musicTrackId].duration().toString(); + } + case ColumnsRoles::CreatorRole: + return currentParser->newMusicTracks()[musicTrackId].artist(); + case ColumnsRoles::ArtistRole: + return currentParser->newMusicTracks()[musicTrackId].artist(); + case ColumnsRoles::AlbumRole: + return currentParser->newMusicTracks()[musicTrackId].albumName(); + case ColumnsRoles::TrackNumberRole: + return currentParser->newMusicTracks()[musicTrackId].trackNumber(); + case ColumnsRoles::RatingRole: + return 0; + case ColumnsRoles::ImageRole: + return data(index.parent(), role); + case ColumnsRoles::ResourceRole: + return currentParser->newMusicTracks()[musicTrackId].resourceURI(); + case ColumnsRoles::ItemClassRole: + return {}; + case ColumnsRoles::CountRole: + return {}; + case ColumnsRoles::IdRole: + return currentParser->newMusicTracks()[musicTrackId].id(); + case ColumnsRoles::ParentIdRole: + return currentParser->newMusicTracks()[musicTrackId].parentId(); + case ColumnsRoles::IsPlayingRole: + return false; + } + + return {}; +} + +QModelIndex UpnpAlbumModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return createIndex(row, column, quintptr(0)); + } + + return createIndex(row, column, quintptr(parent.row()) + 1); +} + +QModelIndex UpnpAlbumModel::parent(const QModelIndex &child) const +{ + // child is valid + if (!child.isValid()) { + return {}; + } + + if (child.internalId() == 0) { + return {}; + } + + return createIndex(int(child.internalId() - 1), 0, quintptr(0)); +} + +int UpnpAlbumModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return 1; +} + +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; + emit useLocalIconsChanged(); +} + +void UpnpAlbumModel::contentChanged(const QString &parentId) +{ + if (parentId == QStringLiteral("0")) { + beginResetModel(); + + d->mChilds = d->mDidlParser.newMusicTrackIds(); + + endResetModel(); + return; + } + + auto indexChild = d->mChilds.indexOf(parentId); + + if (indexChild == -1) { + return; + } + + if (!d->mAlbumParsers.contains(parentId)) { + return; + } + + auto childParser = d->mAlbumParsers[parentId]; + + if (!childParser) { + return; + } + + beginInsertRows(index(indexChild, 0), 0, childParser->newMusicTrackIds().size() - 1); + + endInsertRows(); +} + + +#include "moc_upnpalbummodel.cpp" diff --git a/src/models/viewsmodel.cpp b/src/models/viewsmodel.cpp --- a/src/models/viewsmodel.cpp +++ b/src/models/viewsmodel.cpp @@ -40,7 +40,7 @@ ViewManager::FrequentlyPlayedTracks, ViewManager::AllAlbums, ViewManager::AllArtists, ViewManager::AllTracks, ViewManager::AllGenres, ViewManager::FilesBrowser, - ViewManager::RadiosBrowser}; + ViewManager::RadiosBrowser, ViewManager::UpnpServers,}; mNames = {{ViewManager::Context, {i18nc("Title of the view of the playlist", "Now Playing")}}, {ViewManager::RecentlyPlayedTracks, {i18nc("Title of the view of recently played tracks", "Recently Played")}}, @@ -50,7 +50,8 @@ {ViewManager::AllTracks, {i18nc("Title of the view of all tracks", "Tracks")}}, {ViewManager::AllGenres, {i18nc("Title of the view of all genres", "Genres")}}, {ViewManager::FilesBrowser, {i18nc("Title of the file browser view", "Files")}}, - {ViewManager::RadiosBrowser, {i18nc("Title of the file radios browser view", "Radios")}}}; + {ViewManager::RadiosBrowser, {i18nc("Title of the file radios browser view", "Radios")}}, + {ViewManager::UpnpServers, {i18nc("Title of the view of all UPnP/DLNA servers", "Local Network Music")}}}; mIcons = {{ViewManager::Context, QUrl{QStringLiteral("image://icon/view-media-lyrics")}}, {ViewManager::RecentlyPlayedTracks, QUrl{QStringLiteral("image://icon/media-playlist-play")}}, @@ -60,7 +61,8 @@ {ViewManager::AllTracks, QUrl{QStringLiteral("image://icon/view-media-track")}}, {ViewManager::AllGenres, QUrl{QStringLiteral("image://icon/view-media-genre")}}, {ViewManager::FilesBrowser, QUrl{QStringLiteral("image://icon/document-open-folder")}}, - {ViewManager::RadiosBrowser, QUrl{QStringLiteral("image://icon/radio")}}}; + {ViewManager::RadiosBrowser, QUrl{QStringLiteral("image://icon/radio")}}, + {ViewManager::UpnpServers, QUrl{QStringLiteral("image://icon/network-server")}}}; } }; @@ -172,6 +174,8 @@ return 7; case ViewManager::RadiosBrowser: return 8; + case ViewManager::UpnpServers: + return 9; case ViewManager::OneAlbum: case ViewManager::OneArtist: case ViewManager::OneAlbumFromArtist: diff --git a/src/musiclistenersmanager.h b/src/musiclistenersmanager.h --- a/src/musiclistenersmanager.h +++ b/src/musiclistenersmanager.h @@ -31,6 +31,8 @@ class MediaPlayList; class ElisaApplication; class ModelDataLoader; +class UpnpSsdpEngine; +class UpnpDiscoverAllMusic; class ELISALIB_EXPORT MusicListenersManager : public QObject { @@ -100,6 +102,10 @@ bool androidIndexerAvailable() const; + UpnpSsdpEngine* ssdpEngine() const; + + UpnpDiscoverAllMusic* upnpServiceDiscovery() const; + Q_SIGNALS: void viewDatabaseChanged(); diff --git a/src/musiclistenersmanager.cpp b/src/musiclistenersmanager.cpp --- a/src/musiclistenersmanager.cpp +++ b/src/musiclistenersmanager.cpp @@ -21,10 +21,6 @@ #include "indexersManager.h" -#if defined UPNPQT_FOUND && UPNPQT_FOUND -#include "upnp/upnplistener.h" -#endif - #if defined KF5Baloo_FOUND && KF5Baloo_FOUND #include "baloo/baloolistener.h" #include "baloo/baloodetector.h" @@ -34,6 +30,14 @@ #include "android/androidmusiclistener.h" #endif +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + +#include "upnp/upnpdiscoverallmusic.h" + +#include + +#endif + #include "databaseinterface.h" #include "mediaplaylist.h" #include "file/filelistener.h" @@ -68,10 +72,6 @@ QThread mListenerThread; -#if defined UPNPQT_FOUND && UPNPQT_FOUND - UpnpListener mUpnpListener; -#endif - #if defined KF5Baloo_FOUND && KF5Baloo_FOUND BalooDetector mBalooDetector; @@ -84,6 +84,14 @@ std::unique_ptr mAndroidMusicListener; #endif +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + UpnpSsdpEngine mSsdpEngine; + + UpnpDiscoverAllMusic mUpnpServiceDiscovery; + + QThread mUpnpThread; +#endif + DatabaseInterface mDatabaseInterface; std::unique_ptr mTracksListener; @@ -116,6 +124,22 @@ d->mDatabaseInterface.moveToThread(&d->mDatabaseThread); +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + d->mUpnpThread.start(); + + d->mSsdpEngine.moveToThread(&d->mUpnpThread); + d->mUpnpServiceDiscovery.moveToThread(&d->mUpnpThread); + + connect(&d->mSsdpEngine, &UpnpSsdpEngine::newService, + &d->mUpnpServiceDiscovery, &UpnpDiscoverAllMusic::newDevice); + connect(&d->mSsdpEngine, &UpnpSsdpEngine::removedService, + &d->mUpnpServiceDiscovery, &UpnpDiscoverAllMusic::removedDevice); + connect(&d->mSsdpEngine, &UpnpSsdpEngine::networkChanged, + &d->mUpnpServiceDiscovery, &UpnpDiscoverAllMusic::networkChanged); + + QMetaObject::invokeMethod(&d->mSsdpEngine, "initialize", Qt::QueuedConnection); +#endif + connect(&d->mDatabaseInterface, &DatabaseInterface::requestsInitDone, this, &MusicListenersManager::databaseReady); connect(this, &MusicListenersManager::clearDatabase, @@ -227,6 +251,24 @@ return d->mAndroidIndexerAvailable; } +UpnpSsdpEngine *MusicListenersManager::ssdpEngine() const +{ +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + return &d->mSsdpEngine; +#else + return nullptr; +#endif +} + +UpnpDiscoverAllMusic *MusicListenersManager::upnpServiceDiscovery() const +{ +#if defined UpnpLibQt_FOUND && UpnpLibQt_FOUND + return &d->mUpnpServiceDiscovery; +#else + return nullptr; +#endif +} + void MusicListenersManager::databaseReady() { configChanged(); @@ -315,13 +357,6 @@ } } -#if defined UPNPQT_FOUND && UPNPQT_FOUND - d->mUpnpListener.setDatabaseInterface(&d->mDatabaseInterface); - d->mUpnpListener.moveToThread(&d->mDatabaseThread); - connect(this, &MusicListenersManager::applicationIsTerminating, - &d->mUpnpListener, &UpnpListener::applicationAboutToQuit, Qt::DirectConnection); -#endif - #if defined Qt5AndroidExtras_FOUND && Qt5AndroidExtras_FOUND if (!d->mAndroidMusicListener) { d->mAndroidMusicListener = std::make_unique(); diff --git a/src/trackslistener.cpp b/src/trackslistener.cpp --- a/src/trackslistener.cpp +++ b/src/trackslistener.cpp @@ -245,6 +245,7 @@ case ElisaUtils::Composer: case ElisaUtils::Genre: case ElisaUtils::Unknown: + case ElisaUtils::NetworkService: break; } } diff --git a/src/upnp/didlparser.h b/src/upnp/didlparser.h --- a/src/upnp/didlparser.h +++ b/src/upnp/didlparser.h @@ -96,8 +96,6 @@ QString parentId() const; - const QVector &newAlbumIds() const; - const QVector &newMusicTrackIds() const; const QList &newMusicTracks() const; diff --git a/src/upnp/didlparser.cpp b/src/upnp/didlparser.cpp --- a/src/upnp/didlparser.cpp +++ b/src/upnp/didlparser.cpp @@ -48,10 +48,6 @@ bool mIsDataValid = false; - QVector mNewAlbumIds; - - QHash mNewAlbums; - QVector mNewMusicTrackIds; QHash mNewMusicTracks; @@ -156,8 +152,6 @@ auto upnpAnswer = d->mContentDirectory->browse(d->mParentId, d->mBrowseFlag, d->mFilter, startIndex, maximumNmberOfResults, d->mSortCriteria); if (startIndex == 0) { - d->mNewAlbumIds.clear(); - d->mNewAlbums.clear(); d->mNewMusicTracks.clear(); d->mNewMusicTrackIds.clear(); d->mCovers.clear(); @@ -173,8 +167,6 @@ } if (startIndex == 0) { - d->mNewAlbumIds.clear(); - d->mNewAlbums.clear(); d->mNewMusicTracks.clear(); d->mNewMusicTrackIds.clear(); d->mCovers.clear(); @@ -190,16 +182,6 @@ return d->mParentId; } -const QVector &DidlParser::newAlbumIds() const -{ - return d->mNewAlbumIds; -} - -const QHash &DidlParser::newAlbums() const -{ - return d->mNewAlbums; -} - const QVector &DidlParser::newMusicTrackIds() const { return d->mNewMusicTrackIds; @@ -223,7 +205,7 @@ if (!success) { d->mIsDataValid = false; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); return; } @@ -235,16 +217,16 @@ if (!intConvert) { d->mIsDataValid = false; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); return; } auto totalMatches = resultData[QStringLiteral("TotalMatches")].toInt(&intConvert); if (!intConvert) { d->mIsDataValid = false; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); return; } @@ -262,7 +244,7 @@ for (int containerIndex = 0; containerIndex < containerList.length(); ++containerIndex) { const QDomNode &containerNode(containerList.at(containerIndex)); if (!containerNode.isNull()) { - decodeContainerNode(containerNode, d->mNewAlbums, d->mNewAlbumIds); + decodeContainerNode(containerNode, d->mNewMusicTracks, d->mNewMusicTrackIds); } } @@ -276,7 +258,7 @@ groupNewTracksByAlbums(); d->mIsDataValid = true; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); } void DidlParser::groupNewTracksByAlbums() @@ -295,7 +277,7 @@ if (!success) { d->mIsDataValid = false; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); return; } @@ -307,16 +289,16 @@ if (!intConvert) { d->mIsDataValid = false; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); return; } auto totalMatches = resultData[QStringLiteral("TotalMatches")].toInt(&intConvert); if (!intConvert) { d->mIsDataValid = false; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); return; } @@ -334,7 +316,7 @@ for (int containerIndex = 0; containerIndex < containerList.length(); ++containerIndex) { const QDomNode &containerNode(containerList.at(containerIndex)); if (!containerNode.isNull()) { - decodeContainerNode(containerNode, d->mNewAlbums, d->mNewAlbumIds); + decodeContainerNode(containerNode, d->mNewMusicTracks, d->mNewMusicTrackIds); } } @@ -348,10 +330,10 @@ groupNewTracksByAlbums(); d->mIsDataValid = true; - Q_EMIT isDataValidChanged(d->mContentDirectory->description()->deviceDescription()->UDN().mid(5), d->mParentId); + Q_EMIT isDataValidChanged(d->mContentDirectory->description().deviceDescription().UDN().mid(5), d->mParentId); } -void DidlParser::decodeContainerNode(const QDomNode &containerNode, QHash &newData, +void DidlParser::decodeContainerNode(const QDomNode &containerNode, QHash &newData, QVector &newDataIds) { auto parentID = containerNode.toElement().attribute(QStringLiteral("parentID")); @@ -364,7 +346,7 @@ chilData.setId(id); const QString &childCount = containerNode.toElement().attribute(QStringLiteral("childCount")); - chilData.setTracksCount(childCount.toInt()); + //chilData.setTracksCount(childCount.toInt()); const QDomNode &titleNode = containerNode.firstChildElement(QStringLiteral("dc:title")); if (!titleNode.isNull()) { @@ -394,7 +376,7 @@ const QDomNode &albumArtNode = containerNode.firstChildElement(QStringLiteral("upnp:albumArtURI")); if (!albumArtNode.isNull()) { - chilData.setAlbumArtURI(QUrl::fromUserInput(albumArtNode.toElement().text())); + //chilData.setAlbumArtURI(QUrl::fromUserInput(albumArtNode.toElement().text())); } } diff --git a/src/upnp/upnpcontentdirectorymodel.h b/src/upnp/upnpcontentdirectorymodel.h --- a/src/upnp/upnpcontentdirectorymodel.h +++ b/src/upnp/upnpcontentdirectorymodel.h @@ -18,8 +18,6 @@ #ifndef UPNPCONTENTDIRECTORYMODEL_H #define UPNPCONTENTDIRECTORYMODEL_H -#include "upnpQt_export.h" - #include #include @@ -30,7 +28,7 @@ class UpnpControlContentDirectory; class UpnpDiscoveryResult; -class UPNPQT_EXPORT UpnpContentDirectoryModel : public QAbstractItemModel +class UpnpContentDirectoryModel : public QAbstractItemModel { Q_OBJECT diff --git a/src/upnp/upnpcontentdirectorymodel.cpp b/src/upnp/upnpcontentdirectorymodel.cpp --- a/src/upnp/upnpcontentdirectorymodel.cpp +++ b/src/upnp/upnpcontentdirectorymodel.cpp @@ -18,6 +18,9 @@ */ #include "upnpcontentdirectorymodel.h" + +#include "upnpLogging.h" + #include "upnpcontrolcontentdirectory.h" #include @@ -27,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -432,10 +435,10 @@ Q_UNUSED(totalMatches) Q_UNUSED(systemUpdateID) - qDebug() << "UpnpContentDirectoryModel::browseFinished" << numberReturned; + qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::browseFinished" << numberReturned; if (!success) { - qDebug() << "UpnpContentDirectoryModel::browseFinished" << "in error"; + qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::browseFinished" << "in error"; return; } @@ -453,15 +456,15 @@ decltype(d->mData) newData; auto containerList = browseDescription.elementsByTagName(QStringLiteral("container")); - qDebug() << "UpnpContentDirectoryModel::browseFinished" << containerList.length(); + qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::browseFinished" << containerList.length(); for (int containerIndex = 0; containerIndex < containerList.length(); ++containerIndex) { const QDomNode &containerNode(containerList.at(containerIndex)); if (!containerNode.isNull()) { const QString &parentID = containerNode.toElement().attribute(QStringLiteral("parentID")); const QString &id = containerNode.toElement().attribute(QStringLiteral("id")); if (!d->mUpnpIds.contains(parentID)) { - qDebug() << "UpnpContentDirectoryModel::browseFinished" << "unknown parent id" << parentID << d->mUpnpIds.keys(); + qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::browseFinished" << "unknown parent id" << parentID << d->mUpnpIds.keys(); return; } @@ -524,7 +527,7 @@ const QString &id = itemNode.toElement().attribute(QStringLiteral("id")); if (!d->mUpnpIds.contains(parentID)) { - qDebug() << "UpnpContentDirectoryModel::browseFinished" << "unknown parent id"; + qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::browseFinished" << "unknown parent id"; return; } @@ -592,7 +595,7 @@ } } - qDebug() << "UpnpContentDirectoryModel::browseFinished" << "decoding finished"; + qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::browseFinished" << "decoding finished"; if (!newDataIds.isEmpty()) { QString parentId = newData[newDataIds.first()][ColumnsRoles::ParentIdRole].toString(); @@ -618,7 +621,7 @@ endRemoveRows(); } - qDebug() << "UpnpContentDirectoryModel::browseFinished" << newDataIds.size(); + qCDebug(orgKdeElisaUpnp()) << "UpnpContentDirectoryModel::browseFinished" << newDataIds.size(); beginInsertRows(indexFromInternalId(parentInternalId), 0, newDataIds.size() - 1); for (auto childInternalId : const_cast(newDataIds)) { d->mChilds[parentInternalId].push_back(childInternalId); diff --git a/src/upnp/upnpcontrolconnectionmanager.h b/src/upnp/upnpcontrolconnectionmanager.h --- a/src/upnp/upnpcontrolconnectionmanager.h +++ b/src/upnp/upnpcontrolconnectionmanager.h @@ -18,16 +18,14 @@ #ifndef UPNPCONTROLCONNECTIONMANAGER_H #define UPNPCONTROLCONNECTIONMANAGER_H -#include "upnpQt_export.h" - #include "upnpcontrolabstractservice.h" #include "upnpbasictypes.h" #include class UpnpControlConnectionManagerPrivate; -class UPNPQT_EXPORT UpnpControlConnectionManager : public UpnpControlAbstractService +class UpnpControlConnectionManager : public UpnpControlAbstractService { Q_OBJECT diff --git a/src/upnp/upnpcontrolconnectionmanager.cpp b/src/upnp/upnpcontrolconnectionmanager.cpp --- a/src/upnp/upnpcontrolconnectionmanager.cpp +++ b/src/upnp/upnpcontrolconnectionmanager.cpp @@ -19,10 +19,12 @@ #include "upnpcontrolconnectionmanager.h" +#include "upnpLogging.h" + #include #include -#include +#include class UpnpControlConnectionManagerPrivate { @@ -132,35 +134,35 @@ } } - qDebug() << "SourceProtocolInfo:" << d->mSourceProtocolInfo; - qDebug() << "SinkProtocolInfo:" << d->mSinkProtocolInfo; + qCDebug(orgKdeElisaUpnp()) << "SourceProtocolInfo:" << d->mSourceProtocolInfo; + qCDebug(orgKdeElisaUpnp()) << "SinkProtocolInfo:" << d->mSinkProtocolInfo; Q_EMIT getProtocolInfoFinished(!self->returnMessage().isFault()); } void UpnpControlConnectionManager::finishedPrepareForConnectionCall(KDSoapPendingCallWatcher *self) { self->deleteLater(); - qDebug() << self->returnValue(); + qCDebug(orgKdeElisaUpnp()) << self->returnValue(); Q_EMIT prepareForConnectionFinished(!self->returnMessage().isFault()); } void UpnpControlConnectionManager::finishedConnectionCompleteCall(KDSoapPendingCallWatcher *self) { self->deleteLater(); - qDebug() << self->returnValue(); + qCDebug(orgKdeElisaUpnp()) << self->returnValue(); Q_EMIT connectionCompleteFinished(!self->returnMessage().isFault()); } void UpnpControlConnectionManager::finishedGetCurrentConnectionIDsCall(KDSoapPendingCallWatcher *self) { self->deleteLater(); - qDebug() << self->returnValue(); + qCDebug(orgKdeElisaUpnp()) << self->returnValue(); d->mCurrentConnectionIDs = self->returnValue().toString(); Q_EMIT currentConnectionIDsChanged(d->mCurrentConnectionIDs); @@ -205,13 +207,13 @@ } } - qDebug() << "RcsID:" << rcsID; - qDebug() << "AVTransportID:" << avTransportID; - qDebug() << "protocolInfo:" << protocolInfo; - qDebug() << "PeerConnectionManager:" << connectionManager; - qDebug() << "PeerConnectionID:" << peerConnectionID; - qDebug() << "Direction:" << direction; - qDebug() << "Status:" << connectionStatus; + qCDebug(orgKdeElisaUpnp()) << "RcsID:" << rcsID; + qCDebug(orgKdeElisaUpnp()) << "AVTransportID:" << avTransportID; + qCDebug(orgKdeElisaUpnp()) << "protocolInfo:" << protocolInfo; + qCDebug(orgKdeElisaUpnp()) << "PeerConnectionManager:" << connectionManager; + qCDebug(orgKdeElisaUpnp()) << "PeerConnectionID:" << peerConnectionID; + qCDebug(orgKdeElisaUpnp()) << "Direction:" << direction; + qCDebug(orgKdeElisaUpnp()) << "Status:" << connectionStatus; Q_EMIT getCurrentConnectionInfoFinished(rcsID, avTransportID, protocolInfo, connectionManager, peerConnectionID, direction, connectionStatus, !self->returnMessage().isFault()); diff --git a/src/upnp/upnpcontrolcontentdirectory.cpp b/src/upnp/upnpcontrolcontentdirectory.cpp --- a/src/upnp/upnpcontrolcontentdirectory.cpp +++ b/src/upnp/upnpcontrolcontentdirectory.cpp @@ -19,12 +19,14 @@ #include "upnpcontrolcontentdirectory.h" +#include "upnpLogging.h" + #include "upnpcontrolabstractservicereply.h" #include #include -#include +#include class UpnpControlContentDirectoryPrivate { @@ -128,7 +130,7 @@ } } - qDebug() << "SearchCaps:" << searchCaps; + qCDebug(orgKdeElisaUpnp()) << "SearchCaps:" << searchCaps; //Q_EMIT getSearchCapabilitiesFinished(searchCaps, !self->returnMessage().isFault()); } @@ -147,7 +149,7 @@ } } - qDebug() << "SortCaps:" << sortCaps; + qCDebug(orgKdeElisaUpnp()) << "SortCaps:" << sortCaps; //Q_EMIT getSortCapabilitiesFinished(sortCaps, !self->returnMessage().isFault()); } @@ -165,14 +167,14 @@ } } - qDebug() << "Id:" << d->mSystemUpdateID; + qCDebug(orgKdeElisaUpnp()) << "Id:" << d->mSystemUpdateID; //Q_EMIT getSystemUpdateIDFinished(d->mSystemUpdateID, !self->returnMessage().isFault()); } void UpnpControlContentDirectory::finishedSearchCall(KDSoapPendingCallWatcher *self) { - qDebug() << "UpnpControlContentDirectory::finishedSearchCall"; + qCDebug(orgKdeElisaUpnp()) << "UpnpControlContentDirectory::finishedSearchCall"; self->deleteLater(); auto answer = self->returnMessage(); @@ -196,10 +198,10 @@ } } - //qDebug() << "Result:" << result; - qDebug() << "NumberReturned:" << numberReturned; - qDebug() << "TotalMatches:" << totalMatches; - qDebug() << "UpdateID:" << d->mSystemUpdateID; + //qCDebug(orgKdeElisaUpnp()) << "Result:" << result; + qCDebug(orgKdeElisaUpnp()) << "NumberReturned:" << numberReturned; + qCDebug(orgKdeElisaUpnp()) << "TotalMatches:" << totalMatches; + qCDebug(orgKdeElisaUpnp()) << "UpdateID:" << d->mSystemUpdateID; //Q_EMIT searchFinished(result, numberReturned, totalMatches, d->mSystemUpdateID, !self->returnMessage().isFault()); } @@ -229,10 +231,10 @@ } } - //qDebug() << "Result:" << result; - //qDebug() << "NumberReturned:" << numberReturned; - //qDebug() << "TotalMatches:" << totalMatches; - //qDebug() << "UpdateID:" << d->mSystemUpdateID; + //qCDebug(orgKdeElisaUpnp()) << "Result:" << result; + //qCDebug(orgKdeElisaUpnp()) << "NumberReturned:" << numberReturned; + //qCDebug(orgKdeElisaUpnp()) << "TotalMatches:" << totalMatches; + //qCDebug(orgKdeElisaUpnp()) << "UpdateID:" << d->mSystemUpdateID; //Q_EMIT browseFinished(result, numberReturned, totalMatches, d->mSystemUpdateID, !self->returnMessage().isFault()); } diff --git a/src/upnp/upnpcontrolmediaserver.cpp b/src/upnp/upnpcontrolmediaserver.cpp --- a/src/upnp/upnpcontrolmediaserver.cpp +++ b/src/upnp/upnpcontrolmediaserver.cpp @@ -20,8 +20,6 @@ #include "upnpcontrolmediaserver.h" #include "upnpcontrolconnectionmanager.h" -#include - class UpnpControlMediaServerPrivate { public: diff --git a/src/upnp/upnpdiscoverallmusic.h b/src/upnp/upnpdiscoverallmusic.h --- a/src/upnp/upnpdiscoverallmusic.h +++ b/src/upnp/upnpdiscoverallmusic.h @@ -32,83 +32,32 @@ Q_OBJECT - Q_PROPERTY(QString deviceId - READ deviceId - WRITE setDeviceId - NOTIFY deviceIdChanged) - - Q_PROPERTY(QString browseFlag - READ browseFlag - WRITE setBrowseFlag - NOTIFY browseFlagChanged) - - Q_PROPERTY(QString filter - READ filter - WRITE setFilter - NOTIFY filterChanged) - - Q_PROPERTY(QString sortCriteria - READ sortCriteria - WRITE setSortCriteria - NOTIFY sortCriteriaChanged) - - Q_PROPERTY(DatabaseInterface* albumDatabase - READ albumDatabase - WRITE setAlbumDatabase - NOTIFY albumDatabaseChanged) - public: explicit UpnpDiscoverAllMusic(QObject *parent = nullptr); ~UpnpDiscoverAllMusic() override; - QString deviceId() const; - - const QString& browseFlag() const; - - const QString& filter() const; - - const QString& sortCriteria() const; - - DatabaseInterface* albumDatabase() const; - Q_SIGNALS: - void deviceIdChanged(QString deviceId); - - void browseFlagChanged(); + void newUpnpContentDirectoryService(const QString &name); - void filterChanged(); + void removedUpnpContentDirectoryService(const QString &name); - void sortCriteriaChanged(); - - void albumDatabaseChanged(); + void networkChanged(); public Q_SLOTS: - void newDevice(QSharedPointer serviceDiscovery); - - void removedDevice(QSharedPointer serviceDiscovery); - - void setDeviceId(QString deviceId); - - void setBrowseFlag(const QString &flag); + void newDevice(const UpnpDiscoveryResult &newService); - void setFilter(const QString &flag); - - void setSortCriteria(const QString &criteria); - - void setAlbumDatabase(DatabaseInterface* albumDatabase); + void removedDevice(const UpnpDiscoveryResult &removedService); private Q_SLOTS: void deviceDescriptionChanged(const QString &uuid); void descriptionParsed(const QString &UDN); - void contentChanged(const QString &uuid, const QString &parentId); - private: std::unique_ptr d; diff --git a/src/upnp/upnpdiscoverallmusic.cpp b/src/upnp/upnpdiscoverallmusic.cpp --- a/src/upnp/upnpdiscoverallmusic.cpp +++ b/src/upnp/upnpdiscoverallmusic.cpp @@ -21,6 +21,8 @@ #include "config-upnp-qt.h" +#include "upnpLogging.h" + #include #include @@ -30,41 +32,27 @@ #include "upnpcontrolcontentdirectory.h" #include "didlparser.h" -#include "databaseinterface.h" - #include #include #include #include +#include + class UpnpDiscoverAllMusicPrivate { public: - QHash > mAllDeviceDiscoveryResults; - - QHash > mAllHostsDescription; + QHash mAllDeviceDiscoveryResults; - QHash > mDeviceDescriptionParsers; + QHash mAllHostsDescription; - QHash > mControlContentDirectory; - - QHash> mDidlParsers; + QHash> mDeviceDescriptionParsers; QList mAllHostsUUID; QNetworkAccessManager mNetworkAccess; - QString mDeviceId; - - QString mBrowseFlag; - - QString mFilter; - - QString mSortCriteria; - - DatabaseInterface* mAlbumDatabase = nullptr; - }; UpnpDiscoverAllMusic::UpnpDiscoverAllMusic(QObject *parent) : QObject(parent), d(new UpnpDiscoverAllMusicPrivate) @@ -74,98 +62,39 @@ UpnpDiscoverAllMusic::~UpnpDiscoverAllMusic() = default; -QString UpnpDiscoverAllMusic::deviceId() const -{ - return d->mDeviceId; -} - -const QString &UpnpDiscoverAllMusic::browseFlag() const +void UpnpDiscoverAllMusic::newDevice(const UpnpDiscoveryResult &newService) { - return d->mBrowseFlag; -} + qCDebug(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::newDevice" << newService; -const QString &UpnpDiscoverAllMusic::filter() const -{ - return d->mFilter; -} + const QString &deviceUuid = newService.usn().mid(5, 36); + if (!d->mAllDeviceDiscoveryResults.contains(deviceUuid)) { + d->mAllDeviceDiscoveryResults[deviceUuid] = newService; -const QString &UpnpDiscoverAllMusic::sortCriteria() const -{ - return d->mSortCriteria; -} + const QString &decodedUdn(deviceUuid); -DatabaseInterface *UpnpDiscoverAllMusic::albumDatabase() const -{ - return d->mAlbumDatabase; -} + d->mAllHostsUUID.push_back(decodedUdn); + d->mAllHostsDescription[decodedUdn].setUDN(decodedUdn); -void UpnpDiscoverAllMusic::newDevice(QSharedPointer serviceDiscovery) -{ - if (serviceDiscovery->nt() == d->mDeviceId) { - const QString &deviceUuid = serviceDiscovery->usn().mid(5, 36); - if (!d->mAllDeviceDiscoveryResults.contains(deviceUuid)) { - d->mAllDeviceDiscoveryResults[deviceUuid] = serviceDiscovery; - - const QString &decodedUdn(deviceUuid); - - d->mAllHostsUUID.push_back(decodedUdn); - d->mAllHostsDescription[decodedUdn].reset(new UpnpDeviceDescription); - d->mAllHostsDescription[decodedUdn]->setUDN(decodedUdn); + d->mDeviceDescriptionParsers[decodedUdn].reset(new UpnpDeviceDescriptionParser(&d->mNetworkAccess, d->mAllHostsDescription[decodedUdn])); - connect(d->mAllHostsDescription[decodedUdn].data(), &UpnpDeviceDescription::friendlyNameChanged, this, &UpnpDiscoverAllMusic::deviceDescriptionChanged); + connect(&d->mNetworkAccess, &QNetworkAccessManager::finished, d->mDeviceDescriptionParsers[decodedUdn].data(), &UpnpDeviceDescriptionParser::finishedDownload); + connect(d->mDeviceDescriptionParsers[decodedUdn].data(), &UpnpDeviceDescriptionParser::descriptionParsed, this, &UpnpDiscoverAllMusic::descriptionParsed); - d->mDeviceDescriptionParsers[decodedUdn].reset(new UpnpDeviceDescriptionParser(&d->mNetworkAccess, d->mAllHostsDescription[decodedUdn])); - - connect(&d->mNetworkAccess, &QNetworkAccessManager::finished, d->mDeviceDescriptionParsers[decodedUdn].data(), &UpnpDeviceDescriptionParser::finishedDownload); - connect(d->mDeviceDescriptionParsers[decodedUdn].data(), &UpnpDeviceDescriptionParser::descriptionParsed, this, &UpnpDiscoverAllMusic::descriptionParsed); - - d->mDeviceDescriptionParsers[decodedUdn]->downloadDeviceDescription(QUrl(serviceDiscovery->location())); - } + d->mDeviceDescriptionParsers[decodedUdn]->downloadDeviceDescription(QUrl(newService.location())); } } -void UpnpDiscoverAllMusic::removedDevice(QSharedPointer serviceDiscovery) +void UpnpDiscoverAllMusic::removedDevice(const UpnpDiscoveryResult &removedService) { - if (serviceDiscovery->nt() == d->mDeviceId) { - qDebug() << "nt" << serviceDiscovery->nt(); - qDebug() << "usn" << serviceDiscovery->usn(); - } -} + qCDebug(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::removedDevice" << removedService; -void UpnpDiscoverAllMusic::setDeviceId(QString deviceId) -{ - if (d->mDeviceId == deviceId) - return; - - d->mDeviceId = deviceId; - Q_EMIT deviceIdChanged(deviceId); -} - -void UpnpDiscoverAllMusic::setBrowseFlag(const QString &flag) -{ - d->mBrowseFlag = flag; - Q_EMIT browseFlagChanged(); -} - -void UpnpDiscoverAllMusic::setFilter(const QString &flag) -{ - d->mFilter = flag; - Q_EMIT filterChanged(); -} - -void UpnpDiscoverAllMusic::setSortCriteria(const QString &criteria) -{ - d->mSortCriteria = criteria; - Q_EMIT sortCriteriaChanged(); -} - -void UpnpDiscoverAllMusic::setAlbumDatabase(DatabaseInterface *albumDatabase) -{ - if (d->mAlbumDatabase == albumDatabase) + const QString &deviceUuid = removedService.usn().mid(5, 36); + if (!d->mAllDeviceDiscoveryResults.contains(deviceUuid)) { return; + } - d->mAlbumDatabase = albumDatabase; - Q_EMIT albumDatabaseChanged(); + qCInfo(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::removedDevice" << d->mAllHostsDescription[deviceUuid].friendlyName(); + Q_EMIT removedUpnpContentDirectoryService(d->mAllHostsDescription[deviceUuid].friendlyName()); } void UpnpDiscoverAllMusic::deviceDescriptionChanged(const QString &uuid) @@ -175,43 +104,26 @@ void UpnpDiscoverAllMusic::descriptionParsed(const QString &UDN) { + qCDebug(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::descriptionParsed" << UDN; + QString uuid = UDN.mid(5); d->mDeviceDescriptionParsers.remove(uuid); - int deviceIndex = d->mAllHostsUUID.indexOf(UDN.mid(5)); - - d->mControlContentDirectory[uuid] = QSharedPointer(new UpnpControlContentDirectory); - auto serviceDescription = d->mAllHostsDescription[d->mAllHostsUUID[deviceIndex]]->serviceById(QStringLiteral("urn:upnp-org:serviceId:ContentDirectory")); - d->mControlContentDirectory[uuid]->setDescription(serviceDescription.data()); - d->mDidlParsers[uuid] = QSharedPointer(new DidlParser); + int deviceIndex = d->mAllHostsUUID.indexOf(uuid); - auto currentDidlParser = d->mDidlParsers[uuid].data(); - currentDidlParser->setSearchCriteria(QStringLiteral("upnp:class = \"object.item.audioItem.musicTrack\"")); - currentDidlParser->setParentId(QStringLiteral("0")); - currentDidlParser->setContentDirectory(d->mControlContentDirectory[uuid].data()); + qCDebug(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::descriptionParsed" << d->mAllHostsUUID; + qCDebug(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::descriptionParsed" << uuid; + qCDebug(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::descriptionParsed" << deviceIndex; - connect(currentDidlParser, &DidlParser::isDataValidChanged, this, &UpnpDiscoverAllMusic::contentChanged); - - currentDidlParser->search(0, 0); -} - -void UpnpDiscoverAllMusic::contentChanged(const QString &uuid, const QString &parentId) -{ - if (!d->mAlbumDatabase) { + if (deviceIndex == -1) { + qCDebug(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::descriptionParsed" << d->mAllHostsUUID; return; } - if (parentId == QStringLiteral("0")) { - auto currentDidlParser = d->mDidlParsers[uuid]; - if (!currentDidlParser) { - return; - } - - const auto &allNewTracks = currentDidlParser->newMusicTracks(); + qCInfo(orgKdeElisaUpnp()) << "UpnpDiscoverAllMusic::descriptionParsed" << d->mAllHostsDescription[uuid].friendlyName(); - d->mAlbumDatabase->insertTracksList(allNewTracks, currentDidlParser->covers(), QStringLiteral("upnp")); - } + Q_EMIT newUpnpContentDirectoryService(d->mAllHostsDescription[uuid].friendlyName()); } diff --git a/src/upnp/upnplistener.h b/src/upnp/upnplistener.h deleted file mode 100644 --- a/src/upnp/upnplistener.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2016-2017 Matthieu Gallien - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef UPNPLISTENER_H -#define UPNPLISTENER_H - -#include -#include -#include - -#include - -class UpnpListenerPrivate; - -class DatabaseInterface; -class UpnpDiscoverAllMusic; -class UpnpSsdpEngine; -class MusicAudioTrack; - -class UpnpListener : public QObject -{ - Q_OBJECT - - Q_PROPERTY(DatabaseInterface* databaseInterface - READ databaseInterface - WRITE setDatabaseInterface - NOTIFY databaseInterfaceChanged) - -public: - - explicit UpnpListener(QObject *parent = nullptr); - - ~UpnpListener() override; - - DatabaseInterface* databaseInterface() const; - -Q_SIGNALS: - - void databaseInterfaceChanged(); - - void databaseReady(); - - void initialTracksListRequired(QString musicSource); - - void initialTracksList(QString musicSource, QList initialList); - -public Q_SLOTS: - - void setDatabaseInterface(DatabaseInterface* databaseInterface); - - void applicationAboutToQuit(); - -private: - - std::unique_ptr d; - -}; - -#endif // UPNPLISTENER_H diff --git a/src/upnp/upnplistener.cpp b/src/upnp/upnplistener.cpp deleted file mode 100644 --- a/src/upnp/upnplistener.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2016-2017 Matthieu Gallien - * - * 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 "upnplistener.h" - -#include "databaseinterface.h" -#include "upnpdiscoverallmusic.h" -#include "upnpssdpengine.h" - -class UpnpListenerPrivate -{ -public: - - UpnpDiscoverAllMusic mUpnpManager; - - UpnpSsdpEngine mSsdpEngine; - -}; - -UpnpListener::UpnpListener(QObject *parent) : QObject(parent), d(new UpnpListenerPrivate) -{ - d->mSsdpEngine.initialize(); - d->mSsdpEngine.searchAllUpnpDevice(); - - d->mUpnpManager.setDeviceId(QStringLiteral("urn:schemas-upnp-org:service:ContentDirectory:1")); - - connect(&d->mSsdpEngine, &UpnpSsdpEngine::newService, - &d->mUpnpManager, &UpnpDiscoverAllMusic::newDevice); - connect(&d->mSsdpEngine, &UpnpSsdpEngine::removedService, - &d->mUpnpManager, &UpnpDiscoverAllMusic::removedDevice); -} - -UpnpListener::~UpnpListener() -= default; - -DatabaseInterface *UpnpListener::databaseInterface() const -{ - return nullptr; -} - -void UpnpListener::setDatabaseInterface(DatabaseInterface *model) -{ - d->mUpnpManager.setAlbumDatabase(model); - - Q_EMIT databaseInterfaceChanged(); -} - -void UpnpListener::applicationAboutToQuit() -{ -} - - -#include "moc_upnplistener.cpp" diff --git a/src/viewmanager.h b/src/viewmanager.h --- a/src/viewmanager.h +++ b/src/viewmanager.h @@ -45,7 +45,8 @@ RecentlyPlayedTracks, FilesBrowser, Context, - RadiosBrowser + RadiosBrowser, + UpnpServers, }; Q_ENUM(ViewsType) @@ -129,6 +130,8 @@ void openFilesBrowser(const QString &mainTitle, const QUrl &imageUrl); + void openUpnpServers(const QString &mainTitle, const QUrl &imageUrl); + void openContextView(const QString &mainTitle, const QUrl &imageUrl); void openRadiosBrowser(const QString &mainTitle, const QUrl &imageUrl); @@ -164,6 +167,8 @@ void radiosBrowserViewIsLoaded(); + void upnpServersIsLoaded(); + QString mCurrentAlbumTitle; QString mCurrentAlbumAuthor; QString mCurrentArtistName; diff --git a/src/viewmanager.cpp b/src/viewmanager.cpp --- a/src/viewmanager.cpp +++ b/src/viewmanager.cpp @@ -54,6 +54,9 @@ case RadiosBrowser: openRadiosBrowser(mainTitle, mainImage); break; + case UpnpServers: + openUpnpServers(mainTitle, mainImage); + break; case OneAlbum: case OneArtist: case OneAlbumFromArtist: @@ -85,6 +88,7 @@ case ElisaUtils::Composer: case ElisaUtils::Radio: case ElisaUtils::Unknown: + case ElisaUtils::NetworkService: break; } } @@ -138,6 +142,9 @@ case ViewsType::RadiosBrowser: radiosBrowserViewIsLoaded(); break; + case ViewsType::UpnpServers: + upnpServersIsLoaded(); + break; } } @@ -292,6 +299,15 @@ } } +void ViewManager::openUpnpServers(const QString &mainTitle, const QUrl &imageUrl) +{ + mTargetView = ViewsType::UpnpServers; + if (mCurrentView != mTargetView) { + Q_EMIT openGridView(ViewsType::UpnpServers, ElisaUtils::NoFilter, 1, mainTitle, {}, imageUrl, ElisaUtils::NetworkService, + QUrl(QStringLiteral("image://icon/network-server")), {}, {}, false, false); + } +} + void ViewManager::openContextView(const QString &mainTitle, const QUrl &imageUrl) { mTargetView = ViewsType::Context; @@ -404,6 +420,11 @@ mCurrentView = ViewsType::RadiosBrowser; } +void ViewManager::upnpServersIsLoaded() +{ + mCurrentView = ViewsType::UpnpServers; +} + void ViewManager::goBack() { Q_EMIT popOneView();