File indexing completed on 2025-01-05 03:52:08

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2012-05-28
0007  * Description : Media server manager
0008  *
0009  * SPDX-FileCopyrightText: 2012      by Smit Mehta <smit dot meh at gmail dot com>
0010  * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "dmediaservermngr.h"
0017 
0018 // Qt includes
0019 
0020 #include <QApplication>
0021 #include <QStringList>
0022 #include <QUrl>
0023 #include <QFile>
0024 #include <QDomDocument>
0025 #include <QDomElement>
0026 #include <QTextStream>
0027 #include <QStandardPaths>
0028 
0029 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
0030 #   include <QTextCodec>
0031 #endif
0032 
0033 // KDE includes
0034 
0035 #include <klocalizedstring.h>
0036 #include <ksharedconfig.h>
0037 #include <kconfiggroup.h>
0038 
0039 // Local includes
0040 
0041 #include "digikam_debug.h"
0042 #include "dnotificationwrapper.h"
0043 
0044 using namespace Digikam;
0045 
0046 namespace DigikamGenericMediaServerPlugin
0047 {
0048 
0049 class Q_DECL_HIDDEN DMediaServerMngrCreator
0050 {
0051 public:
0052 
0053     DMediaServerMngr object;
0054 };
0055 
0056 Q_GLOBAL_STATIC(DMediaServerMngrCreator, creator)
0057 
0058 // ---------------------------------------------------------------------------------------------
0059 
0060 class Q_DECL_HIDDEN DMediaServerMngr::Private
0061 {
0062 public:
0063 
0064     explicit Private()
0065         : server(nullptr)
0066     {
0067     }
0068 
0069     /// Configuration XML file to store albums map to share in case of restoring between sessions.
0070     QString              mapsConf;
0071 
0072     /// Server instance pointer.
0073     DMediaServer*        server;
0074 
0075     /// The current albums collection to share.
0076     MediaServerMap       collectionMap;
0077 
0078     static const QString configGroupName;
0079     static const QString configStartServerOnStartupEntry;
0080 };
0081 
0082 const QString DMediaServerMngr::Private::configGroupName(QLatin1String("DLNA Settings"));
0083 const QString DMediaServerMngr::Private::configStartServerOnStartupEntry(QLatin1String("Start MediaServer At Startup"));
0084 
0085 DMediaServerMngr* DMediaServerMngr::instance()
0086 {
0087     return &creator->object;
0088 }
0089 
0090 DMediaServerMngr::DMediaServerMngr()
0091     : d(new Private)
0092 {
0093     d->mapsConf = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +
0094                   QLatin1String("/mediaserver.xml");
0095 }
0096 
0097 DMediaServerMngr::~DMediaServerMngr()
0098 {
0099     delete d;
0100 }
0101 
0102 QString DMediaServerMngr::configGroupName() const
0103 {
0104     return d->configGroupName;
0105 }
0106 
0107 QString DMediaServerMngr::configStartServerOnStartupEntry() const
0108 {
0109     return d->configStartServerOnStartupEntry;
0110 }
0111 
0112 void DMediaServerMngr::cleanUp()
0113 {
0114     delete d->server;
0115     d->server = nullptr;
0116 }
0117 
0118 bool DMediaServerMngr::loadAtStartup()
0119 {
0120     KSharedConfig::Ptr config    = KSharedConfig::openConfig();
0121     KConfigGroup dlnaConfigGroup = config->group(configGroupName());
0122     bool startServerOnStartup    = dlnaConfigGroup.readEntry(configStartServerOnStartupEntry(), false);
0123     bool result                  = true;
0124 
0125     if (startServerOnStartup)
0126     {
0127         // Restore the old sharing configuration and start the server.
0128 
0129         result &= load();
0130         result &= startMediaServer();
0131 
0132         mediaServerNotification(result);
0133 
0134         return result;
0135     }
0136 
0137     return false;
0138 }
0139 
0140 void DMediaServerMngr::saveAtShutdown()
0141 {
0142     KSharedConfig::Ptr config    = KSharedConfig::openConfig();
0143     KConfigGroup dlnaConfigGroup = config->group(configGroupName());
0144     bool startServerOnStartup    = dlnaConfigGroup.readEntry(configStartServerOnStartupEntry(), false);
0145 
0146     if (startServerOnStartup)
0147     {
0148         // Save the current sharing configuration for the next session.
0149 
0150         save();
0151     }
0152 
0153     cleanUp();
0154 }
0155 
0156 void DMediaServerMngr::mediaServerNotification(bool started)
0157 {
0158     DNotificationWrapper(QLatin1String("mediaserverloadstartup"),
0159                          started ? i18n("Media Server have been started")
0160                                  : i18n("Media Server cannot be started!"),
0161                          qApp->activeWindow(), qApp->applicationName());
0162 }
0163 
0164 void DMediaServerMngr::setItemsList(const QString& aname, const QList<QUrl>& urls)
0165 {
0166     d->collectionMap.clear();
0167     d->collectionMap.insert(aname, urls);
0168 }
0169 
0170 QList<QUrl> DMediaServerMngr::itemsList() const
0171 {
0172     QList<QUrl> ret;
0173 
0174     if (!d->collectionMap.isEmpty())
0175     {
0176         QList<QList<QUrl> > ulst = d->collectionMap.values();
0177 
0178         Q_FOREACH (const QList<QUrl>& urls, ulst)
0179         {
0180             ret << urls;
0181         }
0182     }
0183 
0184     return ret;
0185 }
0186 
0187 void DMediaServerMngr::setCollectionMap(const MediaServerMap& map)
0188 {
0189     d->collectionMap = map;
0190 }
0191 
0192 MediaServerMap DMediaServerMngr::collectionMap() const
0193 {
0194     return d->collectionMap;
0195 }
0196 
0197 bool DMediaServerMngr::startMediaServer()
0198 {
0199     if (!d->server)
0200     {
0201         d->server = new DMediaServer();
0202 
0203         if (!d->server->init())
0204         {
0205             cleanUp();
0206 
0207             return false;
0208         }
0209     }
0210 
0211     if (d->collectionMap.isEmpty())
0212     {
0213         cleanUp();
0214 
0215         return false;
0216     }
0217 
0218     d->server->addAlbumsOnServer(d->collectionMap);
0219 
0220     return true;
0221 }
0222 
0223 bool DMediaServerMngr::isRunning() const
0224 {
0225     return (d->server ? true : false);
0226 }
0227 
0228 int DMediaServerMngr::albumsShared() const
0229 {
0230     if (d->collectionMap.isEmpty())
0231     {
0232         return 0;
0233     }
0234 
0235     return d->collectionMap.count();
0236 }
0237 
0238 int DMediaServerMngr::itemsShared() const
0239 {
0240     return itemsList().count();
0241 }
0242 
0243 bool DMediaServerMngr::save()
0244 {
0245     QDomDocument doc(QLatin1String("mediaserverlist"));
0246     doc.setContent(QString::fromUtf8("<!DOCTYPE XMLQueueList><mediaserverlist version=\"1.0\" client=\"digikam\" encoding=\"UTF-8\"/>"));
0247     QDomElement docElem = doc.documentElement();
0248 
0249     auto end = d->collectionMap.cend();
0250 
0251     for (auto it = d->collectionMap.cbegin() ; it != end ; ++it)
0252     {
0253         QDomElement elm = doc.createElement(QLatin1String("album"));
0254         elm.setAttribute(QLatin1String("title"), it.key());
0255 
0256         // ----------------------
0257 
0258         QDomElement data;
0259 
0260         Q_FOREACH (const QUrl& url, it.value())
0261         {
0262             data = doc.createElement(QLatin1String("path"));
0263             data.setAttribute(QLatin1String("value"), url.toLocalFile());
0264             elm.appendChild(data);
0265         }
0266 
0267         docElem.appendChild(elm);
0268     }
0269 
0270     QFile file(d->mapsConf);
0271 
0272     if (!file.open(QIODevice::WriteOnly))
0273     {
0274         qCDebug(DIGIKAM_MEDIASRV_LOG) << "Cannot open XML file to store MediaServer list";
0275         qCDebug(DIGIKAM_MEDIASRV_LOG) << file.fileName();
0276 
0277         return false;
0278     }
0279 
0280     QTextStream stream(&file);
0281 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
0282     // In Qt5 only. Qt6 uses UTF-8 by default.
0283     stream.setCodec(QTextCodec::codecForName("UTF-8"));
0284 #endif
0285     stream.setAutoDetectUnicode(true);
0286     stream << doc.toString(4);
0287     file.close();
0288 
0289     return true;
0290 }
0291 
0292 bool DMediaServerMngr::load()
0293 {
0294     QFile file(d->mapsConf);
0295 
0296     if (file.exists())
0297     {
0298         if (!file.open(QIODevice::ReadOnly))
0299         {
0300             qCDebug(DIGIKAM_MEDIASRV_LOG) << "Cannot open XML file to load MediaServer list";
0301 
0302             return false;
0303         }
0304 
0305         QDomDocument doc(QLatin1String("mediaserverlist"));
0306 
0307         if (!doc.setContent(&file))
0308         {
0309             qCDebug(DIGIKAM_MEDIASRV_LOG) << "Cannot load MediaServer list XML file";
0310             file.close();
0311 
0312             return false;
0313         }
0314 
0315         QDomElement    docElem = doc.documentElement();
0316         MediaServerMap map;
0317         QList<QUrl>    urls;
0318         QString        album;
0319 
0320         for (QDomNode n = docElem.firstChild() ; !n.isNull() ; n = n.nextSibling())
0321         {
0322             QDomElement e = n.toElement();
0323 
0324             if (e.isNull())
0325             {
0326                 continue;
0327             }
0328 
0329             if (e.tagName() != QLatin1String("album"))
0330             {
0331                 continue;
0332             }
0333 
0334             album = e.attribute(QLatin1String("title"));
0335             urls.clear();
0336 
0337             for (QDomNode n2 = e.firstChild() ; !n2.isNull() ; n2 = n2.nextSibling())
0338             {
0339                 QDomElement e2 = n2.toElement();
0340 
0341                 if (e2.isNull())
0342                 {
0343                     continue;
0344                 }
0345 
0346                 QString name2  = e2.tagName();
0347                 QString val2   = e2.attribute(QLatin1String("value"));
0348 
0349                 if (name2 == QLatin1String("path"))
0350                 {
0351                     urls << QUrl::fromLocalFile(val2);
0352                 }
0353             }
0354 
0355             map.insert(album, urls);
0356         }
0357 
0358         setCollectionMap(map);
0359         file.close();
0360 
0361         return true;
0362     }
0363     else
0364     {
0365         return false;
0366     }
0367 }
0368 
0369 } // namespace DigikamGenericMediaServerPlugin
0370 
0371 #include "moc_dmediaservermngr.cpp"