00001
00002 #include <QString>
00003 #include <QFileInfo>
00004 #include <QtAlgorithms>
00005
00006
00007 #include <mythdb.h>
00008 #include <mythcontext.h>
00009 #include <mythdirs.h>
00010 #include <mythsystem.h>
00011 #include <remoteutil.h>
00012 #include <remotefile.h>
00013 #include <mythprogressdialog.h>
00014 #include <rssparse.h>
00015 #include <netutils.h>
00016 #include <mythrssmanager.h>
00017 #include <netgrabbermanager.h>
00018 #include <mythcoreutil.h>
00019 #include <metadata/videoutils.h>
00020
00021
00022 #include "treeeditor.h"
00023 #include "nettree.h"
00024 #include "rsseditor.h"
00025 #include "netcommon.h"
00026
00027 class ResultItem;
00028 class GrabberScript;
00029
00030 const QString NetTree::RSSNode = tr("RSS Feeds");
00031 const QString NetTree::SearchNode = tr("Searches");
00032 const QString NetTree::DownloadNode = tr("Downloaded Files");
00033
00034 namespace
00035 {
00036 MythGenericTree *GetNodePtrFromButton(MythUIButtonListItem *item)
00037 {
00038 if (item)
00039 return item->GetData().value<MythGenericTree *>();
00040
00041 return 0;
00042 }
00043 }
00044
00045 NetTree::NetTree(DialogType type, MythScreenStack *parent, const char *name)
00046 : MythScreenType(parent, name),
00047 m_siteMap(NULL), m_siteButtonList(NULL),
00048 m_noSites(NULL), m_thumbImage(NULL),
00049 m_downloadable(NULL), m_busyPopup(NULL),
00050 m_menuPopup(NULL), m_popupStack(),
00051 m_progressDialog(NULL), m_downloadFile(QString()),
00052 m_type(type)
00053 {
00054 m_imageDownload = new MetadataImageDownload(this);
00055 m_gdt = new GrabberDownloadThread(this);
00056 m_popupStack = GetMythMainWindow()->GetStack("popup stack");
00057 m_updateFreq = gCoreContext->GetNumSetting(
00058 "mythNetTree.updateFreq", 6);
00059 m_rssAutoUpdate = gCoreContext->GetNumSetting(
00060 "mythnetvision.rssBackgroundFetch", 0);
00061 m_treeAutoUpdate = gCoreContext->GetNumSetting(
00062 "mythnetvision.backgroundFetch", 0);
00063 gCoreContext->addListener(this);
00064 }
00065
00066 bool NetTree::Create()
00067 {
00068 QString windowName = "gallery";
00069
00070 switch (m_type)
00071 {
00072 case DLG_GALLERY:
00073 windowName = "gallery";
00074 break;
00075 case DLG_BROWSER:
00076 windowName = "browser";
00077 break;
00078 case DLG_TREE:
00079 windowName = "tree";
00080 break;
00081 case DLG_DEFAULT:
00082 default:
00083 break;
00084 }
00085
00086 if (!LoadWindowFromXML("netvision-ui.xml", windowName, this))
00087 return false;
00088
00089 bool err = false;
00090 if (m_type == DLG_TREE)
00091 UIUtilE::Assign(this, m_siteMap, "videos", &err);
00092 else
00093 UIUtilE::Assign(this, m_siteButtonList, "videos", &err);
00094
00095 UIUtilW::Assign(this, m_noSites, "nosites");
00096
00097 UIUtilW::Assign(this, m_thumbImage, "preview");
00098
00099 UIUtilW::Assign(this, m_downloadable, "downloadable");
00100
00101 m_siteGeneric = new MythGenericTree("site root", 0, false);
00102 m_currentNode = m_siteGeneric;
00103
00104 if (err)
00105 {
00106 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen '" + windowName + "'");
00107 return false;
00108 }
00109
00110 BuildFocusList();
00111
00112 LoadInBackground();
00113
00114 if (m_type == DLG_TREE)
00115 {
00116 SetFocusWidget(m_siteMap);
00117
00118 connect(m_siteMap, SIGNAL(itemClicked(MythUIButtonListItem *)),
00119 SLOT(streamWebVideo(void)));
00120 connect(m_siteMap, SIGNAL(itemSelected(MythUIButtonListItem *)),
00121 SLOT(slotItemChanged(void)));
00122 connect(m_siteMap, SIGNAL(nodeChanged(MythGenericTree *)),
00123 SLOT(slotItemChanged(void)));
00124 }
00125 else
00126 {
00127 SetFocusWidget(m_siteButtonList);
00128
00129 connect(m_siteButtonList, SIGNAL(itemClicked(MythUIButtonListItem *)),
00130 SLOT(handleSelect(MythUIButtonListItem *)));
00131 connect(m_siteButtonList, SIGNAL(itemSelected(MythUIButtonListItem *)),
00132 SLOT(slotItemChanged(void)));
00133 }
00134
00135 return true;
00136 }
00137
00138 void NetTree::Load()
00139 {
00140 m_grabberList = findAllDBTreeGrabbersByHost(VIDEO_FILE);
00141 m_rssList = findAllDBRSS();
00142
00143 fillTree();
00144 }
00145
00146 void NetTree::SetCurrentNode(MythGenericTree *node)
00147 {
00148 if (!node)
00149 return;
00150
00151 m_currentNode = node;
00152 }
00153
00154 void NetTree::Init()
00155 {
00156 loadData();
00157 }
00158
00159 NetTree::~NetTree()
00160 {
00161 qDeleteAll(m_grabberList);
00162 m_grabberList.clear();
00163
00164 if (m_siteGeneric)
00165 {
00166 delete m_siteGeneric;
00167 m_siteGeneric = NULL;
00168 }
00169
00170 cleanThumbnailCacheDir();
00171
00172 if (m_imageDownload)
00173 {
00174 delete m_imageDownload;
00175 m_imageDownload = NULL;
00176 }
00177
00178 if (m_gdt)
00179 {
00180 delete m_gdt;
00181 m_gdt = NULL;
00182 }
00183
00184 m_rssList.clear();
00185
00186 qDeleteAll(m_videos);
00187 m_videos.clear();
00188
00189 cleanCacheDir();
00190
00191 gCoreContext->removeListener(this);
00192 }
00193
00194 void NetTree::cleanCacheDir()
00195 {
00196 QString cache = QString("%1/thumbcache")
00197 .arg(GetConfDir());
00198 QDir cacheDir(cache);
00199 QStringList thumbs = cacheDir.entryList(QDir::Files);
00200
00201 for (QStringList::const_iterator i = thumbs.end() - 1;
00202 i != thumbs.begin() - 1; --i)
00203 {
00204 QString filename = QString("%1/%2").arg(cache).arg(*i);
00205 LOG(VB_GENERAL, LOG_DEBUG, QString("Deleting file %1").arg(filename));
00206 QFileInfo fi(filename);
00207 QDateTime lastmod = fi.lastModified();
00208 if (lastmod.addDays(7) < QDateTime::currentDateTime())
00209 QFile::remove(filename);
00210 }
00211 }
00212
00213 void NetTree::loadData(void)
00214 {
00215 if (m_type == DLG_TREE)
00216 m_siteMap->AssignTree(m_siteGeneric);
00217 else
00218 {
00219 m_siteButtonList->Reset();
00220
00221 if (!m_currentNode)
00222 SetCurrentNode(m_siteGeneric);
00223
00224 if (!m_currentNode)
00225 return;
00226
00227 MythGenericTree *selectedNode = m_currentNode->getSelectedChild();
00228
00229 typedef QList<MythGenericTree *> MGTreeChildList;
00230 MGTreeChildList *lchildren = m_currentNode->getAllChildren();
00231
00232 for (MGTreeChildList::const_iterator p = lchildren->begin();
00233 p != lchildren->end(); ++p)
00234 {
00235 if (*p != NULL)
00236 {
00237 MythUIButtonListItem *item =
00238 new MythUIButtonListItem(m_siteButtonList, QString(), 0,
00239 true, MythUIButtonListItem::NotChecked);
00240
00241 item->SetData(qVariantFromValue(*p));
00242
00243 UpdateItem(item);
00244
00245 if (*p == selectedNode)
00246 m_siteButtonList->SetItemCurrent(item);
00247 }
00248 }
00249
00250 slotItemChanged();
00251 }
00252
00253 if (m_siteGeneric->childCount() == 0 && m_noSites)
00254 m_noSites->SetVisible(true);
00255 else if (m_noSites)
00256 m_noSites->SetVisible(false);
00257
00258 if (m_siteGeneric->childCount() == 0)
00259 runTreeEditor();
00260 }
00261
00262 void NetTree::UpdateItem(MythUIButtonListItem *item)
00263 {
00264 if (!item)
00265 return;
00266
00267 MythGenericTree *node = GetNodePtrFromButton(item);
00268
00269 if (!node)
00270 return;
00271
00272 RSSSite *site = qVariantValue<RSSSite *>(node->GetData());
00273 ResultItem *video = qVariantValue<ResultItem *>(node->GetData());
00274
00275 int nodeInt = node->getInt();
00276
00277 if (nodeInt == kSubFolder)
00278 {
00279 item->SetText(QString("%1").arg(node->visibleChildCount()), "childcount");
00280 item->DisplayState("subfolder", "nodetype");
00281 item->SetText(node->getString(), "title");
00282 item->SetText(node->getString());
00283 item->SetImage(node->GetData().toString());
00284 }
00285 else if (nodeInt == kUpFolder)
00286 {
00287 item->DisplayState("upfolder", "nodetype");
00288 item->SetText(node->getString(), "title");
00289 item->SetText(node->getString());
00290 }
00291
00292 if (site)
00293 {
00294 item->SetText(site->GetTitle());
00295 item->SetText(site->GetDescription(), "description");
00296 item->SetText(site->GetURL(), "url");
00297 item->SetImage(site->GetImage());
00298 }
00299 else if (video)
00300 {
00301 item->SetText(video->GetTitle());
00302
00303 MetadataMap metadataMap;
00304 video->toMap(metadataMap);
00305 item->SetTextFromMap(metadataMap);
00306
00307 int pos;
00308 if (m_type == DLG_TREE)
00309 pos = 0;
00310 else
00311 pos = m_siteButtonList->GetItemPos(item);
00312
00313 QString dlfile = video->GetThumbnail();
00314 if (dlfile.contains("%SHAREDIR%"))
00315 dlfile.replace("%SHAREDIR%", GetShareDir());
00316 else
00317 dlfile = getDownloadFilename(video->GetTitle(),
00318 video->GetThumbnail());
00319
00320 if (QFile::exists(dlfile))
00321 item->SetImage(dlfile);
00322 else if (video->GetThumbnail().startsWith("http"))
00323 m_imageDownload->addThumb(video->GetTitle(), video->GetThumbnail(),
00324 qVariantFromValue<uint>(pos));
00325 }
00326 else
00327 {
00328 item->SetText(node->getString());
00329 if (!node->GetData().toString().isEmpty())
00330 {
00331 QString tpath = node->GetData().toString();
00332 if (tpath.startsWith("http://"))
00333 {
00334 uint pos;
00335 if (m_type == DLG_TREE)
00336 pos = 0;
00337 else
00338 pos = m_siteButtonList->GetItemPos(item);
00339
00340 QString dlfile = GetThumbnailFilename(tpath,
00341 node->getString());
00342 if (QFile::exists(dlfile))
00343 item->SetImage(dlfile);
00344 else
00345 m_imageDownload->addThumb(node->getString(), tpath,
00346 qVariantFromValue<uint>(pos));
00347 }
00348 else if (tpath != "0")
00349 {
00350 QString filename = node->GetData().toString();
00351 if (filename.contains("%SHAREDIR%"))
00352 filename.replace("%SHAREDIR%", GetShareDir());
00353 item->SetImage(filename);
00354 }
00355 }
00356 }
00357 }
00358
00359 void NetTree::handleSelect(MythUIButtonListItem *item)
00360 {
00361 MythGenericTree *node = GetNodePtrFromButton(item);
00362 int nodeInt = node->getInt();
00363
00364 switch (nodeInt)
00365 {
00366 case kSubFolder:
00367 handleDirSelect(node);
00368 break;
00369 case kUpFolder:
00370 goBack();
00371 break;
00372 default:
00373 {
00374 streamWebVideo();
00375 }
00376 };
00377 slotItemChanged();
00378 }
00379
00380 void NetTree::handleDirSelect(MythGenericTree *node)
00381 {
00382 if (m_imageDownload && m_imageDownload->isRunning())
00383 m_imageDownload->cancel();
00384
00385 SetCurrentNode(node);
00386 loadData();
00387 }
00388
00389 bool NetTree::goBack()
00390 {
00391 bool handled = false;
00392
00393 if (m_imageDownload && m_imageDownload->isRunning())
00394 m_imageDownload->cancel();
00395
00396 if (m_currentNode != m_siteGeneric)
00397 {
00398 MythGenericTree *lparent = m_currentNode->getParent();
00399 if (lparent)
00400 {
00401 SetCurrentNode(lparent);
00402 handled = true;
00403 }
00404 }
00405
00406 loadData();
00407
00408 return handled;
00409 }
00410
00411 bool NetTree::keyPressEvent(QKeyEvent *event)
00412 {
00413 if (GetFocusWidget()->keyPressEvent(event))
00414 return true;
00415
00416 bool handled = false;
00417 QStringList actions;
00418 handled = GetMythMainWindow()->TranslateKeyPress("Internet Video", event, actions);
00419
00420 for (int i = 0; i < actions.size() && !handled; i++)
00421 {
00422 QString action = actions[i];
00423 handled = true;
00424
00425 if (action == "MENU")
00426 {
00427 showMenu();
00428 }
00429 else if (action == "ESCAPE")
00430 {
00431 if (m_type != DLG_TREE
00432 && !GetMythMainWindow()->IsExitingToMain()
00433 && m_currentNode != m_siteGeneric)
00434 handled = goBack();
00435 else
00436 handled = false;
00437 }
00438 else
00439 handled = false;
00440 }
00441
00442 if (!handled && MythScreenType::keyPressEvent(event))
00443 handled = true;
00444
00445 return handled;
00446 }
00447
00448 void NetTree::createBusyDialog(QString title)
00449 {
00450 if (m_busyPopup)
00451 return;
00452
00453 QString message = title;
00454
00455 m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
00456 "nettreebusydialog");
00457
00458 if (m_busyPopup->Create())
00459 m_popupStack->AddScreen(m_busyPopup);
00460 else
00461 {
00462 delete m_busyPopup;
00463 m_busyPopup = NULL;
00464 }
00465 }
00466
00467 void NetTree::showMenu(void)
00468 {
00469 QString label = tr("Playback/Download Options");
00470
00471 MythMenu *menu = new MythMenu(label, this, "options");
00472
00473 ResultItem *item = NULL;
00474 if (m_type == DLG_TREE)
00475 {
00476 MythGenericTree *node = m_siteMap->GetCurrentNode();
00477
00478 if (node)
00479 item = qVariantValue<ResultItem *>(node->GetData());
00480 }
00481 else
00482 {
00483 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
00484
00485 if (node)
00486 item = qVariantValue<ResultItem *>(node->GetData());
00487 }
00488
00489 if (item)
00490 {
00491 if (item->GetDownloadable())
00492 menu->AddItem(tr("Stream Video"), SLOT(streamWebVideo()));
00493 menu->AddItem(tr("Open Web Link"), SLOT(showWebVideo()));
00494
00495 if (item->GetDownloadable())
00496 menu->AddItem(tr("Save This Video"), SLOT(doDownloadAndPlay()));
00497 }
00498
00499 menu->AddItem(tr("Scan/Manage Subscriptions"), NULL, createShowManageMenu());
00500 menu->AddItem(tr("Change View"), NULL, createShowViewMenu());
00501
00502 MythDialogBox *menuPopup = new MythDialogBox(menu, m_popupStack, "mythnettreemenupopup");
00503
00504 if (menuPopup->Create())
00505 m_popupStack->AddScreen(menuPopup);
00506 else
00507 delete menuPopup;
00508 }
00509
00510 MythMenu* NetTree::createShowViewMenu()
00511 {
00512 QString label = tr("View Options");
00513
00514 MythMenu *menu = new MythMenu(label, this, "options");
00515
00516 if (m_type != DLG_TREE)
00517 menu->AddItem(tr("Switch to List View"), SLOT(switchTreeView()));
00518 if (m_type != DLG_GALLERY)
00519 menu->AddItem(tr("Switch to Gallery View"), SLOT(switchGalleryView()));
00520 if (m_type != DLG_BROWSER)
00521 menu->AddItem(tr("Switch to Browse View"), SLOT(switchBrowseView()));
00522
00523 return menu;
00524 }
00525
00526 MythMenu* NetTree::createShowManageMenu()
00527 {
00528 QString label = tr("Subscription Management");
00529
00530 MythMenu *menu = new MythMenu(label, this, "options");
00531
00532
00533 menu->AddItem(tr("Update Site Maps"), SLOT(updateTrees()));
00534 menu->AddItem(tr("Update RSS"), SLOT(updateRSS()));
00535 menu->AddItem(tr("Manage Site Subscriptions"), SLOT(runTreeEditor()));
00536 menu->AddItem(tr("Manage RSS Subscriptions"), SLOT(runRSSEditor()));
00537 if (!m_treeAutoUpdate)
00538 menu->AddItem(tr("Enable Automatic Site Updates"), SLOT(toggleTreeUpdates()));
00539 else
00540 menu->AddItem(tr("Disable Automatic Site Updates"), SLOT(toggleTreeUpdates()));
00541
00542
00543
00544
00545
00546 return menu;
00547 }
00548
00549 void NetTree::switchTreeView()
00550 {
00551 m_type = DLG_TREE;
00552 switchView();
00553 }
00554
00555 void NetTree::switchGalleryView()
00556 {
00557 m_type = DLG_GALLERY;
00558 switchView();
00559 }
00560
00561 void NetTree::switchBrowseView()
00562 {
00563 m_type = DLG_BROWSER;
00564 switchView();
00565 }
00566
00567 void NetTree::switchView()
00568 {
00569 NetTree *nettree =
00570 new NetTree(m_type, GetMythMainWindow()->GetMainStack(), "nettree");
00571
00572 if (nettree->Create())
00573 {
00574 gCoreContext->SaveSetting("mythnetvision.ViewMode", m_type);
00575 MythScreenStack *screenStack = GetScreenStack();
00576 screenStack->AddScreen(nettree);
00577 screenStack->PopScreen(this, false, false);
00578 deleteLater();
00579 }
00580 else
00581 delete nettree;
00582 }
00583
00584 void NetTree::fillTree()
00585 {
00586
00587
00588 m_rssGeneric = new MythGenericTree(
00589 RSSNode, kSubFolder, false);
00590
00591
00592 if (m_type != DLG_TREE)
00593 {
00594 m_rssGeneric->addNode(QString(tr("Back")), kUpFolder, true, false);
00595 }
00596
00597 m_rssGeneric->SetData(QString("%1/mythnetvision/icons/rss.png")
00598 .arg(GetShareDir()));
00599
00600 RSSSite::rssList::iterator i = m_rssList.begin();
00601 for (; i != m_rssList.end(); ++i)
00602 {
00603 ResultItem::resultList items =
00604 getRSSArticles((*i)->GetTitle(), VIDEO_PODCAST);
00605 MythGenericTree *ret = new MythGenericTree(
00606 (*i)->GetTitle(), kSubFolder, false);
00607 ret->SetData(qVariantFromValue(*i));
00608 m_rssGeneric->addNode(ret);
00609
00610
00611 if (m_type != DLG_TREE)
00612 {
00613 ret->addNode(QString(tr("Back")), kUpFolder, true, false);
00614 }
00615
00616 ResultItem::resultList::iterator it = items.begin();
00617 for (; it != items.end(); ++it)
00618 {
00619 AddFileNode(ret, *it);
00620 }
00621 }
00622
00623 if (m_rssList.count() > 0)
00624 m_siteGeneric->addNode(m_rssGeneric);
00625 else
00626 {
00627 delete m_rssGeneric;
00628 m_rssGeneric = NULL;
00629 }
00630
00631
00632
00633 for (GrabberScript::scriptList::iterator i = m_grabberList.begin();
00634 i != m_grabberList.end(); ++i)
00635 {
00636
00637 QMultiMap<QPair<QString,QString>, ResultItem*> treePathsNodes =
00638 getTreeArticles((*i)->GetTitle(), VIDEO_FILE);
00639
00640 QList< QPair<QString,QString> > paths = treePathsNodes.uniqueKeys();
00641
00642 MythGenericTree *ret = new MythGenericTree(
00643 (*i)->GetTitle(), kSubFolder, false);
00644 QString thumb = QString("%1mythnetvision/icons/%2").arg(GetShareDir())
00645 .arg((*i)->GetImage());
00646 ret->SetData(qVariantFromValue(thumb));
00647
00648
00649 if (m_type != DLG_TREE)
00650 {
00651 ret->addNode(QString(tr("Back")), kUpFolder, true, false);
00652 }
00653
00654 for (QList<QPair<QString, QString> >::iterator i = paths.begin();
00655 i != paths.end(); ++i)
00656 {
00657 QStringList curPaths = (*i).first.split("/");
00658 QString dirthumb = (*i).second;
00659 QList<ResultItem*> videos = treePathsNodes.values(*i);
00660 buildGenericTree(ret, curPaths, dirthumb, videos);
00661 }
00662 m_siteGeneric->addNode(ret);
00663 }
00664 }
00665
00666 void NetTree::buildGenericTree(MythGenericTree *dst, QStringList paths,
00667 QString dirthumb, QList<ResultItem*> videos)
00668 {
00669 MythGenericTree *folder = NULL;
00670
00671
00672
00673
00674 while (folder == NULL && paths.size())
00675 {
00676 QString curPath = paths.takeFirst();
00677 curPath.replace("|", "/");
00678 MythGenericTree *tmp = dst->getChildByName(curPath);
00679 if (tmp)
00680 dst = tmp;
00681 else
00682 folder = new MythGenericTree(
00683 curPath, kSubFolder, false);
00684 }
00685
00686 if (!folder)
00687 return;
00688
00689 folder->SetData(dirthumb);
00690 dst->addNode(folder);
00691
00692
00693 if (m_type != DLG_TREE)
00694 {
00695 folder->addNode(QString(tr("Back")), kUpFolder, true, false);
00696 }
00697
00698 if (paths.size())
00699 buildGenericTree(folder, paths, dirthumb, videos);
00700 else
00701 {
00702
00703 for (QList<ResultItem*>::iterator it = videos.begin();
00704 it != videos.end(); ++it)
00705 AddFileNode(folder, *it);
00706 }
00707 }
00708
00709 MythGenericTree *NetTree::AddDirNode(MythGenericTree *where_to_add,
00710 QString name, QString thumbnail)
00711 {
00712 QString title = name;
00713 title.replace("&", "&");
00714 MythGenericTree *sub_node =
00715 where_to_add->addNode(title, kSubFolder, false);
00716 sub_node->SetData(thumbnail);
00717 return sub_node;
00718 }
00719
00720 int NetTree::AddFileNode(MythGenericTree *where_to_add, ResultItem *video)
00721 {
00722 QString title = video->GetTitle();
00723 title.replace("&", "&");
00724 MythGenericTree *sub_node = where_to_add->
00725 addNode(title, 0, true);
00726 sub_node->SetData(qVariantFromValue(video));
00727 m_videos.append(video);
00728 return 1;
00729 }
00730
00731 void NetTree::streamWebVideo()
00732 {
00733 ResultItem *item;
00734
00735 if (m_type == DLG_TREE)
00736 item = qVariantValue<ResultItem *>(m_siteMap->GetCurrentNode()->GetData());
00737 else
00738 {
00739 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
00740
00741 if (!node)
00742 return;
00743
00744 item = qVariantValue<ResultItem *>(node->GetData());
00745 }
00746
00747 if (!item)
00748 return;
00749
00750 if (!item->GetDownloadable())
00751 {
00752 showWebVideo();
00753 return;
00754 }
00755
00756 GetMythMainWindow()->HandleMedia("Internal", item->GetMediaURL(),
00757 item->GetDescription(), item->GetTitle(), item->GetSubtitle(), QString(),
00758 item->GetSeason(), item->GetEpisode(), QString(), item->GetTime().toInt(),
00759 item->GetDate().toString("yyyy"));
00760 }
00761
00762 void NetTree::showWebVideo()
00763 {
00764 ResultItem *item;
00765
00766 if (m_type == DLG_TREE)
00767 item = qVariantValue<ResultItem *>(m_siteMap->GetCurrentNode()->GetData());
00768 else
00769 {
00770 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
00771
00772 if (!node)
00773 return;
00774
00775 item = qVariantValue<ResultItem *>(node->GetData());
00776 }
00777
00778 if (!item)
00779 return;
00780
00781 if (!item->GetPlayer().isEmpty())
00782 {
00783 QString cmd = item->GetPlayer();
00784 QStringList args = item->GetPlayerArguments();
00785 if (!args.size())
00786 {
00787 args += item->GetMediaURL();
00788 if (!args.size())
00789 args += item->GetURL();
00790 }
00791 else
00792 {
00793 args.replaceInStrings("%DIR%", QString(GetConfDir() + "/MythNetvision"));
00794 args.replaceInStrings("%MEDIAURL%", item->GetMediaURL());
00795 args.replaceInStrings("%URL%", item->GetURL());
00796 args.replaceInStrings("%TITLE%", item->GetTitle());
00797 }
00798 QString playerCommand = cmd + " " + args.join(" ");
00799
00800 myth_system(playerCommand);
00801 }
00802 else
00803 {
00804 QString url = item->GetURL();
00805
00806 LOG(VB_GENERAL, LOG_DEBUG, QString("Web URL = %1").arg(url));
00807
00808 if (url.isEmpty())
00809 return;
00810
00811 QString browser = gCoreContext->GetSetting("WebBrowserCommand", "");
00812 QString zoom = gCoreContext->GetSetting("WebBrowserZoomLevel", "1.0");
00813
00814 if (browser.isEmpty())
00815 {
00816 ShowOkPopup(tr("No browser command set! MythNetTree needs MythBrowser "
00817 "installed to display the video."));
00818 return;
00819 }
00820
00821 if (browser.toLower() == "internal")
00822 {
00823 GetMythMainWindow()->HandleMedia("WebBrowser", url);
00824 return;
00825 }
00826 else
00827 {
00828 QString cmd = browser;
00829 cmd.replace("%ZOOM%", zoom);
00830 cmd.replace("%URL%", url);
00831 cmd.replace('\'', "%27");
00832 cmd.replace("&","\\&");
00833 cmd.replace(";","\\;");
00834
00835 GetMythMainWindow()->AllowInput(false);
00836 myth_system(cmd, kMSDontDisableDrawing);
00837 GetMythMainWindow()->AllowInput(true);
00838 return;
00839 }
00840 }
00841 }
00842
00843 void NetTree::doPlayVideo(QString filename)
00844 {
00845 ResultItem *item;
00846 if (m_type == DLG_TREE)
00847 item = qVariantValue<ResultItem *>(m_siteMap->GetCurrentNode()->GetData());
00848 else
00849 {
00850 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
00851
00852 if (!node)
00853 return;
00854
00855 item = qVariantValue<ResultItem *>(node->GetData());
00856 }
00857
00858 if (!item)
00859 return;
00860
00861 GetMythMainWindow()->HandleMedia("Internal", filename);
00862 }
00863
00864 void NetTree::slotDeleteVideo()
00865 {
00866 QString message = tr("Are you sure you want to delete this file?");
00867
00868 MythConfirmationDialog *confirmdialog =
00869 new MythConfirmationDialog(m_popupStack,message);
00870
00871 if (confirmdialog->Create())
00872 {
00873 m_popupStack->AddScreen(confirmdialog);
00874 connect(confirmdialog, SIGNAL(haveResult(bool)),
00875 SLOT(doDeleteVideo(bool)));
00876 }
00877 else
00878 delete confirmdialog;
00879 }
00880
00881 void NetTree::doDeleteVideo(bool remove)
00882 {
00883 if (!remove)
00884 return;
00885
00886 ResultItem *item;
00887 if (m_type == DLG_TREE)
00888 item = qVariantValue<ResultItem *>(m_siteMap->GetCurrentNode()->GetData());
00889 else
00890 {
00891 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
00892
00893 if (!node)
00894 return;
00895
00896 item = qVariantValue<ResultItem *>(node->GetData());
00897 }
00898
00899 if (!item)
00900 return;
00901
00902 QString filename = GetDownloadFilename(item->GetTitle(),
00903 item->GetMediaURL());
00904
00905 if (filename.startsWith("myth://"))
00906 RemoteFile::DeleteFile(filename);
00907 else
00908 {
00909 QFile file(filename);
00910 file.remove();
00911 }
00912 }
00913
00914 void NetTree::doDownloadAndPlay()
00915 {
00916 ResultItem *item;
00917 if (m_type == DLG_TREE)
00918 item = qVariantValue<ResultItem *>(m_siteMap->GetCurrentNode()->GetData());
00919 else
00920 {
00921 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
00922
00923 if (!node)
00924 return;
00925
00926 item = qVariantValue<ResultItem *>(node->GetData());
00927 }
00928
00929 if (!item)
00930 return;
00931
00932 QString baseFilename = GetDownloadFilename(item->GetTitle(),
00933 item->GetMediaURL());
00934
00935 QString finalFilename = generate_file_url("Default",
00936 gCoreContext->GetMasterHostName(),
00937 baseFilename);
00938
00939 LOG(VB_GENERAL, LOG_INFO, QString("Downloading %1 to %2")
00940 .arg(item->GetMediaURL()) .arg(finalFilename));
00941
00942
00943 bool exists = RemoteFile::Exists(finalFilename);
00944
00945 if (exists)
00946 {
00947 doPlayVideo(finalFilename);
00948 return;
00949 }
00950 else
00951 DownloadVideo(item->GetMediaURL(), baseFilename);
00952 }
00953
00954 void NetTree::DownloadVideo(QString url, QString dest)
00955 {
00956 initProgressDialog();
00957 m_downloadFile = RemoteDownloadFile(url, "Default", dest);
00958 }
00959
00960 void NetTree::initProgressDialog()
00961 {
00962 QString message = tr("Downloading Video...");
00963 m_progressDialog = new MythUIProgressDialog(message,
00964 m_popupStack, "videodownloadprogressdialog");
00965
00966 if (m_progressDialog->Create())
00967 {
00968 m_popupStack->AddScreen(m_progressDialog, false);
00969 }
00970 else
00971 {
00972 delete m_progressDialog;
00973 m_progressDialog = NULL;
00974 }
00975 }
00976
00977 void NetTree::slotItemChanged()
00978 {
00979 ResultItem *item;
00980 RSSSite *site;
00981
00982 if (m_type == DLG_TREE)
00983 {
00984 item = qVariantValue<ResultItem *>(m_siteMap->GetCurrentNode()->GetData());
00985 site = qVariantValue<RSSSite *>(m_siteMap->GetCurrentNode()->GetData());
00986 }
00987 else
00988 {
00989 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
00990
00991 if (!node)
00992 return;
00993
00994 item = qVariantValue<ResultItem *>(node->GetData());
00995 site = qVariantValue<RSSSite *>(node->GetData());
00996 }
00997
00998 if (item)
00999 {
01000 MetadataMap metadataMap;
01001 item->toMap(metadataMap);
01002 SetTextFromMap(metadataMap);
01003
01004 if (!item->GetThumbnail().isEmpty() && m_thumbImage)
01005 {
01006 m_thumbImage->Reset();
01007 QString dlfile = item->GetThumbnail();
01008 if (dlfile.contains("%SHAREDIR%"))
01009 {
01010 dlfile.replace("%SHAREDIR%", GetShareDir());
01011 m_thumbImage->SetFilename(dlfile);
01012 m_thumbImage->Load();
01013 }
01014 else
01015 {
01016 QString sFilename = getDownloadFilename(item->GetTitle(), item->GetThumbnail());
01017
01018 bool exists = QFile::exists(sFilename);
01019 if (exists)
01020 {
01021 m_thumbImage->SetFilename(sFilename);
01022 m_thumbImage->Load();
01023 }
01024 }
01025 }
01026 else if (m_thumbImage)
01027 m_thumbImage->Reset();
01028
01029 if (m_downloadable)
01030 {
01031 if (item->GetDownloadable())
01032 m_downloadable->DisplayState("yes");
01033 else
01034 m_downloadable->DisplayState("no");
01035 }
01036 }
01037 else if (site)
01038 {
01039 ResultItem *res = new ResultItem(site->GetTitle(), QString(), site->GetDescription(),
01040 site->GetURL(), site->GetImage(), QString(), site->GetAuthor(), QDateTime(),
01041 0, 0, -1, QString(), QStringList(), QString(), QStringList(), 0, 0, QString(),
01042 0, QStringList(), 0, 0, 0);
01043
01044 MetadataMap metadataMap;
01045 res->toMap(metadataMap);
01046 SetTextFromMap(metadataMap);
01047
01048 if (!site->GetImage().isEmpty() && m_thumbImage)
01049 {
01050 m_thumbImage->SetFilename(site->GetImage());
01051 m_thumbImage->Load();
01052 }
01053 else if (m_thumbImage)
01054 m_thumbImage->Reset();
01055
01056 if (m_downloadable)
01057 {
01058 m_downloadable->Reset();
01059 }
01060 }
01061 else
01062 {
01063 QString title;
01064
01065 if (m_type == DLG_TREE)
01066 title = m_siteMap->GetItemCurrent()->GetText();
01067 else
01068 title = m_siteButtonList->GetItemCurrent()->GetText();
01069
01070 QString thumb;
01071 if (m_type == DLG_TREE)
01072 thumb = m_siteMap->GetCurrentNode()->
01073 GetData().toString();
01074 else
01075 {
01076 MythGenericTree *node = GetNodePtrFromButton(m_siteButtonList->GetItemCurrent());
01077
01078 if (node)
01079 thumb = node->GetData().toString();
01080 }
01081
01082 ResultItem *res = new ResultItem(title, QString(), QString(),
01083 QString(), thumb, QString(), QString(), QDateTime(),
01084 0, 0, -1, QString(), QStringList(), QString(), QStringList(), 0, 0, QString(),
01085 0, QStringList(), 0, 0, 0);
01086
01087 MetadataMap metadataMap;
01088 res->toMap(metadataMap);
01089 SetTextFromMap(metadataMap);
01090
01091 if (m_thumbImage)
01092 {
01093 if (!thumb.startsWith("http://"))
01094 {
01095 if (thumb.contains("%SHAREDIR%"))
01096 thumb.replace("%SHAREDIR%", GetShareDir());
01097
01098 bool exists = QFile::exists(thumb);
01099
01100 if (exists)
01101 {
01102 m_thumbImage->SetFilename(thumb);
01103 m_thumbImage->Load();
01104 }
01105 else
01106 m_thumbImage->Reset();
01107 }
01108 else
01109 {
01110
01111 QString url = thumb;
01112 QString title;
01113 if (m_type == DLG_TREE)
01114 title = m_siteMap->GetItemCurrent()->GetText();
01115 else
01116 title = m_siteButtonList->GetItemCurrent()->GetText();
01117
01118 QString sFilename = GetDownloadFilename(title, url);
01119
01120 bool exists = QFile::exists(sFilename);
01121 if (exists && !url.isEmpty())
01122 {
01123 m_thumbImage->SetFilename(sFilename);
01124 m_thumbImage->Load();
01125 }
01126 else
01127 m_thumbImage->Reset();
01128 }
01129 }
01130
01131 if (m_downloadable)
01132 m_downloadable->Reset();
01133 }
01134 }
01135
01136 void NetTree::runTreeEditor()
01137 {
01138 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
01139
01140 TreeEditor *treeedit = new TreeEditor(mainStack, "mythnettreeedit");
01141
01142 if (treeedit->Create())
01143 {
01144 connect(treeedit, SIGNAL(itemsChanged()), this,
01145 SLOT(doTreeRefresh()));
01146
01147 mainStack->AddScreen(treeedit);
01148 }
01149 else
01150 {
01151 delete treeedit;
01152 }
01153 }
01154
01155 void NetTree::runRSSEditor()
01156 {
01157 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
01158
01159 RSSEditor *rssedit = new RSSEditor(mainStack, "mythnetrssedit");
01160
01161 if (rssedit->Create())
01162 {
01163 connect(rssedit, SIGNAL(itemsChanged()), this,
01164 SLOT(updateRSS()));
01165
01166 mainStack->AddScreen(rssedit);
01167 }
01168 else
01169 {
01170 delete rssedit;
01171 }
01172 }
01173
01174 void NetTree::doTreeRefresh()
01175 {
01176 if (m_busyPopup)
01177 {
01178 m_busyPopup->Close();
01179 m_busyPopup = NULL;
01180 }
01181
01182 TreeRefresh();
01183 }
01184
01185 void NetTree::TreeRefresh()
01186 {
01187 m_siteGeneric = new MythGenericTree("site root", 0, false);
01188 m_currentNode = m_siteGeneric;
01189
01190 m_grabberList = findAllDBTreeGrabbers();
01191 m_rssList = findAllDBRSS();
01192
01193 fillTree();
01194 loadData();
01195 switchView();
01196 }
01197
01198 void NetTree::updateRSS()
01199 {
01200 if (!findAllDBRSS().count())
01201 return;
01202
01203 QString title(tr("Updating RSS. This could take a while..."));
01204 createBusyDialog(title);
01205
01206 RSSManager *rssMan = new RSSManager();
01207 connect(rssMan, SIGNAL(finished()), this,
01208 SLOT(doTreeRefresh()));
01209 rssMan->startTimer();
01210 rssMan->doUpdate();
01211 }
01212
01213 void NetTree::updateTrees()
01214 {
01215 if (m_grabberList.count() == 0)
01216 return;
01217
01218 QString title(tr("Updating Site Maps. This could take a while..."));
01219 createBusyDialog(title);
01220 m_gdt->refreshAll();
01221 }
01222
01223 void NetTree::toggleRSSUpdates()
01224 {
01225 m_rssAutoUpdate = !m_rssAutoUpdate;
01226 gCoreContext->SaveSetting("mythnetvision.rssBackgroundFetch",
01227 m_rssAutoUpdate);
01228 }
01229
01230 void NetTree::toggleTreeUpdates()
01231 {
01232 m_treeAutoUpdate = !m_treeAutoUpdate;
01233 gCoreContext->SaveSetting("mythnetvision.backgroundFetch",
01234 m_treeAutoUpdate);
01235 }
01236
01237 void NetTree::customEvent(QEvent *event)
01238 {
01239 if (event->type() == ThumbnailDLEvent::kEventType)
01240 {
01241 ThumbnailDLEvent *tde = (ThumbnailDLEvent *)event;
01242
01243 if (!tde)
01244 return;
01245
01246 ThumbnailData *data = tde->thumb;
01247
01248 if (!data)
01249 return;
01250
01251 QString title = data->title;
01252 QString file = data->url;
01253 uint pos = qVariantValue<uint>(data->data);
01254
01255 if (file.isEmpty())
01256 return;
01257
01258 if (m_type == DLG_TREE)
01259 {
01260 if (title == m_siteMap->GetCurrentNode()->getString() &&
01261 m_thumbImage)
01262 {
01263 m_thumbImage->SetFilename(file);
01264 m_thumbImage->Load();
01265 m_thumbImage->Show();
01266 }
01267 }
01268 else
01269 {
01270 if (!((uint)m_siteButtonList->GetCount() >= pos))
01271 {
01272 delete data;
01273 return;
01274 }
01275
01276 MythUIButtonListItem *item =
01277 m_siteButtonList->GetItemAt(pos);
01278
01279 if (item && item->GetText() == title)
01280 {
01281 item->SetImage(file);
01282 }
01283 }
01284
01285 delete data;
01286 }
01287 else if (event->type() == kGrabberUpdateEventType)
01288 {
01289 doTreeRefresh();
01290 }
01291 else if ((MythEvent::Type)(event->type()) == MythEvent::MythEventMessage)
01292 {
01293 MythEvent *me = (MythEvent *)event;
01294 QStringList tokens = me->Message().split(" ", QString::SkipEmptyParts);
01295
01296 if (tokens.isEmpty())
01297 return;
01298
01299 if (tokens[0] == "DOWNLOAD_FILE")
01300 {
01301 QStringList args = me->ExtraDataList();
01302 if ((tokens.size() != 2) ||
01303 (args[1] != m_downloadFile))
01304 return;
01305
01306 if (tokens[1] == "UPDATE")
01307 {
01308 QString message = tr("Downloading Video...\n"
01309 "(%1 of %2 MB)")
01310 .arg(QString::number(args[2].toInt() / 1024.0 / 1024.0, 'f', 2))
01311 .arg(QString::number(args[3].toInt() / 1024.0 / 1024.0, 'f', 2));
01312 m_progressDialog->SetMessage(message);
01313 m_progressDialog->SetTotal(args[3].toInt());
01314 m_progressDialog->SetProgress(args[2].toInt());
01315 }
01316 else if (tokens[1] == "FINISHED")
01317 {
01318 int fileSize = args[2].toInt();
01319 int errorCode = args[4].toInt();
01320
01321 if (m_progressDialog)
01322 m_progressDialog->Close();
01323
01324 QFileInfo file(m_downloadFile);
01325 if ((m_downloadFile.startsWith("myth://")))
01326 {
01327 if ((errorCode == 0) &&
01328 (fileSize > 0))
01329 {
01330 doPlayVideo(m_downloadFile);
01331 }
01332 else
01333 {
01334 ShowOkPopup(tr("Error downloading video to backend."));
01335 }
01336 }
01337 }
01338 }
01339 }
01340
01341 }