MythTV  master
netgrabbermanager.cpp
Go to the documentation of this file.
1 #include "netgrabbermanager.h"
2 
3 // qt
4 #include <QCoreApplication>
5 #include <QDir>
6 #include <QFile>
7 #include <QString>
8 #include <utility>
9 
10 #include "libmythbase/exitcodes.h"
11 #include "libmythbase/mythcorecontext.h" // for GetDurSetting TODO: excise database from MythCoreContext
12 #include "libmythbase/mythdate.h"
13 #include "libmythbase/mythdirs.h"
16 
17 #include "netutils.h"
18 
19 #define LOC QString("NetContent: ")
20 
21 // ---------------------------------------------------
22 
24 {
25  wait();
26 }
27 
29 {
30  RunProlog();
31  QMutexLocker locker(&m_lock);
32 
33  QString commandline = m_commandline;
34  MythSystemLegacy getTree(commandline, QStringList("-T"),
36  getTree.Run(15min);
37  uint status = getTree.Wait();
38 
39  if( status == GENERIC_EXIT_CMD_NOT_FOUND )
40  {
41  LOG(VB_GENERAL, LOG_ERR, LOC +
42  QString("Internet Content Source %1 cannot run, file missing.")
43  .arg(m_title));
44  }
45  else if( status == GENERIC_EXIT_OK )
46  {
47  LOG(VB_GENERAL, LOG_INFO, LOC +
48  QString("Internet Content Source %1 completed download, "
49  "beginning processing...").arg(m_title));
50 
51  QByteArray result = getTree.ReadAll();
52 
53  QDomDocument domDoc;
54 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
55  domDoc.setContent(result, true);
56 #else
57  domDoc.setContent(result, QDomDocument::ParseOption::UseNamespaceProcessing);
58 #endif
59  QDomElement root = domDoc.documentElement();
60  QDomElement channel = root.firstChildElement("channel");
61 
63 
64  while (!channel.isNull())
65  {
66  parseDBTree(m_title, QString(), QString(), channel, GetType());
67  channel = channel.nextSiblingElement("channel");
68  }
70  LOG(VB_GENERAL, LOG_INFO, LOC +
71  QString("Internet Content Source %1 completed processing, "
72  "marking as updated.").arg(m_title));
73  }
74  else
75  {
76  LOG(VB_GENERAL, LOG_ERR, LOC +
77  QString("Internet Content Source %1 crashed while grabbing tree.")
78  .arg(m_title));
79  }
80 
81  // NOLINTNEXTLINE(readability-misleading-indentation)
82  emit finished();
83  RunEpilog();
84 }
85 
86 void GrabberScript::parseDBTree(const QString &feedtitle, const QString &path,
87  const QString &pathThumb, QDomElement& domElem,
88  const ArticleType type)
89 {
90  QMutexLocker locker(&m_lock);
91 
92  Parse parse;
93  ResultItem::resultList articles;
94 
95  // File Handling
96  QDomElement fileitem = domElem.firstChildElement("item");
97  while (!fileitem.isNull())
98  { // Fill the article list...
99  articles.append(Parse::ParseItem(fileitem));
100  fileitem = fileitem.nextSiblingElement("item");
101  }
102 
103  while (!articles.isEmpty())
104  { // Insert the articles in the DB...
105  insertTreeArticleInDB(feedtitle, path,
106  pathThumb, articles.takeFirst(), type);
107  }
108 
109  // Directory Handling
110  QDomElement diritem = domElem.firstChildElement("directory");
111  while (!diritem.isNull())
112  {
113  QDomElement subfolder = diritem;
114  QString dirname = diritem.attribute("name");
115  QString dirthumb = diritem.attribute("thumbnail");
116  dirname.replace("/", "|");
117  QString pathToUse;
118 
119  if (path.isEmpty())
120  pathToUse = dirname;
121  else
122  pathToUse = QString("%1/%2").arg(path, dirname);
123 
124  parseDBTree(feedtitle,
125  pathToUse,
126  dirthumb,
127  subfolder,
128  type);
129  diritem = diritem.nextSiblingElement("directory");
130  }
131 }
132 
134  : m_timer(new QTimer()),
135  m_updateFreq(gCoreContext->GetDurSetting<std::chrono::hours>("netsite.updateFreq", 24h))
136 {
137  connect( m_timer, &QTimer::timeout,
138  this, &GrabberManager::timeout);
139 }
140 
142 {
143  delete m_timer;
144 }
145 
147 {
148  m_timer->start(m_updateFreq);
149 }
150 
152 {
153  m_timer->stop();
154 }
155 
157 {
158  auto *gdt = new GrabberDownloadThread(this);
159  if (m_refreshAll)
160  gdt->refreshAll();
161  gdt->start(QThread::LowPriority);
162 
163  m_timer->start(m_updateFreq);
164 }
165 
167 {
168  QMutexLocker locker(&m_lock);
169  doUpdate();
170 }
171 
173 {
174  m_refreshAll = true;
175 }
176 
178  MThread("GrabberDownload"),
179  m_parent(parent)
180 {
181 }
182 
184 {
185  cancel();
186  wait();
187 }
188 
190 {
191  m_mutex.lock();
192  qDeleteAll(m_scripts);
193  m_scripts.clear();
194  m_mutex.unlock();
195 }
196 
198 {
199  m_mutex.lock();
200  m_refreshAll = true;
201  if (!isRunning())
202  start();
203  m_mutex.unlock();
204 }
205 
207 {
208  RunProlog();
209 
211  auto updateFreq = gCoreContext->GetDurSetting<std::chrono::hours>(
212  "netsite.updateFreq", 24h);
213 
214  while (!m_scripts.isEmpty())
215  {
216  GrabberScript *script = m_scripts.takeFirst();
217  if (script && (needsUpdate(script, updateFreq) || m_refreshAll))
218  {
219  LOG(VB_GENERAL, LOG_INFO, LOC +
220  QString("Internet Content Source %1 Updating...")
221  .arg(script->GetTitle()));
222  script->run();
223  }
224  delete script;
225  }
226  emit finished();
227  if (m_parent)
228  QCoreApplication::postEvent(m_parent, new GrabberUpdateEvent());
229 
230  RunEpilog();
231 }
232 
234 {
235  m_videoList.clear();
236 }
237 
239 {
240  resetSearch();
241 
242  delete m_searchProcess;
243  m_searchProcess = nullptr;
244 }
245 
246 
247 void Search::executeSearch(const QString &script, const QString &query,
248  const QString &pagenum)
249 {
250  resetSearch();
251 
252  LOG(VB_GENERAL, LOG_DEBUG, "Search::executeSearch");
254 
256  this, qOverload<>(&Search::slotProcessSearchExit));
258  this, qOverload<uint>(&Search::slotProcessSearchExit));
259 
260  const QString& cmd = script;
261 
262  QStringList args;
263 
264  if (!pagenum.isEmpty())
265  {
266  args.append(QString("-p"));
267  args.append(pagenum);
268  }
269 
270  args.append("-S");
271  const QString& term = query;
272  args.append(MythSystemLegacy::ShellEscape(term));
273 
274  LOG(VB_GENERAL, LOG_INFO, LOC +
275  QString("Internet Search Query: %1 %2").arg(cmd, args.join(" ")));
276 
278  m_searchProcess->SetCommand(cmd, args, flags);
279  m_searchProcess->Run(40s);
280 }
281 
283 {
284  qDeleteAll(m_videoList);
285  m_videoList.clear();
286 }
287 
289 {
290  Parse parse;
292 
293  QDomNodeList entries = m_document.elementsByTagName("channel");
294 
295  if (entries.count() == 0)
296  {
297  m_numResults = 0;
298  m_numReturned = 0;
299  m_numIndex = 0;
300  return;
301  }
302 
303  QDomNode itemNode = entries.item(0);
304 
305  QDomNode Node = itemNode.namedItem(QString("numresults"));
306  if (!Node.isNull())
307  {
308  m_numResults = Node.toElement().text().toUInt();
309  }
310  else
311  {
312  QDomNodeList count = m_document.elementsByTagName("item");
313 
314  if (count.count() == 0)
315  m_numResults = 0;
316  else
317  m_numResults = count.count();
318  }
319 
320  Node = itemNode.namedItem(QString("returned"));
321  if (!Node.isNull())
322  {
323  m_numReturned = Node.toElement().text().toUInt();
324  }
325  else
326  {
327  QDomNodeList items = m_document.elementsByTagName("item");
328 
329  if (items.count() == 0)
330  m_numReturned = 0;
331  else
332  m_numReturned = items.count();
333  }
334 
335  Node = itemNode.namedItem(QString("startindex"));
336  if (!Node.isNull())
337  {
338  m_numIndex = Node.toElement().text().toUInt();
339  }
340  else
341  {
342  m_numIndex = 0;
343  }
344 
345  Node = itemNode.namedItem(QString("nextpagetoken"));
346  if (!Node.isNull())
347  {
348  m_nextPageToken = Node.toElement().text();
349  }
350  else
351  {
352  m_nextPageToken = "";
353  }
354 
355  Node = itemNode.namedItem(QString("prevpagetoken"));
356  if (!Node.isNull())
357  {
358  m_prevPageToken = Node.toElement().text();
359  }
360  else
361  {
362  m_prevPageToken = "";
363  }
364 }
365 
367 {
368  if (exitcode == GENERIC_EXIT_TIMEOUT)
369  {
370  LOG(VB_GENERAL, LOG_WARNING, LOC + "Internet Search Timeout");
371 
372  if (m_searchProcess)
373  {
374  m_searchProcess->Term(true);
375  m_searchProcess->deleteLater();
376  m_searchProcess = nullptr;
377  }
378  emit searchTimedOut(this);
379  return;
380  }
381 
382  if (exitcode != GENERIC_EXIT_OK)
383  {
384  m_document.setContent(QString());
385  }
386  else
387  {
388  LOG(VB_GENERAL, LOG_INFO, LOC +
389  "Internet Search Successfully Completed");
390 
392 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
393  m_document.setContent(m_data, true);
394 #else
395  m_document.setContent(m_data, QDomDocument::ParseOption::UseNamespaceProcessing);
396 #endif
397  }
398 
399  m_searchProcess->deleteLater();
400  m_searchProcess = nullptr;
401  emit finishedSearch(this);
402 }
403 
405 {
407 }
408 
409 void Search::SetData(QByteArray data)
410 {
411  m_data = std::move(data);
412 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
413  m_document.setContent(m_data, true);
414 #else
415  m_document.setContent(m_data, QDomDocument::ParseOption::UseNamespaceProcessing);
416 #endif
417 }
needsUpdate
bool needsUpdate(GrabberScript *script, std::chrono::hours updateFreq)
Definition: netutils.cpp:330
build_compdb.args
args
Definition: build_compdb.py:11
GrabberScript::GetType
const ArticleType & GetType() const
Definition: netgrabbermanager.h:42
Search::m_searchProcess
MythSystemLegacy * m_searchProcess
Definition: netgrabbermanager.h:171
GrabberScript::m_lock
QRecursiveMutex m_lock
Definition: netgrabbermanager.h:63
Search::finishedSearch
void finishedSearch(Search *item)
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
insertTreeArticleInDB
bool insertTreeArticleInDB(const QString &feedtitle, const QString &path, const QString &paththumb, ResultItem *item, ArticleType type)
Definition: netutils.cpp:399
Search::m_numIndex
uint m_numIndex
Definition: netgrabbermanager.h:179
MythSystemLegacy::Term
void Term(bool force=false)
Definition: mythsystemlegacy.cpp:285
MythSystemLegacy
Definition: mythsystemlegacy.h:67
Search::m_numResults
uint m_numResults
Definition: netgrabbermanager.h:177
Search::~Search
~Search() override
Definition: netgrabbermanager.cpp:238
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
GrabberManager::startTimer
void startTimer()
Definition: netgrabbermanager.cpp:146
GrabberManager::m_updateFreq
std::chrono::hours m_updateFreq
Definition: netgrabbermanager.h:100
Search::m_numReturned
uint m_numReturned
Definition: netgrabbermanager.h:178
Search::m_videoList
ResultItem::resultList m_videoList
Definition: netgrabbermanager.h:175
GrabberManager::GrabberManager
GrabberManager()
Definition: netgrabbermanager.cpp:133
MythSystemLegacy::finished
void finished(void)
GrabberScript::GetTitle
const QString & GetTitle() const
Definition: netgrabbermanager.h:40
GrabberScript::m_commandline
QString m_commandline
Definition: netgrabbermanager.h:72
GrabberScript::parseDBTree
void parseDBTree(const QString &feedtitle, const QString &path, const QString &pathThumb, QDomElement &domElem, ArticleType type)
Definition: netgrabbermanager.cpp:86
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
MythSystemLegacy::ReadAll
QByteArray & ReadAll()
Definition: mythsystemlegacy.cpp:402
Search::m_nextPageToken
QString m_nextPageToken
Definition: netgrabbermanager.h:181
Search::SetData
void SetData(QByteArray data)
Definition: netgrabbermanager.cpp:409
GrabberDownloadThread::GrabberDownloadThread
GrabberDownloadThread(QObject *parent)
Definition: netgrabbermanager.cpp:177
GrabberDownloadThread::m_refreshAll
bool m_refreshAll
Definition: netgrabbermanager.h:139
mythdirs.h
findAllDBTreeGrabbers
GrabberScript::scriptList findAllDBTreeGrabbers()
Definition: netutils.cpp:115
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
markTreeUpdated
bool markTreeUpdated(GrabberScript *script, const QDateTime &curTime)
Definition: netutils.cpp:314
MythSystemLegacy::SetCommand
void SetCommand(const QString &command, uint flags)
Resets an existing MythSystemLegacy object to a new command.
Definition: mythsystemlegacy.cpp:88
mythsystemlegacy.h
Parse
Definition: rssparse.h:188
mythdate.h
GrabberDownloadThread::m_parent
QObject * m_parent
Definition: netgrabbermanager.h:136
mythlogging.h
Search::m_document
QDomDocument m_document
Definition: netgrabbermanager.h:174
Search::process
void process(void)
Definition: netgrabbermanager.cpp:288
netgrabbermanager.h
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
MythSystemLegacy::error
void error(uint status)
Search::m_prevPageToken
QString m_prevPageToken
Definition: netgrabbermanager.h:182
MythSystemLegacy::ShellEscape
static QString ShellEscape(const QString &in)
Definition: mythsystemlegacy.cpp:482
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:168
GENERIC_EXIT_CMD_NOT_FOUND
@ GENERIC_EXIT_CMD_NOT_FOUND
Command not found.
Definition: exitcodes.h:15
GrabberManager::m_lock
QRecursiveMutex m_lock
Definition: netgrabbermanager.h:97
netutils.h
MythSystemLegacy::Wait
uint Wait(std::chrono::seconds timeout=0s)
Definition: mythsystemlegacy.cpp:243
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
gdt
GrabberDownloadThread * gdt
Definition: mythfillnetvision.cpp:27
GrabberScript
Definition: netgrabbermanager.h:17
GrabberUpdateEvent
Definition: netgrabbermanager.h:107
GrabberScript::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: netgrabbermanager.cpp:28
GrabberScript::m_title
QString m_title
Definition: netgrabbermanager.h:65
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
kMSRunShell
@ kMSRunShell
run process through shell
Definition: mythsystem.h:43
kMSRunBackground
@ kMSRunBackground
run child in the background
Definition: mythsystem.h:38
GrabberDownloadThread::refreshAll
void refreshAll()
Definition: netgrabbermanager.cpp:197
ArticleType
ArticleType
Definition: rssparse.h:20
GrabberManager::m_refreshAll
bool m_refreshAll
Definition: netgrabbermanager.h:102
GrabberManager::m_timer
QTimer * m_timer
Definition: netgrabbermanager.h:98
GrabberManager::~GrabberManager
~GrabberManager() override
Definition: netgrabbermanager.cpp:141
GrabberManager::doUpdate
void doUpdate()
Definition: netgrabbermanager.cpp:156
GrabberScript::~GrabberScript
~GrabberScript() override
Definition: netgrabbermanager.cpp:23
clearTreeItems
bool clearTreeItems(const QString &feedcommand)
Definition: netutils.cpp:360
GrabberDownloadThread::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: netgrabbermanager.cpp:206
mythcorecontext.h
Search::Search
Search()
Definition: netgrabbermanager.cpp:233
Search::m_data
QByteArray m_data
Definition: netgrabbermanager.h:173
Parse::ParseItem
static ResultItem * ParseItem(const QDomElement &item)
Definition: rssparse.cpp:734
Search::searchTimedOut
void searchTimedOut(Search *item)
GrabberDownloadThread::m_mutex
QMutex m_mutex
Definition: netgrabbermanager.h:138
GrabberDownloadThread::~GrabberDownloadThread
~GrabberDownloadThread() override
Definition: netgrabbermanager.cpp:183
Search::resetSearch
void resetSearch(void)
Definition: netgrabbermanager.cpp:282
GrabberScript::finished
void finished(void)
Search::slotProcessSearchExit
void slotProcessSearchExit(void)
Definition: netgrabbermanager.cpp:404
GrabberManager::timeout
void timeout(void)
Definition: netgrabbermanager.cpp:166
GrabberManager::stopTimer
void stopTimer()
Definition: netgrabbermanager.cpp:151
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:263
ResultItem::resultList
QList< ResultItem * > resultList
Definition: rssparse.h:114
GrabberDownloadThread::m_scripts
QList< GrabberScript * > m_scripts
Definition: netgrabbermanager.h:137
Parse::parseRSS
static ResultItem::resultList parseRSS(const QDomDocument &domDoc)
Definition: rssparse.cpp:711
MythSystemLegacy::Run
void Run(std::chrono::seconds timeout=0s)
Runs a command inside the /bin/sh shell. Returns immediately.
Definition: mythsystemlegacy.cpp:213
GrabberDownloadThread::cancel
void cancel()
Definition: netgrabbermanager.cpp:189
GrabberManager::refreshAll
void refreshAll()
Definition: netgrabbermanager.cpp:172
exitcodes.h
Search::executeSearch
void executeSearch(const QString &script, const QString &query, const QString &pagenum="")
Definition: netgrabbermanager.cpp:247
kMSStdOut
@ kMSStdOut
allow access to stdout
Definition: mythsystem.h:41
GrabberDownloadThread::finished
void finished()
GENERIC_EXIT_TIMEOUT
@ GENERIC_EXIT_TIMEOUT
Process timed out.
Definition: exitcodes.h:27
GrabberDownloadThread
Definition: netgrabbermanager.h:115
uint
unsigned int uint
Definition: freesurround.h:24
LOC
#define LOC
Definition: netgrabbermanager.cpp:19