00001 #include <set>
00002 #include <map>
00003
00004 #include <QApplication>
00005 #include <QTimer>
00006 #include <QList>
00007 #include <QFile>
00008 #include <QFileInfo>
00009 #include <QDir>
00010 #include <QUrl>
00011
00012 #include "mythcontext.h"
00013 #include "compat.h"
00014 #include "mythdirs.h"
00015
00016 #include "mythuihelper.h"
00017 #include "mythprogressdialog.h"
00018 #include "mythuitext.h"
00019 #include "mythuibutton.h"
00020 #include "mythuibuttonlist.h"
00021 #include "mythuibuttontree.h"
00022 #include "mythuiimage.h"
00023 #include "mythuistatetype.h"
00024 #include "mythuimetadataresults.h"
00025 #include "mythdialogbox.h"
00026 #include "mythgenerictree.h"
00027 #include "mythsystem.h"
00028 #include "remotefile.h"
00029 #include "remoteutil.h"
00030 #include "storagegroup.h"
00031
00032 #include "videoscan.h"
00033 #include "globals.h"
00034 #include "videometadatalistmanager.h"
00035 #include "parentalcontrols.h"
00036 #include "videoutils.h"
00037 #include "dbaccess.h"
00038 #include "dirscan.h"
00039 #include "metadatafactory.h"
00040 #include "videofilter.h"
00041 #include "editvideometadata.h"
00042 #include "videopopups.h"
00043 #include "videolist.h"
00044 #include "videoplayercommand.h"
00045 #include "videodlg.h"
00046 #include "videofileassoc.h"
00047 #include "videoplayersettings.h"
00048 #include "videometadatasettings.h"
00049
00050 namespace
00051 {
00052 bool IsValidDialogType(int num)
00053 {
00054 for (int i = 1; i <= VideoDialog::dtLast - 1; i <<= 1)
00055 if (num == i) return true;
00056 return false;
00057 }
00058
00059 class ParentalLevelNotifyContainer : public QObject
00060 {
00061 Q_OBJECT
00062
00063 signals:
00064 void SigLevelChanged();
00065
00066 public:
00067 ParentalLevelNotifyContainer(QObject *lparent = 0) :
00068 QObject(lparent), m_level(ParentalLevel::plNone)
00069 {
00070 connect(&m_levelCheck,
00071 SIGNAL(SigResultReady(bool, ParentalLevel::Level)),
00072 SLOT(OnResultReady(bool, ParentalLevel::Level)));
00073 }
00074
00075 const ParentalLevel &GetLevel() const { return m_level; }
00076
00077 void SetLevel(ParentalLevel level)
00078 {
00079 m_levelCheck.Check(m_level.GetLevel(), level.GetLevel());
00080 }
00081
00082 private slots:
00083 void OnResultReady(bool passwordValid, ParentalLevel::Level newLevel)
00084 {
00085 ParentalLevel lastLevel = m_level;
00086 if (passwordValid)
00087 {
00088 m_level = newLevel;
00089 }
00090
00091 if (m_level.GetLevel() == ParentalLevel::plNone)
00092 {
00093 m_level = ParentalLevel(ParentalLevel::plLowest);
00094 }
00095
00096 if (lastLevel != m_level)
00097 {
00098 emit SigLevelChanged();
00099 }
00100 }
00101
00102 private:
00103 ParentalLevel m_level;
00104 ParentalLevelChangeChecker m_levelCheck;
00105 };
00106
00107 MythGenericTree *GetNodePtrFromButton(MythUIButtonListItem *item)
00108 {
00109 if (item)
00110 return item->GetData().value<MythGenericTree *>();
00111
00112 return NULL;
00113 }
00114
00115 VideoMetadata *GetMetadataPtrFromNode(MythGenericTree *node)
00116 {
00117 if (node)
00118 return node->GetData().value<TreeNodeData>().GetMetadata();
00119
00120 return NULL;
00121 }
00122
00123 bool GetLocalVideoImage(const QString &video_uid, const QString &filename,
00124 const QStringList &in_dirs, QString &image,
00125 QString title, int season,
00126 const QString host, QString sgroup,
00127 int episode = 0, bool isScreenshot = false)
00128 {
00129 QStringList search_dirs(in_dirs);
00130 QFileInfo qfi(filename);
00131 search_dirs += qfi.absolutePath();
00132 if (title.contains("/"))
00133 title.replace("/", "-");
00134
00135 const QString base_name = qfi.completeBaseName();
00136 QList<QByteArray> image_types = QImageReader::supportedImageFormats();
00137
00138 typedef std::set<QString> image_type_list;
00139 image_type_list image_exts;
00140
00141 QString suffix;
00142
00143 if (sgroup == "Coverart")
00144 suffix = "coverart";
00145 if (sgroup == "Fanart")
00146 suffix = "fanart";
00147 if (sgroup == "Screenshots")
00148 suffix = "screenshot";
00149 if (sgroup == "Banners")
00150 suffix = "banner";
00151
00152 for (QList<QByteArray>::const_iterator it = image_types.begin();
00153 it != image_types.end(); ++it)
00154 {
00155 image_exts.insert(QString(*it).toLower());
00156 }
00157
00158 if (!host.isEmpty())
00159 {
00160 QStringList hostFiles;
00161
00162 RemoteGetFileList(host, "", &hostFiles, sgroup, true);
00163 const QString hntm("%2.%3");
00164
00165 for (image_type_list::const_iterator ext = image_exts.begin();
00166 ext != image_exts.end(); ++ext)
00167 {
00168 QStringList sfn;
00169 if (episode > 0 || season > 0)
00170 {
00171 if (isScreenshot)
00172 sfn += hntm.arg(QString("%1 Season %2x%3_%4")
00173 .arg(title).arg(QString::number(season))
00174 .arg(QString::number(episode))
00175 .arg(suffix))
00176 .arg(*ext);
00177 else
00178 sfn += hntm.arg(QString("%1 Season %2_%3")
00179 .arg(title).arg(QString::number(season))
00180 .arg(suffix))
00181 .arg(*ext);
00182
00183 }
00184 else
00185 {
00186 sfn += hntm.arg(base_name + "_%1").arg(suffix).arg(*ext);
00187 sfn += hntm.arg(video_uid + "_%1").arg(suffix).arg(*ext);
00188 }
00189
00190 for (QStringList::const_iterator i = sfn.begin();
00191 i != sfn.end(); ++i)
00192 {
00193 if (hostFiles.contains(*i))
00194 {
00195 image = *i;
00196 return true;
00197 }
00198 }
00199 }
00200 }
00201
00202 const QString fntm("%1/%2.%3");
00203
00204 for (QStringList::const_iterator dir = search_dirs.begin();
00205 dir != search_dirs.end(); ++dir)
00206 {
00207 if (!(*dir).length()) continue;
00208
00209 for (image_type_list::const_iterator ext = image_exts.begin();
00210 ext != image_exts.end(); ++ext)
00211 {
00212 QStringList sfn;
00213 if (season > 0 || episode > 0)
00214 {
00215 if (isScreenshot)
00216 sfn += fntm.arg(*dir).arg(QString("%1 Season %2x%3_%4")
00217 .arg(title).arg(QString::number(season))
00218 .arg(QString::number(episode))
00219 .arg(suffix))
00220 .arg(*ext);
00221 else if (!isScreenshot)
00222 sfn += fntm.arg(*dir).arg(QString("%1 Season %2_%3")
00223 .arg(title).arg(QString::number(season))
00224 .arg(suffix))
00225 .arg(*ext);
00226
00227 }
00228 if (!isScreenshot)
00229 {
00230 sfn += fntm.arg(*dir).arg(QString(base_name + "_%1")
00231 .arg(suffix)).arg(*ext);
00232 sfn += fntm.arg(*dir).arg(QString(video_uid + "_%1")
00233 .arg(suffix)).arg(*ext);
00234 }
00235
00236 for (QStringList::const_iterator i = sfn.begin();
00237 i != sfn.end(); ++i)
00238 {
00239 if (QFile::exists(*i))
00240 {
00241 image = *i;
00242 return true;
00243 }
00244 }
00245 }
00246 }
00247
00248 return false;
00249 }
00250
00251 void PlayVideo(const QString &filename,
00252 const VideoMetadataListManager &video_list, bool useAltPlayer = false)
00253 {
00254 const int WATCHED_WATERMARK = 10000;
00255
00256
00257
00258 VideoMetadataListManager::VideoMetadataPtr item = video_list.byFilename(filename);
00259
00260 if (!item) return;
00261
00262 QTime playing_time;
00263
00264 do
00265 {
00266 playing_time.start();
00267
00268 if (useAltPlayer)
00269 VideoPlayerCommand::AltPlayerFor(item.get()).Play();
00270 else
00271 VideoPlayerCommand::PlayerFor(item.get()).Play();
00272
00273 if (item->GetChildID() > 0 && video_list.byID(item->GetChildID()))
00274 item = video_list.byID(item->GetChildID());
00275 else
00276 break;
00277 }
00278 while (item && playing_time.elapsed() > WATCHED_WATERMARK);
00279 }
00280
00281 class FanartLoader: public QObject
00282 {
00283 Q_OBJECT
00284
00285 public:
00286 FanartLoader() : itemsPast(0)
00287 {
00288 connect(&m_fanartTimer, SIGNAL(timeout()), SLOT(fanartLoad()));
00289 }
00290
00291 ~FanartLoader()
00292 {
00293 m_fanartTimer.stop();
00294 m_fanartTimer.disconnect(this);
00295 }
00296
00297 void LoadImage(const QString &filename, MythUIImage *image)
00298 {
00299 bool wasActive = m_fanartTimer.isActive();
00300 if (filename.isEmpty())
00301 {
00302 if (wasActive)
00303 m_fanartTimer.stop();
00304
00305 image->Reset();
00306 itemsPast++;
00307 }
00308 else
00309 {
00310 QMutexLocker locker(&m_fanartLock);
00311 m_fanart = image;
00312 if (filename != m_fanart->GetFilename())
00313 {
00314 if (wasActive)
00315 m_fanartTimer.stop();
00316
00317 if (itemsPast > 2)
00318 m_fanart->Reset();
00319
00320 m_fanart->SetFilename(filename);
00321 m_fanartTimer.setSingleShot(true);
00322 m_fanartTimer.start(300);
00323
00324 if (wasActive)
00325 itemsPast++;
00326 else
00327 itemsPast = 0;
00328 }
00329 else
00330 itemsPast = 0;
00331 }
00332 }
00333
00334 protected slots:
00335 void fanartLoad(void)
00336 {
00337 QMutexLocker locker(&m_fanartLock);
00338 m_fanart->Load();
00339 }
00340
00341 private:
00342 int itemsPast;
00343 QMutex m_fanartLock;
00344 MythUIImage *m_fanart;
00345 QTimer m_fanartTimer;
00346 };
00347
00348 FanartLoader fanartLoader;
00349
00350 struct CopyMetadataDestination
00351 {
00352 virtual void handleText(const QString &name, const QString &value) = 0;
00353 virtual void handleState(const QString &name, const QString &value) = 0;
00354 virtual void handleImage(const QString &name,
00355 const QString &filename) = 0;
00356 };
00357
00358 class ScreenCopyDest : public CopyMetadataDestination
00359 {
00360 public:
00361 ScreenCopyDest(MythScreenType *screen) : m_screen(screen) {}
00362
00363 void handleText(const QString &name, const QString &value)
00364 {
00365 CheckedSet(m_screen, name, value);
00366 }
00367
00368 void handleState(const QString &name, const QString &value)
00369 {
00370 handleText(name, value);
00371 }
00372
00373 void handleImage(const QString &name, const QString &filename)
00374 {
00375 MythUIImage *image = NULL;
00376 UIUtilW::Assign(m_screen, image, name);
00377 if (image)
00378 {
00379 if (name != "fanart")
00380 {
00381 if (!filename.isEmpty())
00382 {
00383 image->SetFilename(filename);
00384 image->Load();
00385 }
00386 else
00387 image->Reset();
00388 }
00389 else
00390 {
00391 fanartLoader.LoadImage(filename, image);
00392 }
00393 }
00394 }
00395
00396 private:
00397 MythScreenType *m_screen;
00398 };
00399
00400 class MythUIButtonListItemCopyDest : public CopyMetadataDestination
00401 {
00402 public:
00403 MythUIButtonListItemCopyDest(MythUIButtonListItem *item) :
00404 m_item(item) {}
00405
00406 void handleText(const QString &name, const QString &value)
00407 {
00408 m_item->SetText(value, name);
00409 }
00410
00411 void handleState(const QString &name, const QString &value)
00412 {
00413 m_item->DisplayState(value, name);
00414 }
00415
00416 void handleImage(const QString &name, const QString &filename)
00417 {
00418 (void) name;
00419 (void) filename;
00420 }
00421
00422 private:
00423 MythUIButtonListItem *m_item;
00424 };
00425
00426 void CopyMetadataToUI(const VideoMetadata *metadata,
00427 CopyMetadataDestination &dest)
00428 {
00429 typedef std::map<QString, QString> valuelist;
00430 valuelist tmp;
00431
00432 if (metadata)
00433 {
00434 QString coverfile;
00435 if ((metadata->IsHostSet()
00436 && !metadata->GetCoverFile().startsWith("/"))
00437 && !metadata->GetCoverFile().isEmpty()
00438 && !IsDefaultCoverFile(metadata->GetCoverFile()))
00439 {
00440 coverfile = generate_file_url("Coverart", metadata->GetHost(),
00441 metadata->GetCoverFile());
00442 }
00443 else
00444 {
00445 coverfile = metadata->GetCoverFile();
00446 }
00447
00448 if (!IsDefaultCoverFile(coverfile))
00449 tmp["coverart"] = coverfile;
00450
00451 tmp["coverfile"] = coverfile;
00452
00453 QString screenshotfile;
00454 if (metadata->IsHostSet() && !metadata->GetScreenshot().startsWith("/")
00455 && !metadata->GetScreenshot().isEmpty())
00456 {
00457 screenshotfile = generate_file_url("Screenshots",
00458 metadata->GetHost(), metadata->GetScreenshot());
00459 }
00460 else
00461 {
00462 screenshotfile = metadata->GetScreenshot();
00463 }
00464
00465 if (!IsDefaultScreenshot(screenshotfile))
00466 tmp["screenshot"] = screenshotfile;
00467
00468 tmp["screenshotfile"] = screenshotfile;
00469
00470 QString bannerfile;
00471 if (metadata->IsHostSet() && !metadata->GetBanner().startsWith("/")
00472 && !metadata->GetBanner().isEmpty())
00473 {
00474 bannerfile = generate_file_url("Banners", metadata->GetHost(),
00475 metadata->GetBanner());
00476 }
00477 else
00478 {
00479 bannerfile = metadata->GetBanner();
00480 }
00481
00482 if (!IsDefaultBanner(bannerfile))
00483 tmp["banner"] = bannerfile;
00484
00485 tmp["bannerfile"] = bannerfile;
00486
00487 QString fanartfile;
00488 if (metadata->IsHostSet() && !metadata->GetFanart().startsWith("/")
00489 && !metadata->GetFanart().isEmpty())
00490 {
00491 fanartfile = generate_file_url("Fanart", metadata->GetHost(),
00492 metadata->GetFanart());
00493 }
00494 else
00495 {
00496 fanartfile = metadata->GetFanart();
00497 }
00498
00499 if (!IsDefaultFanart(fanartfile))
00500 tmp["fanart"] = fanartfile;
00501
00502 tmp["fanartfile"] = fanartfile;
00503
00504 tmp["trailerstate"] = TrailerToState(metadata->GetTrailer());
00505 tmp["studiostate"] = metadata->GetStudio();
00506 tmp["userratingstate"] =
00507 QString::number((int)(metadata->GetUserRating()));
00508 tmp["watchedstate"] = WatchedToState(metadata->GetWatched());
00509
00510 tmp["videolevel"] = ParentalLevelToState(metadata->GetShowLevel());
00511 }
00512
00513 struct helper
00514 {
00515 helper(valuelist &values, CopyMetadataDestination &d) :
00516 m_vallist(values), m_dest(d) {}
00517
00518 void handleImage(const QString &name)
00519 {
00520 m_dest.handleImage(name, m_vallist[name]);
00521 }
00522
00523 void handleState(const QString &name)
00524 {
00525 m_dest.handleState(name, m_vallist[name]);
00526 }
00527 private:
00528 valuelist &m_vallist;
00529 CopyMetadataDestination &m_dest;
00530 };
00531
00532 helper h(tmp, dest);
00533
00534 h.handleImage("coverart");
00535 h.handleImage("screenshot");
00536 h.handleImage("banner");
00537 h.handleImage("fanart");
00538
00539 h.handleState("trailerstate");
00540 h.handleState("userratingstate");
00541 h.handleState("watchedstate");
00542 h.handleState("videolevel");
00543 }
00544 }
00545
00546 class ItemDetailPopup : public MythScreenType
00547 {
00548 Q_OBJECT
00549
00550 public:
00551 static bool Exists()
00552 {
00553
00554 return LoadWindowFromXML("video-ui.xml", WINDOW_NAME, NULL);
00555 }
00556
00557 public:
00558 ItemDetailPopup(MythScreenStack *lparent, VideoMetadata *metadata,
00559 const VideoMetadataListManager &listManager) :
00560 MythScreenType(lparent, WINDOW_NAME), m_metadata(metadata),
00561 m_listManager(listManager), m_playButton(NULL), m_doneButton(NULL)
00562 {
00563 }
00564
00565 bool Create()
00566 {
00567 if (!LoadWindowFromXML("video-ui.xml", WINDOW_NAME, this))
00568 return false;
00569
00570 UIUtilW::Assign(this, m_playButton, "play_button");
00571 UIUtilW::Assign(this, m_doneButton, "done_button");
00572
00573 if (m_playButton)
00574 connect(m_playButton, SIGNAL(Clicked()), SLOT(OnPlay()));
00575
00576 if (m_doneButton)
00577 connect(m_doneButton, SIGNAL(Clicked()), SLOT(OnDone()));
00578
00579 BuildFocusList();
00580
00581 if (m_playButton || m_doneButton)
00582 SetFocusWidget(m_playButton ? m_playButton : m_doneButton);
00583
00584 MetadataMap metadataMap;
00585 m_metadata->toMap(metadataMap);
00586 SetTextFromMap(metadataMap);
00587
00588 ScreenCopyDest dest(this);
00589 CopyMetadataToUI(m_metadata, dest);
00590
00591 return true;
00592 }
00593
00594 private slots:
00595 void OnPlay()
00596 {
00597 PlayVideo(m_metadata->GetFilename(), m_listManager);
00598 }
00599
00600 void OnDone()
00601 {
00602
00603
00604 Close();
00605 }
00606
00607 private:
00608 bool OnKeyAction(const QStringList &actions)
00609 {
00610 bool handled = false;
00611 for (QStringList::const_iterator key = actions.begin();
00612 key != actions.end(); ++key)
00613 {
00614 handled = true;
00615 if (*key == "SELECT" || *key == "PLAYBACK")
00616 OnPlay();
00617 else
00618 handled = false;
00619 }
00620
00621 return handled;
00622 }
00623
00624 protected:
00625 bool keyPressEvent(QKeyEvent *levent)
00626 {
00627 if (!MythScreenType::keyPressEvent(levent))
00628 {
00629 QStringList actions;
00630 bool handled = GetMythMainWindow()->TranslateKeyPress("Video",
00631 levent, actions);
00632
00633 if (!handled && !OnKeyAction(actions))
00634 {
00635 handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend",
00636 levent, actions);
00637 OnKeyAction(actions);
00638 }
00639 }
00640
00641 return true;
00642 }
00643
00644 private:
00645 static const char * const WINDOW_NAME;
00646 VideoMetadata *m_metadata;
00647 const VideoMetadataListManager &m_listManager;
00648
00649 MythUIButton *m_playButton;
00650 MythUIButton *m_doneButton;
00651 };
00652
00653 const char * const ItemDetailPopup::WINDOW_NAME = "itemdetailpopup";
00654
00655 class VideoDialogPrivate
00656 {
00657 private:
00658 typedef std::list<std::pair<QString, ParentalLevel::Level> >
00659 parental_level_map;
00660
00661 struct rating_to_pl_less :
00662 public std::binary_function<parental_level_map::value_type,
00663 parental_level_map::value_type, bool>
00664 {
00665 bool operator()(const parental_level_map::value_type &lhs,
00666 const parental_level_map::value_type &rhs) const
00667 {
00668 return lhs.first.length() < rhs.first.length();
00669 }
00670 };
00671
00672 typedef VideoDialog::VideoListPtr VideoListPtr;
00673
00674 public:
00675 VideoDialogPrivate(VideoListPtr videoList, VideoDialog::DialogType type,
00676 VideoDialog::BrowseType browse) :
00677 m_switchingLayout(false), m_firstLoadPass(true),
00678 m_rememberPosition(false), m_videoList(videoList), m_rootNode(0),
00679 m_currentNode(0), m_treeLoaded(false), m_isFlatList(false),
00680 m_type(type), m_browse(browse), m_scanner(0)
00681 {
00682 if (gCoreContext->GetNumSetting("mythvideo.ParentalLevelFromRating", 0))
00683 {
00684 for (ParentalLevel sl(ParentalLevel::plLowest);
00685 sl.GetLevel() <= ParentalLevel::plHigh && sl.good(); ++sl)
00686 {
00687 QString ratingstring =
00688 gCoreContext->GetSetting(QString("mythvideo.AutoR2PL%1")
00689 .arg(sl.GetLevel()));
00690 QStringList ratings =
00691 ratingstring.split(':', QString::SkipEmptyParts);
00692
00693 for (QStringList::const_iterator p = ratings.begin();
00694 p != ratings.end(); ++p)
00695 {
00696 m_rating_to_pl.push_back(
00697 parental_level_map::value_type(*p, sl.GetLevel()));
00698 }
00699 }
00700 m_rating_to_pl.sort(std::not2(rating_to_pl_less()));
00701 }
00702
00703 m_rememberPosition =
00704 gCoreContext->GetNumSetting("mythvideo.VideoTreeRemember", 0);
00705
00706 m_isFileBrowser = gCoreContext->GetNumSetting("VideoDialogNoDB", 0);
00707 m_groupType = gCoreContext->GetNumSetting("mythvideo.db_group_type", 0);
00708
00709 m_altPlayerEnabled =
00710 gCoreContext->GetNumSetting("mythvideo.EnableAlternatePlayer");
00711
00712 m_autoMeta = gCoreContext->GetNumSetting("mythvideo.AutoMetaDataScan", 1);
00713
00714 m_artDir = gCoreContext->GetSetting("VideoArtworkDir");
00715 m_sshotDir = gCoreContext->GetSetting("mythvideo.screenshotDir");
00716 m_fanDir = gCoreContext->GetSetting("mythvideo.fanartDir");
00717 m_banDir = gCoreContext->GetSetting("mythvideo.bannerDir");
00718 }
00719
00720 ~VideoDialogPrivate()
00721 {
00722 delete m_scanner;
00723
00724 if (m_rememberPosition && m_lastTreeNodePath.length())
00725 {
00726 gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive",
00727 m_lastTreeNodePath);
00728 }
00729 }
00730
00731 void AutomaticParentalAdjustment(VideoMetadata *metadata)
00732 {
00733 if (metadata && !m_rating_to_pl.empty())
00734 {
00735 QString rating = metadata->GetRating();
00736 for (parental_level_map::const_iterator p = m_rating_to_pl.begin();
00737 !rating.isEmpty() && p != m_rating_to_pl.end(); ++p)
00738 {
00739 if (rating.indexOf(p->first) != -1)
00740 {
00741 metadata->SetShowLevel(p->second);
00742 break;
00743 }
00744 }
00745 }
00746 }
00747
00748 void DelayVideoListDestruction(VideoListPtr videoList)
00749 {
00750 m_savedPtr = new VideoListDeathDelay(videoList);
00751 }
00752
00753 public:
00754 ParentalLevelNotifyContainer m_parentalLevel;
00755 bool m_switchingLayout;
00756
00757 static VideoDialog::VideoListDeathDelayPtr m_savedPtr;
00758
00759 bool m_firstLoadPass;
00760
00761 bool m_rememberPosition;
00762
00763 VideoListPtr m_videoList;
00764
00765 MythGenericTree *m_rootNode;
00766 MythGenericTree *m_currentNode;
00767
00768 bool m_treeLoaded;
00769
00770 bool m_isFileBrowser;
00771 int m_groupType;
00772 bool m_isFlatList;
00773 bool m_altPlayerEnabled;
00774 VideoDialog::DialogType m_type;
00775 VideoDialog::BrowseType m_browse;
00776
00777 bool m_autoMeta;
00778
00779 QString m_artDir;
00780 QString m_sshotDir;
00781 QString m_fanDir;
00782 QString m_banDir;
00783 VideoScanner *m_scanner;
00784
00785 QString m_lastTreeNodePath;
00786
00787 private:
00788 parental_level_map m_rating_to_pl;
00789 };
00790
00791 VideoDialog::VideoListDeathDelayPtr VideoDialogPrivate::m_savedPtr;
00792
00793 class VideoListDeathDelayPrivate
00794 {
00795 public:
00796 VideoListDeathDelayPrivate(VideoDialog::VideoListPtr toSave) :
00797 m_savedList(toSave)
00798 {
00799 }
00800
00801 VideoDialog::VideoListPtr GetSaved()
00802 {
00803 return m_savedList;
00804 }
00805
00806 private:
00807 VideoDialog::VideoListPtr m_savedList;
00808 };
00809
00810 VideoListDeathDelay::VideoListDeathDelay(VideoDialog::VideoListPtr toSave) :
00811 QObject(qApp)
00812 {
00813 m_d = new VideoListDeathDelayPrivate(toSave);
00814 QTimer::singleShot(3000, this, SLOT(OnTimeUp()));
00815 }
00816
00817 VideoListDeathDelay::~VideoListDeathDelay()
00818 {
00819 delete m_d;
00820 }
00821
00822 VideoDialog::VideoListPtr VideoListDeathDelay::GetSaved()
00823 {
00824 return m_d->GetSaved();
00825 }
00826
00827 void VideoListDeathDelay::OnTimeUp()
00828 {
00829 deleteLater();
00830 }
00831
00832 VideoDialog::VideoListDeathDelayPtr &VideoDialog::GetSavedVideoList()
00833 {
00834 return VideoDialogPrivate::m_savedPtr;
00835 }
00836
00837 VideoDialog::VideoDialog(MythScreenStack *lparent, QString lname,
00838 VideoListPtr video_list, DialogType type, BrowseType browse) :
00839 MythScreenType(lparent, lname), m_menuPopup(0), m_busyPopup(0),
00840 m_videoButtonList(0), m_videoButtonTree(0), m_titleText(0),
00841 m_novideoText(0), m_positionText(0), m_crumbText(0), m_coverImage(0),
00842 m_screenshot(0), m_banner(0), m_fanart(0), m_trailerState(0),
00843 m_parentalLevelState(0), m_watchedState(0), m_studioState(0)
00844 {
00845 m_metadataFactory = new MetadataFactory(this);
00846
00847 m_d = new VideoDialogPrivate(video_list, type, browse);
00848
00849 m_popupStack = GetMythMainWindow()->GetStack("popup stack");
00850 m_mainStack = GetMythMainWindow()->GetMainStack();
00851
00852 m_d->m_videoList->setCurrentVideoFilter(VideoFilterSettings(true,
00853 lname));
00854
00855 m_d->m_parentalLevel.SetLevel(ParentalLevel(gCoreContext->
00856 GetNumSetting("VideoDefaultParentalLevel",
00857 ParentalLevel::plLowest)));
00858
00859 StorageGroup::ClearGroupToUseCache();
00860 }
00861
00862 VideoDialog::~VideoDialog()
00863 {
00864 if (!m_d->m_switchingLayout)
00865 m_d->DelayVideoListDestruction(m_d->m_videoList);
00866
00867 SavePosition();
00868
00869 delete m_d;
00870 }
00871
00872 void VideoDialog::SavePosition(void)
00873 {
00874 m_d->m_lastTreeNodePath = "";
00875
00876 if (m_d->m_type == DLG_TREE)
00877 {
00878 MythGenericTree *node = m_videoButtonTree->GetCurrentNode();
00879 if (node)
00880 m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
00881 }
00882 else if (m_d->m_type == DLG_BROWSER || m_d->m_type == DLG_GALLERY)
00883 {
00884 MythUIButtonListItem *item = m_videoButtonList->GetItemCurrent();
00885 if (item)
00886 {
00887 MythGenericTree *node = GetNodePtrFromButton(item);
00888 if (node)
00889 m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
00890 }
00891 }
00892
00893 gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive", m_d->m_lastTreeNodePath);
00894 }
00895
00896 bool VideoDialog::Create()
00897 {
00898 if (m_d->m_type == DLG_DEFAULT)
00899 {
00900 m_d->m_type = static_cast<DialogType>(
00901 gCoreContext->GetNumSetting("Default MythVideo View", DLG_GALLERY));
00902 m_d->m_browse = static_cast<BrowseType>(
00903 gCoreContext->GetNumSetting("mythvideo.db_group_type", BRS_FOLDER));
00904 }
00905
00906 if (!IsValidDialogType(m_d->m_type))
00907 {
00908 m_d->m_type = DLG_GALLERY;
00909 }
00910
00911 QString windowName = "videogallery";
00912 int flatlistDefault = 0;
00913
00914 switch (m_d->m_type)
00915 {
00916 case DLG_BROWSER:
00917 windowName = "browser";
00918 flatlistDefault = 1;
00919 break;
00920 case DLG_GALLERY:
00921 windowName = "gallery";
00922 break;
00923 case DLG_TREE:
00924 windowName = "tree";
00925 break;
00926 case DLG_MANAGER:
00927 m_d->m_isFlatList =
00928 gCoreContext->GetNumSetting("mythvideo.db_folder_view", 1);
00929 windowName = "manager";
00930 flatlistDefault = 1;
00931 break;
00932 case DLG_DEFAULT:
00933 default:
00934 break;
00935 }
00936
00937 switch (m_d->m_browse)
00938 {
00939 case BRS_GENRE:
00940 m_d->m_groupType = BRS_GENRE;
00941 break;
00942 case BRS_CATEGORY:
00943 m_d->m_groupType = BRS_CATEGORY;
00944 break;
00945 case BRS_YEAR:
00946 m_d->m_groupType = BRS_YEAR;
00947 break;
00948 case BRS_DIRECTOR:
00949 m_d->m_groupType = BRS_DIRECTOR;
00950 break;
00951 case BRS_STUDIO:
00952 m_d->m_groupType = BRS_STUDIO;
00953 break;
00954 case BRS_CAST:
00955 m_d->m_groupType = BRS_CAST;
00956 break;
00957 case BRS_USERRATING:
00958 m_d->m_groupType = BRS_USERRATING;
00959 break;
00960 case BRS_INSERTDATE:
00961 m_d->m_groupType = BRS_INSERTDATE;
00962 break;
00963 case BRS_TVMOVIE:
00964 m_d->m_groupType = BRS_TVMOVIE;
00965 break;
00966 case BRS_FOLDER:
00967 default:
00968 m_d->m_groupType = BRS_FOLDER;
00969 break;
00970 }
00971
00972 m_d->m_isFlatList =
00973 gCoreContext->GetNumSetting(QString("mythvideo.folder_view_%1")
00974 .arg(m_d->m_type), flatlistDefault);
00975
00976 if (!LoadWindowFromXML("video-ui.xml", windowName, this))
00977 return false;
00978
00979 bool err = false;
00980 if (m_d->m_type == DLG_TREE)
00981 UIUtilE::Assign(this, m_videoButtonTree, "videos", &err);
00982 else
00983 UIUtilE::Assign(this, m_videoButtonList, "videos", &err);
00984
00985 UIUtilW::Assign(this, m_titleText, "title");
00986 UIUtilW::Assign(this, m_novideoText, "novideos");
00987 UIUtilW::Assign(this, m_positionText, "position");
00988 UIUtilW::Assign(this, m_crumbText, "breadcrumbs");
00989
00990 UIUtilW::Assign(this, m_coverImage, "coverart");
00991 UIUtilW::Assign(this, m_screenshot, "screenshot");
00992 UIUtilW::Assign(this, m_banner, "banner");
00993 UIUtilW::Assign(this, m_fanart, "fanart");
00994
00995 UIUtilW::Assign(this, m_trailerState, "trailerstate");
00996 UIUtilW::Assign(this, m_parentalLevelState, "parentallevel");
00997 UIUtilW::Assign(this, m_watchedState, "watchedstate");
00998 UIUtilW::Assign(this, m_studioState, "studiostate");
00999
01000 if (err)
01001 {
01002 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen '" + windowName + "'");
01003 return false;
01004 }
01005
01006 CheckedSet(m_trailerState, "None");
01007 CheckedSet(m_parentalLevelState, "None");
01008 CheckedSet(m_watchedState, "None");
01009 CheckedSet(m_studioState, "None");
01010
01011 BuildFocusList();
01012
01013 if (m_d->m_type == DLG_TREE)
01014 {
01015 SetFocusWidget(m_videoButtonTree);
01016
01017 connect(m_videoButtonTree, SIGNAL(itemClicked(MythUIButtonListItem *)),
01018 SLOT(handleSelect(MythUIButtonListItem *)));
01019 connect(m_videoButtonTree, SIGNAL(itemSelected(MythUIButtonListItem *)),
01020 SLOT(UpdateText(MythUIButtonListItem *)));
01021 connect(m_videoButtonTree, SIGNAL(nodeChanged(MythGenericTree *)),
01022 SLOT(SetCurrentNode(MythGenericTree *)));
01023 }
01024 else
01025 {
01026 SetFocusWidget(m_videoButtonList);
01027
01028 connect(m_videoButtonList, SIGNAL(itemClicked(MythUIButtonListItem *)),
01029 SLOT(handleSelect(MythUIButtonListItem *)));
01030 connect(m_videoButtonList, SIGNAL(itemSelected(MythUIButtonListItem *)),
01031 SLOT(UpdateText(MythUIButtonListItem *)));
01032 }
01033
01034 return true;
01035 }
01036
01037 void VideoDialog::Init()
01038 {
01039 connect(&m_d->m_parentalLevel, SIGNAL(SigLevelChanged()),
01040 SLOT(reloadData()));
01041 }
01042
01043 void VideoDialog::Load()
01044 {
01045 reloadData();
01046
01047 if (m_d->m_rootNode->childCount() == 1 &&
01048 m_d->m_rootNode->getChildAt(0)->getInt() == kNoFilesFound)
01049 PromptToScan();
01050 }
01051
01056 void VideoDialog::refreshData()
01057 {
01058 fetchVideos();
01059 loadData();
01060
01061 CheckedSet(m_parentalLevelState,
01062 ParentalLevelToState(m_d->m_parentalLevel.GetLevel()));
01063
01064 bool noFiles = (m_d->m_rootNode->childCount() == 1 &&
01065 m_d->m_rootNode->getChildAt(0)->getInt() == kNoFilesFound);
01066
01067 if (m_novideoText)
01068 m_novideoText->SetVisible(noFiles);
01069 }
01070
01071 void VideoDialog::scanFinished(bool dbChanged)
01072 {
01073 delete m_d->m_scanner;
01074 m_d->m_scanner = 0;
01075
01076 if (dbChanged)
01077 m_d->m_videoList->InvalidateCache();
01078
01079 m_d->m_currentNode = NULL;
01080 reloadData();
01081
01082 if (m_d->m_autoMeta)
01083 VideoAutoSearch();
01084
01085 if (m_d->m_rootNode->childCount() == 1 &&
01086 m_d->m_rootNode->getChildAt(0)->getInt() == kNoFilesFound)
01087 {
01088 QString message = tr("The video scan found no files, have you "
01089 "configured a video storage group?");
01090 ShowOkPopup(message);
01091 }
01092 }
01093
01098 void VideoDialog::reloadData()
01099 {
01100 m_d->m_treeLoaded = false;
01101 refreshData();
01102 }
01103
01108 void VideoDialog::loadData()
01109 {
01110 if (m_d->m_type == DLG_TREE)
01111 {
01112 m_videoButtonTree->AssignTree(m_d->m_rootNode);
01113
01114 if (m_d->m_firstLoadPass)
01115 {
01116 m_d->m_firstLoadPass = false;
01117
01118 if (m_d->m_rememberPosition)
01119 {
01120 QStringList route =
01121 gCoreContext->GetSetting("mythvideo.VideoTreeLastActive",
01122 "").split("\n");
01123 m_videoButtonTree->SetNodeByString(route);
01124 }
01125 }
01126 }
01127 else
01128 {
01129 m_videoButtonList->Reset();
01130
01131 if (!m_d->m_treeLoaded)
01132 return;
01133
01134 if (!m_d->m_currentNode)
01135 SetCurrentNode(m_d->m_rootNode);
01136
01137 if (!m_d->m_currentNode)
01138 return;
01139
01140 MythGenericTree *selectedNode = m_d->m_currentNode->getSelectedChild();
01141
01142
01143
01144 if (m_d->m_firstLoadPass)
01145 {
01146 if (m_d->m_rememberPosition)
01147 {
01148 QStringList lastTreeNodePath = gCoreContext->GetSetting("mythvideo.VideoTreeLastActive", "").split("\n");
01149
01150 if (m_d->m_type == DLG_GALLERY || m_d->m_type == DLG_BROWSER)
01151 {
01152 if (!lastTreeNodePath.isEmpty())
01153 {
01154 MythGenericTree *node;
01155
01156
01157 for (int i = 0; i < lastTreeNodePath.size(); i++)
01158 {
01159 node = m_d->m_currentNode->getChildByName(lastTreeNodePath.at(i));
01160 if (node != NULL)
01161 {
01162
01163
01164
01165 if (node->getString().compare(lastTreeNodePath.at(i)) == 0)
01166 {
01167
01168
01169 if (node->getInt() == kSubFolder &&
01170 node->childCount() > 1 &&
01171 i < lastTreeNodePath.size()-1)
01172 {
01173 SetCurrentNode(node);
01174 }
01175
01176
01177 if (lastTreeNodePath.at(i) == lastTreeNodePath.last())
01178 selectedNode = node;
01179 }
01180 }
01181 }
01182 m_d->m_firstLoadPass = false;
01183 }
01184 }
01185 }
01186 }
01187
01188 typedef QList<MythGenericTree *> MGTreeChildList;
01189 MGTreeChildList *lchildren = m_d->m_currentNode->getAllChildren();
01190
01191 for (MGTreeChildList::const_iterator p = lchildren->begin();
01192 p != lchildren->end(); ++p)
01193 {
01194 if (*p != NULL)
01195 {
01196 MythUIButtonListItem *item =
01197 new MythUIButtonListItem(m_videoButtonList, QString(), 0,
01198 true, MythUIButtonListItem::NotChecked);
01199
01200 item->SetData(qVariantFromValue(*p));
01201
01202 UpdateItem(item);
01203
01204 if (*p == selectedNode)
01205 m_videoButtonList->SetItemCurrent(item);
01206 }
01207 }
01208 }
01209
01210 UpdatePosition();
01211 }
01212
01217 void VideoDialog::UpdateItem(MythUIButtonListItem *item)
01218 {
01219 if (!item)
01220 return;
01221
01222 MythGenericTree *node = GetNodePtrFromButton(item);
01223
01224 VideoMetadata *metadata = GetMetadata(item);
01225
01226 if (metadata)
01227 {
01228 MetadataMap metadataMap;
01229 metadata->toMap(metadataMap);
01230 item->SetTextFromMap(metadataMap);
01231 }
01232
01233 MythUIButtonListItemCopyDest dest(item);
01234 CopyMetadataToUI(metadata, dest);
01235
01236 MythGenericTree *parent = node->getParent();
01237
01238 if (parent && metadata && ((QString::compare(parent->getString(),
01239 metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
01240 parent->getString().startsWith(tr("Season"), Qt::CaseInsensitive)))
01241 item->SetText(metadata->GetSubtitle());
01242 else if (metadata && !metadata->GetSubtitle().isEmpty())
01243 item->SetText(QString("%1: %2").arg(metadata->GetTitle()).arg(metadata->GetSubtitle()));
01244 else
01245 item->SetText(metadata ? metadata->GetTitle() : node->getString());
01246
01247 QString coverimage = GetCoverImage(node);
01248 QString screenshot = GetScreenshot(node);
01249 QString banner = GetBanner(node);
01250 QString fanart = GetFanart(node);
01251
01252 if (!screenshot.isEmpty() && parent && metadata &&
01253 ((QString::compare(parent->getString(),
01254 metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
01255 parent->getString().startsWith(tr("Season"), Qt::CaseInsensitive)))
01256 {
01257 item->SetImage(screenshot);
01258 }
01259 else
01260 {
01261 if (coverimage.isEmpty())
01262 coverimage = GetFirstImage(node, "Coverart");
01263 item->SetImage(coverimage);
01264 }
01265
01266 int nodeInt = node->getInt();
01267
01268 if (coverimage.isEmpty() && nodeInt == kSubFolder)
01269 coverimage = GetFirstImage(node, "Coverart");
01270
01271 item->SetImage(coverimage, "coverart");
01272
01273 if (screenshot.isEmpty() && nodeInt == kSubFolder)
01274 screenshot = GetFirstImage(node, "Screenshots");
01275
01276 item->SetImage(screenshot, "screenshot");
01277
01278 if (banner.isEmpty() && nodeInt == kSubFolder)
01279 banner = GetFirstImage(node, "Banners");
01280
01281 item->SetImage(banner, "banner");
01282
01283 if (fanart.isEmpty() && nodeInt == kSubFolder)
01284 fanart = GetFirstImage(node, "Fanart");
01285
01286 item->SetImage(fanart, "fanart");
01287
01288 if (nodeInt == kSubFolder)
01289 {
01290 item->SetText(QString("%1").arg(node->visibleChildCount()), "childcount");
01291 item->DisplayState("subfolder", "nodetype");
01292 item->SetText(node->getString(), "title");
01293 item->SetText(node->getString());
01294 }
01295 else if (nodeInt == kUpFolder)
01296 {
01297 item->DisplayState("upfolder", "nodetype");
01298 item->SetText(node->getString(), "title");
01299 item->SetText(node->getString());
01300 }
01301
01302 if (item == GetItemCurrent())
01303 UpdateText(item);
01304 }
01305
01310 void VideoDialog::fetchVideos()
01311 {
01312 MythGenericTree *oldroot = m_d->m_rootNode;
01313 if (!m_d->m_treeLoaded)
01314 {
01315 m_d->m_rootNode = m_d->m_videoList->buildVideoList(m_d->m_isFileBrowser,
01316 m_d->m_isFlatList, m_d->m_groupType,
01317 m_d->m_parentalLevel.GetLevel(), true);
01318 }
01319 else
01320 {
01321 m_d->m_videoList->refreshList(m_d->m_isFileBrowser,
01322 m_d->m_parentalLevel.GetLevel(),
01323 m_d->m_isFlatList, m_d->m_groupType);
01324 m_d->m_rootNode = m_d->m_videoList->GetTreeRoot();
01325 }
01326
01327 m_d->m_treeLoaded = true;
01328
01329 m_d->m_rootNode->setOrderingIndex(kNodeSort);
01330
01331
01332 if (m_d->m_rootNode->childCount() == 1)
01333 {
01334 MythGenericTree *node = m_d->m_rootNode->getChildAt(0);
01335 if (node->getInt() == kSubFolder && node->childCount() > 1)
01336 m_d->m_rootNode = node;
01337 else if (node->getInt() == kUpFolder)
01338 m_d->m_treeLoaded = false;
01339 }
01340 else if (m_d->m_rootNode->childCount() == 0)
01341 m_d->m_treeLoaded = false;
01342
01343 if (!m_d->m_currentNode || m_d->m_rootNode != oldroot)
01344 SetCurrentNode(m_d->m_rootNode);
01345 }
01346
01351 QString VideoDialog::RemoteImageCheck(QString host, QString filename)
01352 {
01353 QString result = "";
01354 #if 0
01355 LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteImageCheck(%1)").arg(filename));
01356 #endif
01357
01358 QStringList dirs = GetVideoDirsByHost(host);
01359
01360 if (!dirs.isEmpty())
01361 {
01362 for (QStringList::const_iterator iter = dirs.begin();
01363 iter != dirs.end(); ++iter)
01364 {
01365 QUrl sgurl = *iter;
01366 QString path = sgurl.path();
01367
01368 QString fname = QString("%1/%2").arg(path).arg(filename);
01369
01370 QStringList list( QString("QUERY_SG_FILEQUERY") );
01371 list << host;
01372 list << "Videos";
01373 list << fname;
01374
01375 bool ok = gCoreContext->SendReceiveStringList(list);
01376
01377 if (!ok || list.at(0).startsWith("SLAVE UNREACHABLE"))
01378 {
01379 LOG(VB_GENERAL, LOG_WARNING,
01380 QString("Backend : %1 currently Unreachable. Skipping "
01381 "this one.") .arg(host));
01382 break;
01383 }
01384
01385 if ((!list.isEmpty()) && (list.at(0) == fname))
01386 result = generate_file_url("Videos", host, filename);
01387
01388 if (!result.isEmpty())
01389 {
01390 #if 0
01391 LOG(VB_GENERAL, LOG_DEBUG,
01392 QString("RemoteImageCheck(%1) res :%2: :%3:")
01393 .arg(fname).arg(result).arg(*iter));
01394 #endif
01395 break;
01396 }
01397
01398 }
01399 }
01400
01401 return result;
01402 }
01403
01408 QString VideoDialog::GetImageFromFolder(VideoMetadata *metadata)
01409 {
01410 QString icon_file;
01411 QString host = metadata->GetHost();
01412 QFileInfo fullpath(metadata->GetFilename());
01413 QDir dir = fullpath.dir();
01414 QString prefix = QDir::cleanPath(dir.path());
01415
01416 QString filename = QString("%1/folder").arg(prefix);
01417
01418 QStringList test_files;
01419 test_files.append(filename + ".png");
01420 test_files.append(filename + ".jpg");
01421 test_files.append(filename + ".gif");
01422 bool foundCover;
01423
01424 for (QStringList::const_iterator tfp = test_files.begin();
01425 tfp != test_files.end(); ++tfp)
01426 {
01427 QString imagePath = *tfp;
01428 foundCover = false;
01429 if (!host.isEmpty())
01430 {
01431
01432 imagePath.replace("//", "/");
01433 prefix.replace("//","/");
01434 imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
01435 QString tmpCover = RemoteImageCheck(host, imagePath);
01436
01437 if (!tmpCover.isEmpty())
01438 {
01439 foundCover = true;
01440 imagePath = tmpCover;
01441 }
01442 }
01443 else
01444 foundCover = QFile::exists(imagePath);
01445
01446 if (foundCover)
01447 {
01448 icon_file = imagePath;
01449 return icon_file;
01450 }
01451 }
01452
01453
01454
01455 if (icon_file.isEmpty())
01456 {
01457 QStringList imageTypes;
01458 imageTypes.append(metadata->GetTitle() + ".png");
01459 imageTypes.append(metadata->GetTitle() + ".jpg");
01460 imageTypes.append(metadata->GetTitle() + ".gif");
01461 imageTypes.append("*.png");
01462 imageTypes.append("*.jpg");
01463 imageTypes.append("*.gif");
01464
01465 QStringList fList;
01466
01467 if (!host.isEmpty())
01468 {
01469
01470
01471 QStringList dirs = GetVideoDirsByHost(host);
01472
01473 if (!dirs.isEmpty())
01474 {
01475 for (QStringList::const_iterator iter = dirs.begin();
01476 iter != dirs.end(); ++iter)
01477 {
01478 QUrl sgurl = *iter;
01479 QString path = sgurl.path();
01480
01481 QString subdir = prefix;
01482
01483 path = path + "/" + subdir;
01484 QStringList tmpList;
01485 bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
01486
01487 if (ok)
01488 {
01489 for (QStringList::const_iterator pattern = imageTypes.begin();
01490 pattern != imageTypes.end(); ++pattern)
01491 {
01492 QRegExp rx(*pattern);
01493 rx.setPatternSyntax(QRegExp::Wildcard);
01494 QStringList matches = tmpList.filter(rx);
01495 if (!matches.isEmpty())
01496 {
01497 fList.clear();
01498 fList.append(subdir + "/" + matches.at(0).split("::").at(1));
01499 break;
01500 }
01501 }
01502
01503 break;
01504 }
01505 }
01506 }
01507 }
01508 else
01509 {
01510 QDir vidDir(prefix);
01511 vidDir.setNameFilters(imageTypes);
01512 fList = vidDir.entryList();
01513 }
01514
01515 if (!fList.isEmpty())
01516 {
01517 if (host.isEmpty())
01518 icon_file = QString("%1/%2")
01519 .arg(prefix)
01520 .arg(fList.at(0));
01521 else
01522 icon_file = generate_file_url("Videos", host, fList.at(0));
01523 }
01524 }
01525
01526 if (!icon_file.isEmpty())
01527 LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
01528 .arg(icon_file));
01529 else
01530 LOG(VB_GENERAL, LOG_DEBUG, QString("Could not find cover Image : %1 ")
01531 .arg(prefix));
01532
01533 if (IsDefaultCoverFile(icon_file))
01534 icon_file.clear();
01535
01536 return icon_file;
01537 }
01538
01543 QString VideoDialog::GetCoverImage(MythGenericTree *node)
01544 {
01545 int nodeInt = node->getInt();
01546
01547 QString icon_file;
01548
01549 if (nodeInt == kSubFolder)
01550 {
01551
01552 QString folder_path = node->GetData().value<TreeNodeData>().GetPath();
01553 QString host = node->GetData().value<TreeNodeData>().GetHost();
01554 QString prefix = node->GetData().value<TreeNodeData>().GetPrefix();
01555
01556 if (folder_path.startsWith("myth://"))
01557 folder_path = folder_path.right(folder_path.length()
01558 - folder_path.lastIndexOf("//") - 1);
01559
01560 QString filename = QString("%1/folder").arg(folder_path);
01561
01562 #if 0
01563 LOG(VB_GENERAL, LOG_DEBUG,
01564 QString("GetCoverImage host : %1 prefix : %2 file : %3")
01565 .arg(host).arg(prefix).arg(filename));
01566 #endif
01567
01568 QStringList test_files;
01569 test_files.append(filename + ".png");
01570 test_files.append(filename + ".jpg");
01571 test_files.append(filename + ".gif");
01572 bool foundCover;
01573
01574 for (QStringList::const_iterator tfp = test_files.begin();
01575 tfp != test_files.end(); ++tfp)
01576 {
01577 QString imagePath = *tfp;
01578 #if 0
01579 LOG(VB_GENERAL, LOG_DEBUG, QString("Cover check :%1 : ").arg(*tfp));
01580 #endif
01581
01582 foundCover = false;
01583 if (!host.isEmpty())
01584 {
01585
01586 imagePath.replace("//", "/");
01587 prefix.replace("//","/");
01588 imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
01589 QString tmpCover = RemoteImageCheck(host, imagePath);
01590
01591 if (!tmpCover.isEmpty())
01592 {
01593 foundCover = true;
01594 imagePath = tmpCover;
01595 }
01596 }
01597 else
01598 foundCover = QFile::exists(imagePath);
01599
01600 if (foundCover)
01601 {
01602 icon_file = imagePath;
01603 break;
01604 }
01605 }
01606
01607
01608 if (icon_file.isEmpty())
01609 {
01610 QStringList imageTypes;
01611 imageTypes.append("*.png");
01612 imageTypes.append("*.jpg");
01613 imageTypes.append("*.gif");
01614
01615 QStringList fList;
01616
01617 if (!host.isEmpty())
01618 {
01619
01620
01621 QStringList dirs = GetVideoDirsByHost(host);
01622
01623 if (!dirs.isEmpty())
01624 {
01625 for (QStringList::const_iterator iter = dirs.begin();
01626 iter != dirs.end(); ++iter)
01627 {
01628 QUrl sgurl = *iter;
01629 QString path = sgurl.path();
01630
01631 QString subdir = folder_path.right(folder_path.length() - (prefix.length() + 2));
01632
01633 path = path + "/" + subdir;
01634
01635 QStringList tmpList;
01636 bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
01637
01638 if (ok)
01639 {
01640 for (QStringList::const_iterator pattern = imageTypes.begin();
01641 pattern != imageTypes.end(); ++pattern)
01642 {
01643 QRegExp rx(*pattern);
01644 rx.setPatternSyntax(QRegExp::Wildcard);
01645 QStringList matches = tmpList.filter(rx);
01646 if (!matches.isEmpty())
01647 {
01648 fList.clear();
01649 fList.append(subdir + "/" + matches.at(0).split("::").at(1));
01650 break;
01651 }
01652 }
01653
01654 break;
01655 }
01656 }
01657 }
01658
01659 }
01660 else
01661 {
01662 QDir vidDir(folder_path);
01663 vidDir.setNameFilters(imageTypes);
01664 fList = vidDir.entryList();
01665 }
01666
01667
01668 if (icon_file.isEmpty())
01669 {
01670 int list_count = node->visibleChildCount();
01671 if (list_count > 0)
01672 {
01673 for (int i = 0; i < list_count; i++)
01674 {
01675 MythGenericTree *subnode = node->getVisibleChildAt(i);
01676 if (subnode)
01677 {
01678 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
01679 if (metadata)
01680 {
01681 if (!metadata->GetHost().isEmpty() &&
01682 !metadata->GetCoverFile().startsWith("/"))
01683 {
01684 QString test_file = generate_file_url("Coverart",
01685 metadata->GetHost(), metadata->GetCoverFile());
01686 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01687 !IsDefaultCoverFile(test_file))
01688 {
01689 icon_file = test_file;
01690 break;
01691 }
01692 }
01693 else
01694 {
01695 QString test_file = metadata->GetCoverFile();
01696 if (!test_file.isEmpty() &&
01697 !IsDefaultCoverFile(test_file))
01698 {
01699 icon_file = test_file;
01700 break;
01701 }
01702 }
01703 }
01704 }
01705 }
01706 }
01707 }
01708
01709 if (!fList.isEmpty())
01710 {
01711 if (host.isEmpty())
01712 icon_file = QString("%1/%2")
01713 .arg(folder_path)
01714 .arg(fList.at(0));
01715 else
01716 icon_file = generate_file_url("Videos", host, fList.at(0));
01717 }
01718 }
01719
01720 if (!icon_file.isEmpty())
01721 LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
01722 .arg(icon_file));
01723 else
01724 LOG(VB_GENERAL, LOG_DEBUG,
01725 QString("Could not find folder cover Image : %1 ")
01726 .arg(folder_path));
01727 }
01728 else
01729 {
01730 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01731
01732 if (metadata)
01733 {
01734 if (metadata->IsHostSet() &&
01735 !metadata->GetCoverFile().startsWith("/") &&
01736 !IsDefaultCoverFile(metadata->GetCoverFile()))
01737 {
01738 icon_file = generate_file_url("Coverart", metadata->GetHost(),
01739 metadata->GetCoverFile());
01740 }
01741 else
01742 {
01743 icon_file = metadata->GetCoverFile();
01744 }
01745 }
01746 }
01747
01748 if (IsDefaultCoverFile(icon_file))
01749 icon_file.clear();
01750
01751 return icon_file;
01752 }
01753
01765 QString VideoDialog::GetFirstImage(MythGenericTree *node, QString type,
01766 QString gpnode, int levels)
01767 {
01768 if (!node || type.isEmpty())
01769 return QString();
01770
01771 QString icon_file;
01772
01773 int list_count = node->visibleChildCount();
01774 if (list_count > 0)
01775 {
01776 QList<MythGenericTree *> subDirs;
01777 int maxRecurse = 1;
01778
01779 for (int i = 0; i < list_count; i++)
01780 {
01781 MythGenericTree *subnode = node->getVisibleChildAt(i);
01782 if (subnode)
01783 {
01784 if (subnode->childCount() > 0)
01785 subDirs << subnode;
01786
01787 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
01788 if (metadata)
01789 {
01790 QString test_file;
01791 QString host = metadata->GetHost();
01792 QString title = metadata->GetTitle();
01793
01794 if (type == "Coverart" && !host.isEmpty() &&
01795 !metadata->GetCoverFile().startsWith("/"))
01796 {
01797 test_file = generate_file_url("Coverart",
01798 host, metadata->GetCoverFile());
01799 }
01800 else if (type == "Coverart")
01801 test_file = metadata->GetCoverFile();
01802
01803 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01804 !IsDefaultCoverFile(test_file) && (gpnode.isEmpty() ||
01805 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01806 {
01807 icon_file = test_file;
01808 break;
01809 }
01810
01811 if (type == "Fanart" && !host.isEmpty() &&
01812 !metadata->GetFanart().startsWith("/"))
01813 {
01814 test_file = generate_file_url("Fanart",
01815 host, metadata->GetFanart());
01816 }
01817 else if (type == "Fanart")
01818 test_file = metadata->GetFanart();
01819
01820 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01821 test_file != VIDEO_FANART_DEFAULT && (gpnode.isEmpty() ||
01822 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01823 {
01824 icon_file = test_file;
01825 break;
01826 }
01827
01828 if (type == "Banners" && !host.isEmpty() &&
01829 !metadata->GetBanner().startsWith("/"))
01830 {
01831 test_file = generate_file_url("Banners",
01832 host, metadata->GetBanner());
01833 }
01834 else if (type == "Banners")
01835 test_file = metadata->GetBanner();
01836
01837 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01838 test_file != VIDEO_BANNER_DEFAULT && (gpnode.isEmpty() ||
01839 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01840 {
01841 icon_file = test_file;
01842 break;
01843 }
01844
01845 if (type == "Screenshots" && !host.isEmpty() &&
01846 !metadata->GetScreenshot().startsWith("/"))
01847 {
01848 test_file = generate_file_url("Screenshots",
01849 host, metadata->GetScreenshot());
01850 }
01851 else if (type == "Screenshots")
01852 test_file = metadata->GetScreenshot();
01853
01854 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01855 test_file != VIDEO_SCREENSHOT_DEFAULT && (gpnode.isEmpty() ||
01856 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01857 {
01858 icon_file = test_file;
01859 break;
01860 }
01861 }
01862 }
01863 }
01864 if (icon_file.isEmpty() && !subDirs.isEmpty())
01865 {
01866 QString test_file;
01867 int subDirCount = subDirs.count();
01868 for (int i = 0; i < subDirCount; i ++)
01869 {
01870 if (levels < maxRecurse)
01871 {
01872 test_file = GetFirstImage(subDirs[i], type,
01873 node->getString(), levels + 1);
01874 if (!test_file.isEmpty())
01875 {
01876 icon_file = test_file;
01877 break;
01878 }
01879 }
01880 }
01881 }
01882 }
01883 return icon_file;
01884 }
01885
01890 QString VideoDialog::GetScreenshot(MythGenericTree *node)
01891 {
01892 const int nodeInt = node->getInt();
01893
01894 QString icon_file;
01895
01896 if (nodeInt == kSubFolder || nodeInt == kUpFolder)
01897 {
01898 icon_file = VIDEO_SCREENSHOT_DEFAULT;
01899 }
01900 else
01901 {
01902 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01903
01904 if (metadata)
01905 {
01906 if (metadata->IsHostSet() &&
01907 !metadata->GetScreenshot().startsWith("/") &&
01908 !metadata->GetScreenshot().isEmpty())
01909 {
01910 icon_file = generate_file_url("Screenshots", metadata->GetHost(),
01911 metadata->GetScreenshot());
01912 }
01913 else
01914 {
01915 icon_file = metadata->GetScreenshot();
01916 }
01917 }
01918 }
01919
01920 if (IsDefaultScreenshot(icon_file))
01921 icon_file.clear();
01922
01923 return icon_file;
01924 }
01925
01930 QString VideoDialog::GetBanner(MythGenericTree *node)
01931 {
01932 const int nodeInt = node->getInt();
01933
01934 if (nodeInt == kSubFolder || nodeInt == kUpFolder)
01935 return QString();
01936
01937 QString icon_file;
01938 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01939
01940 if (metadata)
01941 {
01942 if (metadata->IsHostSet() &&
01943 !metadata->GetBanner().startsWith("/") &&
01944 !metadata->GetBanner().isEmpty())
01945 {
01946 icon_file = generate_file_url("Banners", metadata->GetHost(),
01947 metadata->GetBanner());
01948 }
01949 else
01950 {
01951 icon_file = metadata->GetBanner();
01952 }
01953
01954 if (IsDefaultBanner(icon_file))
01955 icon_file.clear();
01956 }
01957
01958 return icon_file;
01959 }
01960
01965 QString VideoDialog::GetFanart(MythGenericTree *node)
01966 {
01967 const int nodeInt = node->getInt();
01968
01969 if (nodeInt == kSubFolder || nodeInt == kUpFolder)
01970 return QString();
01971
01972 QString icon_file;
01973 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01974
01975 if (metadata)
01976 {
01977 if (metadata->IsHostSet() &&
01978 !metadata->GetFanart().startsWith("/") &&
01979 !metadata->GetFanart().isEmpty())
01980 {
01981 icon_file = generate_file_url("Fanart", metadata->GetHost(),
01982 metadata->GetFanart());
01983 }
01984 else
01985 {
01986 icon_file = metadata->GetFanart();
01987 }
01988
01989 if (IsDefaultFanart(icon_file))
01990 icon_file.clear();
01991 }
01992
01993 return icon_file;
01994 }
01995
02000 bool VideoDialog::keyPressEvent(QKeyEvent *levent)
02001 {
02002 if (GetFocusWidget()->keyPressEvent(levent))
02003 return true;
02004
02005 bool handled = false;
02006 QStringList actions;
02007 handled = GetMythMainWindow()->TranslateKeyPress("Video", levent, actions);
02008
02009 for (int i = 0; i < actions.size() && !handled; i++)
02010 {
02011 QString action = actions[i];
02012 handled = true;
02013
02014 if (action == "INFO")
02015 {
02016 MythUIButtonListItem *item = GetItemCurrent();
02017 MythGenericTree *node = GetNodePtrFromButton(item);
02018 if (!m_menuPopup && node->getInt() != kUpFolder)
02019 VideoMenu();
02020 }
02021 else if (action == "INCPARENT")
02022 shiftParental(1);
02023 else if (action == "DECPARENT")
02024 shiftParental(-1);
02025 else if (action == "1" || action == "2" ||
02026 action == "3" || action == "4")
02027 setParentalLevel((ParentalLevel::Level)action.toInt());
02028 else if (action == "FILTER")
02029 ChangeFilter();
02030 else if (action == "MENU")
02031 {
02032 if (!m_menuPopup)
02033 DisplayMenu();
02034 }
02035 else if (action == "PLAYALT")
02036 {
02037 if (!m_menuPopup && GetMetadata(GetItemCurrent()) &&
02038 m_d->m_altPlayerEnabled)
02039 playVideoAlt();
02040 }
02041 else if (action == "DOWNLOADDATA")
02042 {
02043 if (!m_menuPopup && GetMetadata(GetItemCurrent()))
02044 VideoSearch();
02045 }
02046 else if (action == "INCSEARCH")
02047 searchStart();
02048 else if (action == "ITEMDETAIL")
02049 DoItemDetailShow();
02050 else if (action == "DELETE")
02051 {
02052 if (!m_menuPopup && GetMetadata(GetItemCurrent()))
02053 RemoveVideo();
02054 }
02055 else if (action == "EDIT" && !m_menuPopup)
02056 EditMetadata();
02057 else if (action == "ESCAPE")
02058 {
02059 if (m_d->m_type != DLG_TREE
02060 && !GetMythMainWindow()->IsExitingToMain()
02061 && m_d->m_currentNode != m_d->m_rootNode)
02062 handled = goBack();
02063 else
02064 handled = false;
02065 }
02066 else
02067 handled = false;
02068 }
02069
02070 if (!handled)
02071 {
02072 handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", levent,
02073 actions);
02074
02075 for (int i = 0; i < actions.size() && !handled; i++)
02076 {
02077 QString action = actions[i];
02078 if (action == "PLAYBACK")
02079 {
02080 handled = true;
02081 playVideo();
02082 }
02083 }
02084 }
02085
02086 if (!handled && MythScreenType::keyPressEvent(levent))
02087 handled = true;
02088
02089 return handled;
02090 }
02091
02096 void VideoDialog::createBusyDialog(QString title)
02097 {
02098 if (m_busyPopup)
02099 return;
02100
02101 QString message = title;
02102
02103 m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
02104 "mythvideobusydialog");
02105
02106 if (m_busyPopup->Create())
02107 m_popupStack->AddScreen(m_busyPopup);
02108 }
02109
02114 void VideoDialog::createOkDialog(QString title)
02115 {
02116 QString message = title;
02117
02118 MythConfirmationDialog *okPopup =
02119 new MythConfirmationDialog(m_popupStack, message, false);
02120
02121 if (okPopup->Create())
02122 m_popupStack->AddScreen(okPopup);
02123 }
02124
02129 void VideoDialog::searchComplete(QString string)
02130 {
02131 LOG(VB_GENERAL, LOG_DEBUG, QString("Jumping to: %1").arg(string));
02132
02133 MythGenericTree *parent = m_d->m_currentNode->getParent();
02134 QStringList childList;
02135 QList<MythGenericTree*>::iterator it;
02136 QList<MythGenericTree*> *children;
02137 QMap<int, QString> idTitle;
02138
02139 if (parent && m_d->m_type == DLG_TREE)
02140 children = parent->getAllChildren();
02141 else
02142 children = m_d->m_currentNode->getAllChildren();
02143
02144 for (it = children->begin(); it != children->end(); ++it)
02145 {
02146 MythGenericTree *child = *it;
02147 QString title = child->getString();
02148 int id = child->getPosition();
02149 idTitle.insert(id, title);
02150 }
02151
02152 if (m_d->m_type == DLG_TREE)
02153 {
02154 MythGenericTree *parent = m_videoButtonTree->GetCurrentNode()->getParent();
02155 MythGenericTree *new_node = parent->getChildAt(idTitle.key(string));
02156 if (new_node)
02157 {
02158 m_videoButtonTree->SetCurrentNode(new_node);
02159 m_videoButtonTree->SetActive(true);
02160 }
02161 }
02162 else
02163 m_videoButtonList->SetItemCurrent(idTitle.key(string));
02164 }
02165
02170 void VideoDialog::searchStart(void)
02171 {
02172 MythGenericTree *parent = m_d->m_currentNode->getParent();
02173
02174 QStringList childList;
02175 QList<MythGenericTree*>::iterator it;
02176 QList<MythGenericTree*> *children;
02177 if (parent && m_d->m_type == DLG_TREE)
02178 children = parent->getAllChildren();
02179 else
02180 children = m_d->m_currentNode->getAllChildren();
02181
02182 for (it = children->begin(); it != children->end(); ++it)
02183 {
02184 MythGenericTree *child = *it;
02185 childList << child->getString();
02186 }
02187
02188 MythScreenStack *popupStack =
02189 GetMythMainWindow()->GetStack("popup stack");
02190 MythUISearchDialog *searchDialog = new MythUISearchDialog(popupStack,
02191 tr("Video Search"), childList, false, "");
02192
02193 if (searchDialog->Create())
02194 {
02195 connect(searchDialog, SIGNAL(haveResult(QString)),
02196 SLOT(searchComplete(QString)));
02197
02198 popupStack->AddScreen(searchDialog);
02199 }
02200 else
02201 delete searchDialog;
02202 }
02203
02208 bool VideoDialog::goBack()
02209 {
02210 bool handled = false;
02211
02212 if (m_d->m_currentNode != m_d->m_rootNode)
02213 {
02214 MythGenericTree *lparent = m_d->m_currentNode->getParent();
02215 if (lparent)
02216 {
02217 SetCurrentNode(lparent);
02218
02219 handled = true;
02220 }
02221 }
02222
02223 loadData();
02224
02225 return handled;
02226 }
02227
02232 void VideoDialog::SetCurrentNode(MythGenericTree *node)
02233 {
02234 if (!node)
02235 return;
02236
02237 m_d->m_currentNode = node;
02238 }
02239
02244 void VideoDialog::UpdatePosition()
02245 {
02246 MythUIButtonListItem *ci = GetItemCurrent();
02247 MythUIButtonList *currentList = ci ? ci->parent() : 0;
02248
02249 if (!currentList)
02250 return;
02251
02252 CheckedSet(m_positionText, QString(tr("%1 of %2"))
02253 .arg(currentList->GetCurrentPos() + 1)
02254 .arg(currentList->GetCount()));
02255 }
02256
02261 void VideoDialog::UpdateText(MythUIButtonListItem *item)
02262 {
02263 if (!item)
02264 return;
02265
02266 MythUIButtonList *currentList = item->parent();
02267
02268 if (!currentList)
02269 return;
02270
02271 VideoMetadata *metadata = GetMetadata(item);
02272
02273 MythGenericTree *node = GetNodePtrFromButton(item);
02274
02275 if (!node)
02276 return;
02277
02278 if (metadata)
02279 {
02280 MetadataMap metadataMap;
02281 metadata->toMap(metadataMap);
02282 SetTextFromMap(metadataMap);
02283 }
02284 else
02285 {
02286 MetadataMap metadataMap;
02287 ClearMap(metadataMap);
02288 SetTextFromMap(metadataMap);
02289 }
02290
02291 ScreenCopyDest dest(this);
02292 CopyMetadataToUI(metadata, dest);
02293
02294 if (node->getInt() == kSubFolder && !metadata)
02295 {
02296 QString cover = GetFirstImage(node, "Coverart");
02297 QString fanart = GetFirstImage(node, "Fanart");
02298 QString banner = GetFirstImage(node, "Banners");
02299 QString screenshot = GetFirstImage(node, "Screenshots");
02300 CheckedSet(m_coverImage, cover);
02301 CheckedSet(m_fanart, fanart);
02302 CheckedSet(m_banner, banner);
02303 CheckedSet(m_screenshot, screenshot);
02304 }
02305
02306 if (!metadata)
02307 CheckedSet(m_titleText, item->GetText());
02308 UpdatePosition();
02309
02310 if (m_d->m_currentNode)
02311 {
02312 CheckedSet(m_crumbText, m_d->m_currentNode->getRouteByString().join(" > "));
02313 CheckedSet(this, "foldername", m_d->m_currentNode->getString());
02314 }
02315
02316 if (node && node->getInt() == kSubFolder)
02317 CheckedSet(this, "childcount",
02318 QString("%1").arg(node->visibleChildCount()));
02319
02320 if (node)
02321 node->becomeSelectedChild();
02322 }
02323
02328 void VideoDialog::VideoMenu()
02329 {
02330 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02331 QString label;
02332
02333 if (metadata)
02334 {
02335 if (!metadata->GetSubtitle().isEmpty())
02336 label = tr("Video Options\n%1\n%2").arg(metadata->GetTitle())
02337 .arg(metadata->GetSubtitle());
02338 else
02339 label = tr("Video Options\n%1").arg(metadata->GetTitle());
02340 }
02341 else
02342 label = tr("Video Options");
02343
02344 MythMenu *menu = new MythMenu(label, this, "actions");
02345
02346 MythUIButtonListItem *item = GetItemCurrent();
02347 MythGenericTree *node = GetNodePtrFromButton(item);
02348 if (metadata)
02349 {
02350 if (!metadata->GetTrailer().isEmpty() ||
02351 gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0) ||
02352 m_d->m_altPlayerEnabled)
02353 menu->AddItem(tr("Play..."), NULL, CreatePlayMenu());
02354 else
02355 menu->AddItem(tr("Play"), SLOT(playVideo()));
02356 if (metadata->GetWatched())
02357 menu->AddItem(tr("Mark as Unwatched"), SLOT(ToggleWatched()));
02358 else
02359 menu->AddItem(tr("Mark as Watched"), SLOT(ToggleWatched()));
02360 menu->AddItem(tr("Video Info"), NULL, CreateInfoMenu());
02361 menu->AddItem(tr("Change Video Details"), NULL, CreateManageMenu());
02362 menu->AddItem(tr("Delete"), SLOT(RemoveVideo()));
02363 }
02364 else if (node && node->getInt() != kUpFolder)
02365 {
02366 menu->AddItem(tr("Play Folder"), SLOT(playFolder()));
02367 }
02368
02369
02370 m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
02371
02372 if (m_menuPopup->Create())
02373 m_popupStack->AddScreen(m_menuPopup);
02374 else
02375 delete m_menuPopup;
02376 }
02377
02383 MythMenu* VideoDialog::CreatePlayMenu()
02384 {
02385 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02386 QString label;
02387
02388 if (metadata)
02389 label = tr("Playback Options\n%1").arg(metadata->GetTitle());
02390 else
02391 return NULL;
02392
02393 MythMenu *menu = new MythMenu(label, this, "actions");
02394
02395 menu->AddItem(tr("Play"), SLOT(playVideo()));
02396
02397 if (m_d->m_altPlayerEnabled)
02398 {
02399 menu->AddItem(tr("Play in Alternate Player"), SLOT(playVideoAlt()));
02400 }
02401
02402 if (gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0))
02403 {
02404 menu->AddItem(tr("Play With Trailers"), SLOT(playVideoWithTrailers()));
02405 }
02406
02407 QString trailerFile = metadata->GetTrailer();
02408 if (QFile::exists(trailerFile) ||
02409 (!metadata->GetHost().isEmpty() && !trailerFile.isEmpty()))
02410 {
02411 menu->AddItem(tr("Play Trailer"), SLOT(playTrailer()));
02412 }
02413
02414 return menu;
02415 }
02416
02421 void VideoDialog::DisplayMenu()
02422 {
02423 QString label = tr("Video Display Menu");
02424
02425 MythMenu *menu = new MythMenu(label, this, "display");
02426
02427 menu->AddItem(tr("Scan For Changes"), SLOT(doVideoScan()));
02428 menu->AddItem(tr("Retrieve All Details"), SLOT(VideoAutoSearch()));
02429 menu->AddItem(tr("Filter Display"), SLOT(ChangeFilter()));
02430 menu->AddItem(tr("Browse By..."), NULL, CreateMetadataBrowseMenu());
02431 menu->AddItem(tr("Change View"), NULL, CreateViewMenu());
02432 menu->AddItem(tr("Settings"), NULL, CreateSettingsMenu());
02433
02434 m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
02435
02436 if (m_menuPopup->Create())
02437 m_popupStack->AddScreen(m_menuPopup);
02438 else
02439 delete m_menuPopup;
02440 }
02441
02446 MythMenu* VideoDialog::CreateViewMenu()
02447 {
02448 QString label = tr("Change View");
02449
02450 MythMenu *menu = new MythMenu(label, this, "view");
02451
02452 if (!(m_d->m_type & DLG_BROWSER))
02453 menu->AddItem(tr("Switch to Browse View"), SLOT(SwitchBrowse()));
02454
02455 if (!(m_d->m_type & DLG_GALLERY))
02456 menu->AddItem(tr("Switch to Gallery View"), SLOT(SwitchGallery()));
02457
02458 if (!(m_d->m_type & DLG_TREE))
02459 menu->AddItem(tr("Switch to List View"), SLOT(SwitchTree()));
02460
02461 if (!(m_d->m_type & DLG_MANAGER))
02462 menu->AddItem(tr("Switch to Manage View"), SLOT(SwitchManager()));
02463
02464 if (m_d->m_isFlatList)
02465 menu->AddItem(tr("Show Directory Structure"), SLOT(ToggleFlatView()));
02466 else
02467 menu->AddItem(tr("Hide Directory Structure"), SLOT(ToggleFlatView()));
02468
02469 if (m_d->m_isFileBrowser)
02470 menu->AddItem(tr("Browse Library (recommended)"), SLOT(ToggleBrowseMode()));
02471 else
02472 menu->AddItem(tr("Browse Filesystem (slow)"), SLOT(ToggleBrowseMode()));
02473
02474
02475 return menu;
02476 }
02477
02482 MythMenu* VideoDialog::CreateSettingsMenu()
02483 {
02484 QString label = tr("Video Settings");
02485
02486 MythMenu *menu = new MythMenu(label, this, "settings");
02487
02488 menu->AddItem(tr("Player Settings"), SLOT(ShowPlayerSettings()));
02489 menu->AddItem(tr("Metadata Settings"), SLOT(ShowMetadataSettings()));
02490 menu->AddItem(tr("File Type Settings"), SLOT(ShowExtensionSettings()));
02491
02492 return menu;
02493 }
02494
02499 void VideoDialog::ShowPlayerSettings()
02500 {
02501 PlayerSettings *ps = new PlayerSettings(m_mainStack, "player settings");
02502
02503 if (ps->Create())
02504 m_mainStack->AddScreen(ps);
02505 else
02506 delete ps;
02507 }
02508
02513 void VideoDialog::ShowMetadataSettings()
02514 {
02515 MetadataSettings *ms = new MetadataSettings(m_mainStack, "metadata settings");
02516
02517 if (ms->Create())
02518 m_mainStack->AddScreen(ms);
02519 else
02520 delete ms;
02521 }
02522
02527 void VideoDialog::ShowExtensionSettings()
02528 {
02529 FileAssocDialog *fa = new FileAssocDialog(m_mainStack, "fa dialog");
02530
02531 if (fa->Create())
02532 m_mainStack->AddScreen(fa);
02533 else
02534 delete fa;
02535 }
02536
02541 MythMenu* VideoDialog::CreateMetadataBrowseMenu()
02542 {
02543 QString label = tr("Browse By");
02544
02545 MythMenu *menu = new MythMenu(label, this, "metadata");
02546
02547 if (m_d->m_groupType != BRS_CAST)
02548 menu->AddItem(tr("Cast"), SLOT(SwitchVideoCastGroup()));
02549
02550 if (m_d->m_groupType != BRS_CATEGORY)
02551 menu->AddItem(tr("Category"), SLOT(SwitchVideoCategoryGroup()));
02552
02553 if (m_d->m_groupType != BRS_INSERTDATE)
02554 menu->AddItem(tr("Date Added"), SLOT(SwitchVideoInsertDateGroup()));
02555
02556 if (m_d->m_groupType != BRS_DIRECTOR)
02557 menu->AddItem(tr("Director"), SLOT(SwitchVideoDirectorGroup()));
02558
02559 if (m_d->m_groupType != BRS_STUDIO)
02560 menu->AddItem(tr("Studio"), SLOT(SwitchVideoStudioGroup()));
02561
02562 if (m_d->m_groupType != BRS_FOLDER)
02563 menu->AddItem(tr("Folder"), SLOT(SwitchVideoFolderGroup()));
02564
02565 if (m_d->m_groupType != BRS_GENRE)
02566 menu->AddItem(tr("Genre"), SLOT(SwitchVideoGenreGroup()));
02567
02568 if (m_d->m_groupType != BRS_TVMOVIE)
02569 menu->AddItem(tr("TV/Movies"),SLOT(SwitchVideoTVMovieGroup()));
02570
02571 if (m_d->m_groupType != BRS_USERRATING)
02572 menu->AddItem(tr("User Rating"), SLOT(SwitchVideoUserRatingGroup()));
02573
02574 if (m_d->m_groupType != BRS_YEAR)
02575 menu->AddItem(tr("Year"), SLOT(SwitchVideoYearGroup()));
02576
02577 return menu;
02578 }
02579
02584 MythMenu *VideoDialog::CreateInfoMenu()
02585 {
02586 QString label = tr("Video Info");
02587
02588 MythMenu *menu = new MythMenu(label, this, "info");
02589
02590 if (ItemDetailPopup::Exists())
02591 menu->AddItem(tr("View Details"), SLOT(DoItemDetailShow()));
02592
02593 menu->AddItem(tr("View Full Plot"), SLOT(ViewPlot()));
02594
02595 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02596 if (metadata)
02597 {
02598 if (!metadata->GetCast().empty())
02599 menu->AddItem(tr("View Cast"), SLOT(ShowCastDialog()));
02600 if (!metadata->GetHomepage().isEmpty())
02601 menu->AddItem(tr("View Homepage"), SLOT(ShowHomepage()));
02602 }
02603
02604 return menu;
02605 }
02606
02611 MythMenu *VideoDialog::CreateManageMenu()
02612 {
02613 QString label = tr("Manage Video Details");
02614
02615 MythMenu *menu = new MythMenu(label, this, "manage");
02616
02617 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02618
02619 menu->AddItem(tr("Edit Details"), SLOT(EditMetadata()));
02620 menu->AddItem(tr("Retrieve Details"), SLOT(VideoSearch()));
02621 if (metadata->GetProcessed())
02622 menu->AddItem(tr("Allow Updates"), SLOT(ToggleProcess()));
02623 else
02624 menu->AddItem(tr("Disable Updates"), SLOT(ToggleProcess()));
02625 menu->AddItem(tr("Reset Details"), SLOT(ResetMetadata()));
02626
02627 return menu;
02628 }
02629
02630 void VideoDialog::ToggleProcess()
02631 {
02632 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02633 if (metadata)
02634 {
02635 metadata->SetProcessed(!metadata->GetProcessed());
02636 metadata->UpdateDatabase();
02637
02638 refreshData();
02639 }
02640 }
02641
02646 void VideoDialog::ToggleBrowseMode()
02647 {
02648 m_d->m_isFileBrowser = !m_d->m_isFileBrowser;
02649 gCoreContext->SaveSetting("VideoDialogNoDB",
02650 QString("%1").arg((int)m_d->m_isFileBrowser));
02651 reloadData();
02652 }
02653
02658 void VideoDialog::ToggleFlatView()
02659 {
02660 m_d->m_isFlatList = !m_d->m_isFlatList;
02661 gCoreContext->SaveSetting(QString("mythvideo.folder_view_%1").arg(m_d->m_type),
02662 QString("%1").arg((int)m_d->m_isFlatList));
02663
02664
02665
02666 reloadData();
02667 }
02668
02673 void VideoDialog::handleDirSelect(MythGenericTree *node)
02674 {
02675 SetCurrentNode(node);
02676 loadData();
02677 }
02678
02683 void VideoDialog::handleDynamicDirSelect(MythGenericTree *node)
02684 {
02685 QStringList route = node->getRouteByString();
02686 if (m_d->m_videoList && m_d->m_videoList->refreshNode(node))
02687 reloadData();
02688 m_videoButtonTree->SetNodeByString(route);
02689 }
02690
02695 void VideoDialog::handleSelect(MythUIButtonListItem *item)
02696 {
02697 MythGenericTree *node = GetNodePtrFromButton(item);
02698 int nodeInt = node->getInt();
02699
02700 switch (nodeInt)
02701 {
02702 case kDynamicSubFolder:
02703 handleDynamicDirSelect(node);
02704 break;
02705 case kSubFolder:
02706 handleDirSelect(node);
02707 break;
02708 case kUpFolder:
02709 goBack();
02710 break;
02711 default:
02712 {
02713 bool doPlay = true;
02714 if (m_d->m_type == DLG_GALLERY)
02715 {
02716 doPlay = !DoItemDetailShow();
02717 }
02718
02719 if (doPlay)
02720 playVideo();
02721 }
02722 };
02723 }
02724
02729 void VideoDialog::SwitchTree()
02730 {
02731 SwitchLayout(DLG_TREE, m_d->m_browse);
02732 }
02733
02738 void VideoDialog::SwitchGallery()
02739 {
02740 SwitchLayout(DLG_GALLERY, m_d->m_browse);
02741 }
02742
02747 void VideoDialog::SwitchBrowse()
02748 {
02749 SwitchLayout(DLG_BROWSER, m_d->m_browse);
02750 }
02751
02756 void VideoDialog::SwitchManager()
02757 {
02758 SwitchLayout(DLG_MANAGER, m_d->m_browse);
02759 }
02760
02765 void VideoDialog::SwitchVideoFolderGroup()
02766 {
02767 SwitchLayout(m_d->m_type, BRS_FOLDER);
02768 }
02769
02774 void VideoDialog::SwitchVideoGenreGroup()
02775 {
02776 SwitchLayout(m_d->m_type, BRS_GENRE);
02777 }
02778
02783 void VideoDialog::SwitchVideoCategoryGroup()
02784 {
02785 SwitchLayout(m_d->m_type, BRS_CATEGORY);
02786 }
02787
02792 void VideoDialog::SwitchVideoYearGroup()
02793 {
02794 SwitchLayout(m_d->m_type, BRS_YEAR);
02795 }
02796
02801 void VideoDialog::SwitchVideoDirectorGroup()
02802 {
02803 SwitchLayout(m_d->m_type, BRS_DIRECTOR);
02804 }
02805
02810 void VideoDialog::SwitchVideoStudioGroup()
02811 {
02812 SwitchLayout(m_d->m_type, BRS_STUDIO);
02813 }
02814
02819 void VideoDialog::SwitchVideoCastGroup()
02820 {
02821 SwitchLayout(m_d->m_type, BRS_CAST);
02822 }
02823
02828 void VideoDialog::SwitchVideoUserRatingGroup()
02829 {
02830 SwitchLayout(m_d->m_type, BRS_USERRATING);
02831 }
02832
02837 void VideoDialog::SwitchVideoInsertDateGroup()
02838 {
02839 SwitchLayout(m_d->m_type, BRS_INSERTDATE);
02840 }
02841
02846 void VideoDialog::SwitchVideoTVMovieGroup()
02847 {
02848 SwitchLayout(m_d->m_type, BRS_TVMOVIE);
02849 }
02850
02855 void VideoDialog::SwitchLayout(DialogType type, BrowseType browse)
02856 {
02857 m_d->m_switchingLayout = true;
02858
02859
02860 SavePosition();
02861
02862 VideoDialog *mythvideo =
02863 new VideoDialog(GetMythMainWindow()->GetMainStack(), "mythvideo",
02864 m_d->m_videoList, type, browse);
02865
02866 if (mythvideo->Create())
02867 {
02868 gCoreContext->SaveSetting("Default MythVideo View", type);
02869 gCoreContext->SaveSetting("mythvideo.db_group_type", browse);
02870 MythScreenStack *screenStack = GetScreenStack();
02871 screenStack->AddScreen(mythvideo);
02872 screenStack->PopScreen(this, false, false);
02873 deleteLater();
02874 }
02875 else
02876 {
02877 ShowOkPopup(tr("An error occurred when switching views."));
02878 }
02879 }
02880
02885 void VideoDialog::ViewPlot()
02886 {
02887 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02888
02889 PlotDialog *plotdialog = new PlotDialog(m_popupStack, metadata);
02890
02891 if (plotdialog->Create())
02892 m_popupStack->AddScreen(plotdialog);
02893 }
02894
02899 bool VideoDialog::DoItemDetailShow()
02900 {
02901 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02902
02903 if (metadata)
02904 {
02905 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
02906 ItemDetailPopup *idp = new ItemDetailPopup(mainStack, metadata,
02907 m_d->m_videoList->getListCache());
02908
02909 if (idp->Create())
02910 {
02911 mainStack->AddScreen(idp);
02912 return true;
02913 }
02914 }
02915
02916 return false;
02917 }
02918
02923 void VideoDialog::ShowCastDialog()
02924 {
02925 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02926
02927 CastDialog *castdialog = new CastDialog(m_popupStack, metadata);
02928
02929 if (castdialog->Create())
02930 m_popupStack->AddScreen(castdialog);
02931 }
02932
02933 void VideoDialog::ShowHomepage()
02934 {
02935 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02936
02937 if (!metadata)
02938 return;
02939
02940 QString url = metadata->GetHomepage();
02941
02942 if (url.isEmpty())
02943 return;
02944
02945 QString browser = gCoreContext->GetSetting("WebBrowserCommand", "");
02946 QString zoom = gCoreContext->GetSetting("WebBrowserZoomLevel", "1.0");
02947
02948 if (browser.isEmpty())
02949 {
02950 ShowOkPopup(tr("No browser command set! MythVideo needs MythBrowser "
02951 "installed to display the homepage."));
02952 return;
02953 }
02954
02955 if (browser.toLower() == "internal")
02956 {
02957 GetMythMainWindow()->HandleMedia("WebBrowser", url);
02958 return;
02959 }
02960 else
02961 {
02962 QString cmd = browser;
02963 cmd.replace("%ZOOM%", zoom);
02964 cmd.replace("%URL%", url);
02965 cmd.replace('\'', "%27");
02966 cmd.replace("&","\\&");
02967 cmd.replace(";","\\;");
02968
02969 GetMythMainWindow()->AllowInput(false);
02970 myth_system(cmd, kMSDontDisableDrawing);
02971 GetMythMainWindow()->AllowInput(true);
02972 return;
02973 }
02974 }
02975
02980 void VideoDialog::playVideo()
02981 {
02982 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02983 if (metadata)
02984 PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
02985 }
02986
02991 void VideoDialog::playVideoAlt()
02992 {
02993 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02994 if (metadata)
02995 PlayVideo(metadata->GetFilename(),
02996 m_d->m_videoList->getListCache(), true);
02997 }
02998
03003 void VideoDialog::playFolder()
03004 {
03005 const int WATCHED_WATERMARK = 10000;
03006
03007
03008 QTime playing_time;
03009
03010 MythUIButtonListItem *item = GetItemCurrent();
03011 MythGenericTree *node = GetNodePtrFromButton(item);
03012 int list_count;
03013
03014 if (node && !(node->getInt() >= 0))
03015 list_count = node->childCount();
03016 else
03017 return;
03018
03019 if (list_count > 0)
03020 {
03021 bool video_started = false;
03022 int i = 0;
03023 while (i < list_count &&
03024 (!video_started || playing_time.elapsed() > WATCHED_WATERMARK))
03025 {
03026 MythGenericTree *subnode = node->getChildAt(i);
03027 if (subnode)
03028 {
03029 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
03030 if (metadata)
03031 {
03032 playing_time.start();
03033 video_started = true;
03034 PlayVideo(metadata->GetFilename(),
03035 m_d->m_videoList->getListCache());
03036 }
03037 }
03038 i++;
03039 }
03040 }
03041 }
03042
03043 namespace
03044 {
03045 struct SimpleCollect : public DirectoryHandler
03046 {
03047 SimpleCollect(QStringList &fileList) : m_fileList(fileList) {}
03048
03049 DirectoryHandler *newDir(const QString &dirName,
03050 const QString &fqDirName)
03051 {
03052 (void) dirName;
03053 (void) fqDirName;
03054 return this;
03055 }
03056
03057 void handleFile(const QString &fileName, const QString &fqFileName,
03058 const QString &extension, const QString &host)
03059 {
03060 (void) fileName;
03061 (void) extension;
03062 (void) host;
03063 m_fileList.push_back(fqFileName);
03064 }
03065
03066 private:
03067 QStringList &m_fileList;
03068 };
03069
03070 QStringList GetTrailersInDirectory(const QString &startDir)
03071 {
03072 FileAssociations::ext_ignore_list extensions;
03073 FileAssociations::getFileAssociation()
03074 .getExtensionIgnoreList(extensions);
03075 QStringList ret;
03076 SimpleCollect sc(ret);
03077
03078 (void) ScanVideoDirectory(startDir, &sc, extensions, false);
03079 return ret;
03080 }
03081 }
03082
03087 void VideoDialog::playVideoWithTrailers()
03088 {
03089 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03090 if (!metadata) return;
03091
03092 QStringList trailers = GetTrailersInDirectory(gCoreContext->
03093 GetSetting("mythvideo.TrailersDir"));
03094
03095 if (trailers.isEmpty())
03096 return;
03097
03098 const int trailersToPlay =
03099 gCoreContext->GetNumSetting("mythvideo.TrailersRandomCount");
03100
03101 int i = 0;
03102 while (!trailers.isEmpty() && i < trailersToPlay)
03103 {
03104 ++i;
03105 QString trailer = trailers.takeAt(random() % trailers.size());
03106
03107 LOG(VB_GENERAL, LOG_DEBUG,
03108 QString("Random trailer to play will be: %1").arg(trailer));
03109
03110 VideoPlayerCommand::PlayerFor(trailer).Play();
03111 }
03112
03113 PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
03114 }
03115
03120 void VideoDialog::playTrailer()
03121 {
03122 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03123 if (!metadata) return;
03124 QString url;
03125
03126 if (metadata->IsHostSet() && !metadata->GetTrailer().startsWith("/"))
03127 url = generate_file_url("Trailers", metadata->GetHost(),
03128 metadata->GetTrailer());
03129 else
03130 url = metadata->GetTrailer();
03131
03132 VideoPlayerCommand::PlayerFor(url).Play();
03133 }
03134
03139 void VideoDialog::setParentalLevel(const ParentalLevel::Level &level)
03140 {
03141 m_d->m_parentalLevel.SetLevel(level);
03142 }
03143
03148 void VideoDialog::shiftParental(int amount)
03149 {
03150 setParentalLevel(ParentalLevel(m_d->m_parentalLevel.GetLevel()
03151 .GetLevel() + amount).GetLevel());
03152 }
03153
03158 void VideoDialog::ChangeFilter()
03159 {
03160 MythScreenStack *mainStack = GetScreenStack();
03161
03162 VideoFilterDialog *filterdialog = new VideoFilterDialog(mainStack,
03163 "videodialogfilters", m_d->m_videoList.get());
03164
03165 if (filterdialog->Create())
03166 mainStack->AddScreen(filterdialog);
03167
03168 connect(filterdialog, SIGNAL(filterChanged()), SLOT(reloadData()));
03169 }
03170
03175 VideoMetadata *VideoDialog::GetMetadata(MythUIButtonListItem *item)
03176 {
03177 VideoMetadata *metadata = NULL;
03178
03179 if (item)
03180 {
03181 MythGenericTree *node = GetNodePtrFromButton(item);
03182 if (node)
03183 {
03184 int nodeInt = node->getInt();
03185
03186 if (nodeInt >= 0)
03187 metadata = GetMetadataPtrFromNode(node);
03188 }
03189 }
03190
03191 return metadata;
03192 }
03193
03194 void VideoDialog::customEvent(QEvent *levent)
03195 {
03196 if (levent->type() == MetadataFactoryMultiResult::kEventType)
03197 {
03198 MetadataFactoryMultiResult *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent);
03199
03200 if (!mfmr)
03201 return;
03202
03203 MetadataLookupList list = mfmr->results;
03204
03205 if (m_busyPopup)
03206 {
03207 m_busyPopup->Close();
03208 m_busyPopup = NULL;
03209 }
03210
03211 if (list.count() > 1)
03212 {
03213 MetadataResultsDialog *resultsdialog =
03214 new MetadataResultsDialog(m_popupStack, list);
03215
03216 connect(resultsdialog, SIGNAL(haveResult(MetadataLookup*)),
03217 SLOT(OnVideoSearchListSelection(MetadataLookup*)),
03218 Qt::QueuedConnection);
03219
03220 if (resultsdialog->Create())
03221 m_popupStack->AddScreen(resultsdialog);
03222 }
03223 }
03224 else if (levent->type() == MetadataFactorySingleResult::kEventType)
03225 {
03226 MetadataFactorySingleResult *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent);
03227
03228 if (!mfsr)
03229 return;
03230
03231 MetadataLookup *lookup = mfsr->result;
03232
03233 if (!lookup)
03234 return;
03235
03236 OnVideoSearchDone(lookup);
03237 }
03238 else if (levent->type() == MetadataFactoryNoResult::kEventType)
03239 {
03240 MetadataFactoryNoResult *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent);
03241
03242 if (!mfnr)
03243 return;
03244
03245 MetadataLookup *lookup = mfnr->result;
03246
03247 if (!lookup)
03248 return;
03249
03250 if (m_busyPopup)
03251 {
03252 m_busyPopup->Close();
03253 m_busyPopup = NULL;
03254 }
03255
03256 VideoMetadata *metadata =
03257 qVariantValue<VideoMetadata *>(lookup->GetData());
03258 if (metadata)
03259 {
03260 metadata->SetProcessed(true);
03261 metadata->UpdateDatabase();
03262 }
03263 LOG(VB_GENERAL, LOG_INFO,
03264 QString("No results found for %1 %2 %3").arg(lookup->GetTitle())
03265 .arg(lookup->GetSeason()).arg(lookup->GetEpisode()));
03266 }
03267 else if (levent->type() == DialogCompletionEvent::kEventType)
03268 {
03269 DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(levent);
03270 QString id = dce->GetId();
03271
03272 if (id == "scanprompt")
03273 {
03274 int result = dce->GetResult();
03275 if (result == 1)
03276 doVideoScan();
03277 }
03278 else
03279 m_menuPopup = NULL;
03280 }
03281 }
03282
03283 void VideoDialog::OnVideoImageSetDone(VideoMetadata *metadata)
03284 {
03285
03286 if (m_busyPopup)
03287 {
03288 m_busyPopup->Close();
03289 m_busyPopup = NULL;
03290 }
03291
03292 metadata->SetProcessed(true);
03293 metadata->UpdateDatabase();
03294
03295 MythUIButtonListItem *item = GetItemByMetadata(metadata);
03296 if (item != NULL)
03297 UpdateItem(item);
03298 }
03299
03300 MythUIButtonListItem *VideoDialog::GetItemCurrent()
03301 {
03302 if (m_videoButtonTree)
03303 {
03304 return m_videoButtonTree->GetItemCurrent();
03305 }
03306
03307 return m_videoButtonList->GetItemCurrent();
03308 }
03309
03310 MythUIButtonListItem *VideoDialog::GetItemByMetadata(VideoMetadata *metadata)
03311 {
03312 if (m_videoButtonTree)
03313 {
03314 return m_videoButtonTree->GetItemCurrent();
03315 }
03316
03317 QList<MythGenericTree*>::iterator it;
03318 QList<MythGenericTree*> *children;
03319 QMap<int, int> idPosition;
03320
03321 children = m_d->m_currentNode->getAllChildren();
03322
03323 for (it = children->begin(); it != children->end(); ++it)
03324 {
03325 MythGenericTree *child = *it;
03326 int nodeInt = child->getInt();
03327 if (nodeInt != kSubFolder && nodeInt != kUpFolder)
03328 {
03329 VideoMetadata *listmeta =
03330 GetMetadataPtrFromNode(child);
03331 if (listmeta)
03332 {
03333 int position = child->getPosition();
03334 int id = listmeta->GetID();
03335 idPosition.insert(id, position);
03336 }
03337 }
03338 }
03339
03340 return m_videoButtonList->GetItemAt(idPosition.value(metadata->GetID()));
03341 }
03342
03343 void VideoDialog::VideoSearch(MythGenericTree *node,
03344 bool automode)
03345 {
03346 if (!node)
03347 node = GetNodePtrFromButton(GetItemCurrent());
03348
03349 if (!node)
03350 return;
03351
03352 VideoMetadata *metadata = GetMetadataPtrFromNode(node);
03353
03354 if (!metadata)
03355 return;
03356
03357 m_metadataFactory->Lookup(metadata, automode, true);
03358
03359 if (!automode)
03360 {
03361 QString msg = tr("Fetching details for %1")
03362 .arg(metadata->GetTitle());
03363 if (!metadata->GetSubtitle().isEmpty())
03364 msg += QString(": %1").arg(metadata->GetSubtitle());
03365 if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
03366 msg += tr(" %1x%2").arg(metadata->GetSeason())
03367 .arg(metadata->GetEpisode());
03368 createBusyDialog(msg);
03369 }
03370 }
03371
03372 void VideoDialog::VideoAutoSearch(MythGenericTree *node)
03373 {
03374 if (!node)
03375 node = m_d->m_rootNode;
03376 typedef QList<MythGenericTree *> MGTreeChildList;
03377 MGTreeChildList *lchildren = node->getAllChildren();
03378
03379 LOG(VB_GENERAL, LOG_DEBUG,
03380 QString("Fetching details in %1").arg(node->getString()));
03381
03382 for (MGTreeChildList::const_iterator p = lchildren->begin();
03383 p != lchildren->end(); ++p)
03384 {
03385 if (((*p)->getInt() == kSubFolder) ||
03386 ((*p)->getInt() == kUpFolder))
03387 VideoAutoSearch((*p));
03388 else
03389 {
03390 VideoMetadata *metadata = GetMetadataPtrFromNode((*p));
03391
03392 if (!metadata)
03393 continue;
03394
03395 if (!metadata->GetProcessed())
03396 VideoSearch((*p), true);
03397 }
03398 }
03399 }
03400
03401 void VideoDialog::ToggleWatched()
03402 {
03403 MythUIButtonListItem *item = GetItemCurrent();
03404 if (!item)
03405 return;
03406
03407 VideoMetadata *metadata = GetMetadata(item);
03408 if (metadata)
03409 {
03410 metadata->SetWatched(!metadata->GetWatched());
03411 metadata->UpdateDatabase();
03412 item->DisplayState(WatchedToState(metadata->GetWatched()),
03413 "watchedstate");
03414 }
03415 }
03416
03417 void VideoDialog::OnVideoSearchListSelection(MetadataLookup *lookup)
03418 {
03419 if (!lookup)
03420 return;
03421
03422 lookup->SetStep(kLookupData);
03423 m_metadataFactory->Lookup(lookup);
03424 }
03425
03426 void VideoDialog::OnParentalChange(int amount)
03427 {
03428 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03429 if (metadata)
03430 {
03431 ParentalLevel curshowlevel = metadata->GetShowLevel();
03432
03433 curshowlevel += amount;
03434
03435 if (curshowlevel.GetLevel() != metadata->GetShowLevel())
03436 {
03437 metadata->SetShowLevel(curshowlevel.GetLevel());
03438 metadata->UpdateDatabase();
03439 refreshData();
03440 }
03441 }
03442 }
03443
03444 void VideoDialog::EditMetadata()
03445 {
03446 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03447 if (!metadata)
03448 return;
03449
03450 MythScreenStack *screenStack = GetScreenStack();
03451
03452 EditMetadataDialog *md_editor = new EditMetadataDialog(screenStack,
03453 "mythvideoeditmetadata", metadata,
03454 m_d->m_videoList->getListCache());
03455
03456 connect(md_editor, SIGNAL(Finished()), SLOT(refreshData()));
03457
03458 if (md_editor->Create())
03459 screenStack->AddScreen(md_editor);
03460 }
03461
03462 void VideoDialog::RemoveVideo()
03463 {
03464 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03465
03466 if (!metadata)
03467 return;
03468
03469 QString message = tr("Are you sure you want to permanently delete:\n%1")
03470 .arg(metadata->GetTitle());
03471
03472 MythConfirmationDialog *confirmdialog =
03473 new MythConfirmationDialog(m_popupStack,message);
03474
03475 if (confirmdialog->Create())
03476 m_popupStack->AddScreen(confirmdialog);
03477
03478 connect(confirmdialog, SIGNAL(haveResult(bool)),
03479 SLOT(OnRemoveVideo(bool)));
03480 }
03481
03482 void VideoDialog::OnRemoveVideo(bool dodelete)
03483 {
03484 if (!dodelete)
03485 return;
03486
03487 MythUIButtonListItem *item = GetItemCurrent();
03488 MythGenericTree *gtItem = GetNodePtrFromButton(item);
03489
03490 VideoMetadata *metadata = GetMetadata(item);
03491
03492 if (!metadata)
03493 return;
03494
03495 if (m_d->m_videoList->Delete(metadata->GetID()))
03496 {
03497 if (m_videoButtonTree)
03498 m_videoButtonTree->RemoveItem(item, false);
03499 else
03500 m_videoButtonList->RemoveItem(item);
03501
03502 MythGenericTree *parent = gtItem->getParent();
03503 parent->deleteNode(gtItem);
03504 }
03505 else
03506 {
03507 QString message = tr("Failed to delete file");
03508
03509 MythConfirmationDialog *confirmdialog =
03510 new MythConfirmationDialog(m_popupStack,message,false);
03511
03512 if (confirmdialog->Create())
03513 m_popupStack->AddScreen(confirmdialog);
03514 }
03515 }
03516
03517 void VideoDialog::ResetMetadata()
03518 {
03519 MythUIButtonListItem *item = GetItemCurrent();
03520 VideoMetadata *metadata = GetMetadata(item);
03521
03522 if (metadata)
03523 {
03524 metadata->Reset();
03525 metadata->UpdateDatabase();
03526 UpdateItem(item);
03527 }
03528 }
03529
03530 void VideoDialog::StartVideoImageSet(VideoMetadata *metadata)
03531 {
03532 if (!metadata)
03533 return;
03534
03535 QStringList cover_dirs;
03536 cover_dirs += m_d->m_artDir;
03537
03538 QString cover_file;
03539 QString inetref = metadata->GetInetRef();
03540 QString filename = metadata->GetFilename();
03541 QString title = metadata->GetTitle();
03542 int season = metadata->GetSeason();
03543 QString host = metadata->GetHost();
03544 int episode = metadata->GetEpisode();
03545
03546 if (metadata->GetCoverFile().isEmpty() ||
03547 IsDefaultCoverFile(metadata->GetCoverFile()))
03548 {
03549 if (GetLocalVideoImage(inetref, filename,
03550 cover_dirs, cover_file, title,
03551 season, host, "Coverart", episode))
03552 {
03553 metadata->SetCoverFile(cover_file);
03554 OnVideoImageSetDone(metadata);
03555 }
03556 }
03557
03558 QStringList fanart_dirs;
03559 fanart_dirs += m_d->m_fanDir;
03560
03561 QString fanart_file;
03562
03563 if (metadata->GetFanart().isEmpty())
03564 {
03565 if (GetLocalVideoImage(inetref, filename,
03566 fanart_dirs, fanart_file, title,
03567 season, host, "Fanart", episode))
03568 {
03569 metadata->SetFanart(fanart_file);
03570 OnVideoImageSetDone(metadata);
03571 }
03572 }
03573
03574 QStringList banner_dirs;
03575 banner_dirs += m_d->m_banDir;
03576
03577 QString banner_file;
03578
03579 if (metadata->GetBanner().isEmpty())
03580 {
03581 if (GetLocalVideoImage(inetref, filename,
03582 banner_dirs, banner_file, title,
03583 season, host, "Banners", episode))
03584 {
03585 metadata->SetBanner(banner_file);
03586 OnVideoImageSetDone(metadata);
03587 }
03588 }
03589
03590 QStringList screenshot_dirs;
03591 screenshot_dirs += m_d->m_sshotDir;
03592
03593 QString screenshot_file;
03594
03595 if (metadata->GetScreenshot().isEmpty())
03596 {
03597 if (GetLocalVideoImage(inetref, filename,
03598 screenshot_dirs, screenshot_file, title,
03599 season, host, "Screenshots", episode,
03600 true))
03601 {
03602 metadata->SetScreenshot(screenshot_file);
03603 OnVideoImageSetDone(metadata);
03604 }
03605 }
03606 }
03607
03608 void VideoDialog::OnVideoSearchDone(MetadataLookup *lookup)
03609 {
03610 if (m_busyPopup)
03611 {
03612 m_busyPopup->Close();
03613 m_busyPopup = NULL;
03614 }
03615
03616 if (!lookup)
03617 return;
03618
03619 VideoMetadata *metadata = qVariantValue<VideoMetadata *>(lookup->GetData());
03620
03621 if (!metadata)
03622 return;
03623
03624 metadata->SetTitle(lookup->GetTitle());
03625 metadata->SetSubtitle(lookup->GetSubtitle());
03626
03627 if (metadata->GetTagline().isEmpty())
03628 metadata->SetTagline(lookup->GetTagline());
03629 if (metadata->GetYear() == 1895 || metadata->GetYear() == 0)
03630 metadata->SetYear(lookup->GetYear());
03631 if (metadata->GetReleaseDate() == QDate())
03632 metadata->SetReleaseDate(lookup->GetReleaseDate());
03633 if (metadata->GetDirector() == VIDEO_DIRECTOR_UNKNOWN ||
03634 metadata->GetDirector().isEmpty())
03635 {
03636 QList<PersonInfo> director = lookup->GetPeople(kPersonDirector);
03637 if (director.count() > 0)
03638 metadata->SetDirector(director.takeFirst().name);
03639 }
03640 if (metadata->GetStudio().isEmpty())
03641 {
03642 QStringList studios = lookup->GetStudios();
03643 if (studios.count() > 0)
03644 metadata->SetStudio(studios.takeFirst());
03645 }
03646 if (metadata->GetPlot() == VIDEO_PLOT_DEFAULT ||
03647 metadata->GetPlot().isEmpty())
03648 metadata->SetPlot(lookup->GetDescription());
03649 if (metadata->GetUserRating() == 0)
03650 metadata->SetUserRating(lookup->GetUserRating());
03651 if (metadata->GetRating() == VIDEO_RATING_DEFAULT)
03652 metadata->SetRating(lookup->GetCertification());
03653 if (metadata->GetLength() == 0)
03654 metadata->SetLength(lookup->GetRuntime());
03655 if (metadata->GetSeason() == 0)
03656 metadata->SetSeason(lookup->GetSeason());
03657 if (metadata->GetEpisode() == 0)
03658 metadata->SetEpisode(lookup->GetEpisode());
03659 if (metadata->GetHomepage().isEmpty())
03660 metadata->SetHomepage(lookup->GetHomepage());
03661
03662 metadata->SetInetRef(lookup->GetInetref());
03663
03664 m_d->AutomaticParentalAdjustment(metadata);
03665
03666
03667 QList<PersonInfo> actors = lookup->GetPeople(kPersonActor);
03668 QList<PersonInfo> gueststars = lookup->GetPeople(kPersonGuestStar);
03669
03670 for (QList<PersonInfo>::const_iterator p = gueststars.begin();
03671 p != gueststars.end(); ++p)
03672 {
03673 actors.append(*p);
03674 }
03675
03676 VideoMetadata::cast_list cast;
03677 QStringList cl;
03678
03679 for (QList<PersonInfo>::const_iterator p = actors.begin();
03680 p != actors.end(); ++p)
03681 {
03682 cl.append((*p).name);
03683 }
03684
03685 for (QStringList::const_iterator p = cl.begin();
03686 p != cl.end(); ++p)
03687 {
03688 QString cn = (*p).trimmed();
03689 if (cn.length())
03690 {
03691 cast.push_back(VideoMetadata::cast_list::
03692 value_type(-1, cn));
03693 }
03694 }
03695
03696 metadata->SetCast(cast);
03697
03698
03699 VideoMetadata::genre_list video_genres;
03700 QStringList genres = lookup->GetCategories();
03701
03702 for (QStringList::const_iterator p = genres.begin();
03703 p != genres.end(); ++p)
03704 {
03705 QString genre_name = (*p).trimmed();
03706 if (genre_name.length())
03707 {
03708 video_genres.push_back(
03709 VideoMetadata::genre_list::value_type(-1, genre_name));
03710 }
03711 }
03712
03713 metadata->SetGenres(video_genres);
03714
03715
03716 VideoMetadata::country_list video_countries;
03717 QStringList countries = lookup->GetCountries();
03718
03719 for (QStringList::const_iterator p = countries.begin();
03720 p != countries.end(); ++p)
03721 {
03722 QString country_name = (*p).trimmed();
03723 if (country_name.length())
03724 {
03725 video_countries.push_back(
03726 VideoMetadata::country_list::value_type(-1,
03727 country_name));
03728 }
03729 }
03730
03731 metadata->SetCountries(video_countries);
03732 metadata->SetProcessed(true);
03733
03734 metadata->UpdateDatabase();
03735
03736 MythUIButtonListItem *item = GetItemByMetadata(metadata);
03737 if (item != NULL)
03738 UpdateItem(item);
03739
03740 delete lookup;
03741 lookup = NULL;
03742
03743 StartVideoImageSet(metadata);
03744 }
03745
03746 void VideoDialog::doVideoScan()
03747 {
03748 if (!m_d->m_scanner)
03749 m_d->m_scanner = new VideoScanner();
03750 connect(m_d->m_scanner, SIGNAL(finished(bool)), SLOT(scanFinished(bool)));
03751 m_d->m_scanner->doScan(GetVideoDirs());
03752 }
03753
03754 void VideoDialog::PromptToScan()
03755 {
03756 QString message = tr("There are no videos in the database, would you like "
03757 "to scan your video directories now?");
03758 MythConfirmationDialog *dialog = new MythConfirmationDialog(m_popupStack,
03759 message,
03760 true);
03761 dialog->SetReturnEvent(this, "scanprompt");
03762 if (dialog->Create())
03763 m_popupStack->AddScreen(dialog);
03764 else
03765 delete dialog;
03766 }
03767
03768 #include "videodlg.moc"