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), m_fanart(NULL)
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->GetText().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->GetText(),
01239 metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
01240 parent->GetText().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->GetText());
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->GetText(),
01254 metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
01255 parent->GetText().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->GetText(), "title");
01293 item->SetText(node->GetText());
01294 }
01295 else if (nodeInt == kUpFolder)
01296 {
01297 item->DisplayState("upfolder", "nodetype");
01298 item->SetText(node->GetText(), "title");
01299 item->SetText(node->GetText());
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
01330 if (m_d->m_rootNode->childCount() == 1)
01331 {
01332 MythGenericTree *node = m_d->m_rootNode->getChildAt(0);
01333 if (node->getInt() == kSubFolder && node->childCount() > 1)
01334 m_d->m_rootNode = node;
01335 else if (node->getInt() == kUpFolder)
01336 m_d->m_treeLoaded = false;
01337 }
01338 else if (m_d->m_rootNode->childCount() == 0)
01339 m_d->m_treeLoaded = false;
01340
01341 if (!m_d->m_currentNode || m_d->m_rootNode != oldroot)
01342 SetCurrentNode(m_d->m_rootNode);
01343 }
01344
01349 QString VideoDialog::RemoteImageCheck(QString host, QString filename)
01350 {
01351 QString result = "";
01352 #if 0
01353 LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteImageCheck(%1)").arg(filename));
01354 #endif
01355
01356 QStringList dirs = GetVideoDirsByHost(host);
01357
01358 if (!dirs.isEmpty())
01359 {
01360 for (QStringList::const_iterator iter = dirs.begin();
01361 iter != dirs.end(); ++iter)
01362 {
01363 QUrl sgurl = *iter;
01364 QString path = sgurl.path();
01365
01366 QString fname = QString("%1/%2").arg(path).arg(filename);
01367
01368 QStringList list( QString("QUERY_SG_FILEQUERY") );
01369 list << host;
01370 list << "Videos";
01371 list << fname;
01372
01373 bool ok = gCoreContext->SendReceiveStringList(list);
01374
01375 if (!ok || list.at(0).startsWith("SLAVE UNREACHABLE"))
01376 {
01377 LOG(VB_GENERAL, LOG_WARNING,
01378 QString("Backend : %1 currently Unreachable. Skipping "
01379 "this one.") .arg(host));
01380 break;
01381 }
01382
01383 if ((!list.isEmpty()) && (list.at(0) == fname))
01384 result = generate_file_url("Videos", host, filename);
01385
01386 if (!result.isEmpty())
01387 {
01388 #if 0
01389 LOG(VB_GENERAL, LOG_DEBUG,
01390 QString("RemoteImageCheck(%1) res :%2: :%3:")
01391 .arg(fname).arg(result).arg(*iter));
01392 #endif
01393 break;
01394 }
01395
01396 }
01397 }
01398
01399 return result;
01400 }
01401
01406 QString VideoDialog::GetImageFromFolder(VideoMetadata *metadata)
01407 {
01408 QString icon_file;
01409 QString host = metadata->GetHost();
01410 QFileInfo fullpath(metadata->GetFilename());
01411 QDir dir = fullpath.dir();
01412 QString prefix = QDir::cleanPath(dir.path());
01413
01414 QString filename = QString("%1/folder").arg(prefix);
01415
01416 QStringList test_files;
01417 test_files.append(filename + ".png");
01418 test_files.append(filename + ".jpg");
01419 test_files.append(filename + ".gif");
01420 bool foundCover;
01421
01422 for (QStringList::const_iterator tfp = test_files.begin();
01423 tfp != test_files.end(); ++tfp)
01424 {
01425 QString imagePath = *tfp;
01426 foundCover = false;
01427 if (!host.isEmpty())
01428 {
01429
01430 imagePath.replace("//", "/");
01431 prefix.replace("//","/");
01432 imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
01433 QString tmpCover = RemoteImageCheck(host, imagePath);
01434
01435 if (!tmpCover.isEmpty())
01436 {
01437 foundCover = true;
01438 imagePath = tmpCover;
01439 }
01440 }
01441 else
01442 foundCover = QFile::exists(imagePath);
01443
01444 if (foundCover)
01445 {
01446 icon_file = imagePath;
01447 return icon_file;
01448 }
01449 }
01450
01451
01452
01453 if (icon_file.isEmpty())
01454 {
01455 QStringList imageTypes;
01456 imageTypes.append(metadata->GetTitle() + ".png");
01457 imageTypes.append(metadata->GetTitle() + ".jpg");
01458 imageTypes.append(metadata->GetTitle() + ".gif");
01459 imageTypes.append("*.png");
01460 imageTypes.append("*.jpg");
01461 imageTypes.append("*.gif");
01462
01463 QStringList fList;
01464
01465 if (!host.isEmpty())
01466 {
01467
01468
01469 QStringList dirs = GetVideoDirsByHost(host);
01470
01471 if (!dirs.isEmpty())
01472 {
01473 for (QStringList::const_iterator iter = dirs.begin();
01474 iter != dirs.end(); ++iter)
01475 {
01476 QUrl sgurl = *iter;
01477 QString path = sgurl.path();
01478
01479 QString subdir = prefix;
01480
01481 path = path + "/" + subdir;
01482 QStringList tmpList;
01483 bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
01484
01485 if (ok)
01486 {
01487 for (QStringList::const_iterator pattern = imageTypes.begin();
01488 pattern != imageTypes.end(); ++pattern)
01489 {
01490 QRegExp rx(*pattern);
01491 rx.setPatternSyntax(QRegExp::Wildcard);
01492 QStringList matches = tmpList.filter(rx);
01493 if (!matches.isEmpty())
01494 {
01495 fList.clear();
01496 fList.append(subdir + "/" + matches.at(0).split("::").at(1));
01497 break;
01498 }
01499 }
01500
01501 break;
01502 }
01503 }
01504 }
01505 }
01506 else
01507 {
01508 QDir vidDir(prefix);
01509 vidDir.setNameFilters(imageTypes);
01510 fList = vidDir.entryList();
01511 }
01512
01513 if (!fList.isEmpty())
01514 {
01515 if (host.isEmpty())
01516 icon_file = QString("%1/%2")
01517 .arg(prefix)
01518 .arg(fList.at(0));
01519 else
01520 icon_file = generate_file_url("Videos", host, fList.at(0));
01521 }
01522 }
01523
01524 if (!icon_file.isEmpty())
01525 LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
01526 .arg(icon_file));
01527 else
01528 LOG(VB_GENERAL, LOG_DEBUG, QString("Could not find cover Image : %1 ")
01529 .arg(prefix));
01530
01531 if (IsDefaultCoverFile(icon_file))
01532 icon_file.clear();
01533
01534 return icon_file;
01535 }
01536
01541 QString VideoDialog::GetCoverImage(MythGenericTree *node)
01542 {
01543 int nodeInt = node->getInt();
01544
01545 QString icon_file;
01546
01547 if (nodeInt == kSubFolder)
01548 {
01549
01550 QString folder_path = node->GetData().value<TreeNodeData>().GetPath();
01551 QString host = node->GetData().value<TreeNodeData>().GetHost();
01552 QString prefix = node->GetData().value<TreeNodeData>().GetPrefix();
01553
01554 if (folder_path.startsWith("myth://"))
01555 folder_path = folder_path.right(folder_path.length()
01556 - folder_path.lastIndexOf("//") - 1);
01557
01558 QString filename = QString("%1/folder").arg(folder_path);
01559
01560 #if 0
01561 LOG(VB_GENERAL, LOG_DEBUG,
01562 QString("GetCoverImage host : %1 prefix : %2 file : %3")
01563 .arg(host).arg(prefix).arg(filename));
01564 #endif
01565
01566 QStringList test_files;
01567 test_files.append(filename + ".png");
01568 test_files.append(filename + ".jpg");
01569 test_files.append(filename + ".gif");
01570 bool foundCover;
01571
01572 for (QStringList::const_iterator tfp = test_files.begin();
01573 tfp != test_files.end(); ++tfp)
01574 {
01575 QString imagePath = *tfp;
01576 #if 0
01577 LOG(VB_GENERAL, LOG_DEBUG, QString("Cover check :%1 : ").arg(*tfp));
01578 #endif
01579
01580 foundCover = false;
01581 if (!host.isEmpty())
01582 {
01583
01584 imagePath.replace("//", "/");
01585 prefix.replace("//","/");
01586 imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
01587 QString tmpCover = RemoteImageCheck(host, imagePath);
01588
01589 if (!tmpCover.isEmpty())
01590 {
01591 foundCover = true;
01592 imagePath = tmpCover;
01593 }
01594 }
01595 else
01596 foundCover = QFile::exists(imagePath);
01597
01598 if (foundCover)
01599 {
01600 icon_file = imagePath;
01601 break;
01602 }
01603 }
01604
01605
01606 if (icon_file.isEmpty())
01607 {
01608 QStringList imageTypes;
01609 imageTypes.append("*.png");
01610 imageTypes.append("*.jpg");
01611 imageTypes.append("*.gif");
01612
01613 QStringList fList;
01614
01615 if (!host.isEmpty())
01616 {
01617
01618
01619 QStringList dirs = GetVideoDirsByHost(host);
01620
01621 if (!dirs.isEmpty())
01622 {
01623 for (QStringList::const_iterator iter = dirs.begin();
01624 iter != dirs.end(); ++iter)
01625 {
01626 QUrl sgurl = *iter;
01627 QString path = sgurl.path();
01628
01629 QString subdir = folder_path.right(folder_path.length() - (prefix.length() + 2));
01630
01631 path = path + "/" + subdir;
01632
01633 QStringList tmpList;
01634 bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
01635
01636 if (ok)
01637 {
01638 for (QStringList::const_iterator pattern = imageTypes.begin();
01639 pattern != imageTypes.end(); ++pattern)
01640 {
01641 QRegExp rx(*pattern);
01642 rx.setPatternSyntax(QRegExp::Wildcard);
01643 QStringList matches = tmpList.filter(rx);
01644 if (!matches.isEmpty())
01645 {
01646 fList.clear();
01647 fList.append(subdir + "/" + matches.at(0).split("::").at(1));
01648 break;
01649 }
01650 }
01651
01652 break;
01653 }
01654 }
01655 }
01656
01657 }
01658 else
01659 {
01660 QDir vidDir(folder_path);
01661 vidDir.setNameFilters(imageTypes);
01662 fList = vidDir.entryList();
01663 }
01664
01665
01666 if (icon_file.isEmpty())
01667 {
01668 int list_count = node->visibleChildCount();
01669 if (list_count > 0)
01670 {
01671 for (int i = 0; i < list_count; i++)
01672 {
01673 MythGenericTree *subnode = node->getVisibleChildAt(i);
01674 if (subnode)
01675 {
01676 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
01677 if (metadata)
01678 {
01679 if (!metadata->GetHost().isEmpty() &&
01680 !metadata->GetCoverFile().startsWith("/"))
01681 {
01682 QString test_file = generate_file_url("Coverart",
01683 metadata->GetHost(), metadata->GetCoverFile());
01684 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01685 !IsDefaultCoverFile(test_file))
01686 {
01687 icon_file = test_file;
01688 break;
01689 }
01690 }
01691 else
01692 {
01693 QString test_file = metadata->GetCoverFile();
01694 if (!test_file.isEmpty() &&
01695 !IsDefaultCoverFile(test_file))
01696 {
01697 icon_file = test_file;
01698 break;
01699 }
01700 }
01701 }
01702 }
01703 }
01704 }
01705 }
01706
01707 if (!fList.isEmpty())
01708 {
01709 if (host.isEmpty())
01710 icon_file = QString("%1/%2")
01711 .arg(folder_path)
01712 .arg(fList.at(0));
01713 else
01714 icon_file = generate_file_url("Videos", host, fList.at(0));
01715 }
01716 }
01717
01718 if (!icon_file.isEmpty())
01719 LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
01720 .arg(icon_file));
01721 else
01722 LOG(VB_GENERAL, LOG_DEBUG,
01723 QString("Could not find folder cover Image : %1 ")
01724 .arg(folder_path));
01725 }
01726 else
01727 {
01728 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01729
01730 if (metadata)
01731 {
01732 if (metadata->IsHostSet() &&
01733 !metadata->GetCoverFile().startsWith("/") &&
01734 !IsDefaultCoverFile(metadata->GetCoverFile()))
01735 {
01736 icon_file = generate_file_url("Coverart", metadata->GetHost(),
01737 metadata->GetCoverFile());
01738 }
01739 else
01740 {
01741 icon_file = metadata->GetCoverFile();
01742 }
01743 }
01744 }
01745
01746 if (IsDefaultCoverFile(icon_file))
01747 icon_file.clear();
01748
01749 return icon_file;
01750 }
01751
01763 QString VideoDialog::GetFirstImage(MythGenericTree *node, QString type,
01764 QString gpnode, int levels)
01765 {
01766 if (!node || type.isEmpty())
01767 return QString();
01768
01769 QString icon_file;
01770
01771 int list_count = node->visibleChildCount();
01772 if (list_count > 0)
01773 {
01774 QList<MythGenericTree *> subDirs;
01775 int maxRecurse = 1;
01776
01777 for (int i = 0; i < list_count; i++)
01778 {
01779 MythGenericTree *subnode = node->getVisibleChildAt(i);
01780 if (subnode)
01781 {
01782 if (subnode->childCount() > 0)
01783 subDirs << subnode;
01784
01785 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
01786 if (metadata)
01787 {
01788 QString test_file;
01789 QString host = metadata->GetHost();
01790 QString title = metadata->GetTitle();
01791
01792 if (type == "Coverart" && !host.isEmpty() &&
01793 !metadata->GetCoverFile().startsWith("/"))
01794 {
01795 test_file = generate_file_url("Coverart",
01796 host, metadata->GetCoverFile());
01797 }
01798 else if (type == "Coverart")
01799 test_file = metadata->GetCoverFile();
01800
01801 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01802 !IsDefaultCoverFile(test_file) && (gpnode.isEmpty() ||
01803 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01804 {
01805 icon_file = test_file;
01806 break;
01807 }
01808
01809 if (type == "Fanart" && !host.isEmpty() &&
01810 !metadata->GetFanart().startsWith("/"))
01811 {
01812 test_file = generate_file_url("Fanart",
01813 host, metadata->GetFanart());
01814 }
01815 else if (type == "Fanart")
01816 test_file = metadata->GetFanart();
01817
01818 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01819 test_file != VIDEO_FANART_DEFAULT && (gpnode.isEmpty() ||
01820 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01821 {
01822 icon_file = test_file;
01823 break;
01824 }
01825
01826 if (type == "Banners" && !host.isEmpty() &&
01827 !metadata->GetBanner().startsWith("/"))
01828 {
01829 test_file = generate_file_url("Banners",
01830 host, metadata->GetBanner());
01831 }
01832 else if (type == "Banners")
01833 test_file = metadata->GetBanner();
01834
01835 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01836 test_file != VIDEO_BANNER_DEFAULT && (gpnode.isEmpty() ||
01837 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01838 {
01839 icon_file = test_file;
01840 break;
01841 }
01842
01843 if (type == "Screenshots" && !host.isEmpty() &&
01844 !metadata->GetScreenshot().startsWith("/"))
01845 {
01846 test_file = generate_file_url("Screenshots",
01847 host, metadata->GetScreenshot());
01848 }
01849 else if (type == "Screenshots")
01850 test_file = metadata->GetScreenshot();
01851
01852 if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01853 test_file != VIDEO_SCREENSHOT_DEFAULT && (gpnode.isEmpty() ||
01854 (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01855 {
01856 icon_file = test_file;
01857 break;
01858 }
01859 }
01860 }
01861 }
01862 if (icon_file.isEmpty() && !subDirs.isEmpty())
01863 {
01864 QString test_file;
01865 int subDirCount = subDirs.count();
01866 for (int i = 0; i < subDirCount; i ++)
01867 {
01868 if (levels < maxRecurse)
01869 {
01870 test_file = GetFirstImage(subDirs[i], type,
01871 node->GetText(), levels + 1);
01872 if (!test_file.isEmpty())
01873 {
01874 icon_file = test_file;
01875 break;
01876 }
01877 }
01878 }
01879 }
01880 }
01881 return icon_file;
01882 }
01883
01888 QString VideoDialog::GetScreenshot(MythGenericTree *node)
01889 {
01890 const int nodeInt = node->getInt();
01891
01892 QString icon_file;
01893
01894 if (nodeInt == kSubFolder || nodeInt == kUpFolder)
01895 {
01896 icon_file = VIDEO_SCREENSHOT_DEFAULT;
01897 }
01898 else
01899 {
01900 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01901
01902 if (metadata)
01903 {
01904 if (metadata->IsHostSet() &&
01905 !metadata->GetScreenshot().startsWith("/") &&
01906 !metadata->GetScreenshot().isEmpty())
01907 {
01908 icon_file = generate_file_url("Screenshots", metadata->GetHost(),
01909 metadata->GetScreenshot());
01910 }
01911 else
01912 {
01913 icon_file = metadata->GetScreenshot();
01914 }
01915 }
01916 }
01917
01918 if (IsDefaultScreenshot(icon_file))
01919 icon_file.clear();
01920
01921 return icon_file;
01922 }
01923
01928 QString VideoDialog::GetBanner(MythGenericTree *node)
01929 {
01930 const int nodeInt = node->getInt();
01931
01932 if (nodeInt == kSubFolder || nodeInt == kUpFolder)
01933 return QString();
01934
01935 QString icon_file;
01936 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01937
01938 if (metadata)
01939 {
01940 if (metadata->IsHostSet() &&
01941 !metadata->GetBanner().startsWith("/") &&
01942 !metadata->GetBanner().isEmpty())
01943 {
01944 icon_file = generate_file_url("Banners", metadata->GetHost(),
01945 metadata->GetBanner());
01946 }
01947 else
01948 {
01949 icon_file = metadata->GetBanner();
01950 }
01951
01952 if (IsDefaultBanner(icon_file))
01953 icon_file.clear();
01954 }
01955
01956 return icon_file;
01957 }
01958
01963 QString VideoDialog::GetFanart(MythGenericTree *node)
01964 {
01965 const int nodeInt = node->getInt();
01966
01967 if (nodeInt == kSubFolder || nodeInt == kUpFolder)
01968 return QString();
01969
01970 QString icon_file;
01971 const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01972
01973 if (metadata)
01974 {
01975 if (metadata->IsHostSet() &&
01976 !metadata->GetFanart().startsWith("/") &&
01977 !metadata->GetFanart().isEmpty())
01978 {
01979 icon_file = generate_file_url("Fanart", metadata->GetHost(),
01980 metadata->GetFanart());
01981 }
01982 else
01983 {
01984 icon_file = metadata->GetFanart();
01985 }
01986
01987 if (IsDefaultFanart(icon_file))
01988 icon_file.clear();
01989 }
01990
01991 return icon_file;
01992 }
01993
01998 bool VideoDialog::keyPressEvent(QKeyEvent *levent)
01999 {
02000 if (GetFocusWidget()->keyPressEvent(levent))
02001 return true;
02002
02003 bool handled = false;
02004 QStringList actions;
02005 handled = GetMythMainWindow()->TranslateKeyPress("Video", levent, actions);
02006
02007 for (int i = 0; i < actions.size() && !handled; i++)
02008 {
02009 QString action = actions[i];
02010 handled = true;
02011
02012 if (action == "INFO")
02013 {
02014 MythUIButtonListItem *item = GetItemCurrent();
02015 MythGenericTree *node = GetNodePtrFromButton(item);
02016 if (!m_menuPopup && node->getInt() != kUpFolder)
02017 VideoMenu();
02018 }
02019 else if (action == "INCPARENT")
02020 shiftParental(1);
02021 else if (action == "DECPARENT")
02022 shiftParental(-1);
02023 else if (action == "1" || action == "2" ||
02024 action == "3" || action == "4")
02025 setParentalLevel((ParentalLevel::Level)action.toInt());
02026 else if (action == "FILTER")
02027 ChangeFilter();
02028 else if (action == "MENU")
02029 {
02030 if (!m_menuPopup)
02031 DisplayMenu();
02032 }
02033 else if (action == "PLAYALT")
02034 {
02035 if (!m_menuPopup && GetMetadata(GetItemCurrent()) &&
02036 m_d->m_altPlayerEnabled)
02037 playVideoAlt();
02038 }
02039 else if (action == "DOWNLOADDATA")
02040 {
02041 if (!m_menuPopup && GetMetadata(GetItemCurrent()))
02042 VideoSearch();
02043 }
02044 else if (action == "INCSEARCH")
02045 searchStart();
02046 else if (action == "ITEMDETAIL")
02047 DoItemDetailShow();
02048 else if (action == "DELETE")
02049 {
02050 if (!m_menuPopup && GetMetadata(GetItemCurrent()))
02051 RemoveVideo();
02052 }
02053 else if (action == "EDIT" && !m_menuPopup)
02054 EditMetadata();
02055 else if (action == "ESCAPE")
02056 {
02057 if (m_d->m_type != DLG_TREE
02058 && !GetMythMainWindow()->IsExitingToMain()
02059 && m_d->m_currentNode != m_d->m_rootNode)
02060 handled = goBack();
02061 else
02062 handled = false;
02063 }
02064 else
02065 handled = false;
02066 }
02067
02068 if (!handled)
02069 {
02070 handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", levent,
02071 actions);
02072
02073 for (int i = 0; i < actions.size() && !handled; i++)
02074 {
02075 QString action = actions[i];
02076 if (action == "PLAYBACK")
02077 {
02078 handled = true;
02079 playVideo();
02080 }
02081 }
02082 }
02083
02084 if (!handled && MythScreenType::keyPressEvent(levent))
02085 handled = true;
02086
02087 return handled;
02088 }
02089
02094 void VideoDialog::createBusyDialog(QString title)
02095 {
02096 if (m_busyPopup)
02097 return;
02098
02099 QString message = title;
02100
02101 m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
02102 "mythvideobusydialog");
02103
02104 if (m_busyPopup->Create())
02105 m_popupStack->AddScreen(m_busyPopup);
02106 }
02107
02112 void VideoDialog::createOkDialog(QString title)
02113 {
02114 QString message = title;
02115
02116 MythConfirmationDialog *okPopup =
02117 new MythConfirmationDialog(m_popupStack, message, false);
02118
02119 if (okPopup->Create())
02120 m_popupStack->AddScreen(okPopup);
02121 }
02122
02127 void VideoDialog::searchComplete(QString string)
02128 {
02129 LOG(VB_GENERAL, LOG_DEBUG, QString("Jumping to: %1").arg(string));
02130
02131 MythGenericTree *parent = m_d->m_currentNode->getParent();
02132 QStringList childList;
02133 QList<MythGenericTree*>::iterator it;
02134 QList<MythGenericTree*> *children;
02135 QMap<int, QString> idTitle;
02136
02137 if (parent && m_d->m_type == DLG_TREE)
02138 children = parent->getAllChildren();
02139 else
02140 children = m_d->m_currentNode->getAllChildren();
02141
02142 for (it = children->begin(); it != children->end(); ++it)
02143 {
02144 MythGenericTree *child = *it;
02145 QString title = child->GetText();
02146 int id = child->getPosition();
02147 idTitle.insert(id, title);
02148 }
02149
02150 if (m_d->m_type == DLG_TREE)
02151 {
02152 MythGenericTree *parent = m_videoButtonTree->GetCurrentNode()->getParent();
02153 MythGenericTree *new_node = parent->getChildAt(idTitle.key(string));
02154 if (new_node)
02155 {
02156 m_videoButtonTree->SetCurrentNode(new_node);
02157 m_videoButtonTree->SetActive(true);
02158 }
02159 }
02160 else
02161 m_videoButtonList->SetItemCurrent(idTitle.key(string));
02162 }
02163
02168 void VideoDialog::searchStart(void)
02169 {
02170 MythGenericTree *parent = m_d->m_currentNode->getParent();
02171
02172 QStringList childList;
02173 QList<MythGenericTree*>::iterator it;
02174 QList<MythGenericTree*> *children;
02175 if (parent && m_d->m_type == DLG_TREE)
02176 children = parent->getAllChildren();
02177 else
02178 children = m_d->m_currentNode->getAllChildren();
02179
02180 for (it = children->begin(); it != children->end(); ++it)
02181 {
02182 MythGenericTree *child = *it;
02183 childList << child->GetText();
02184 }
02185
02186 MythScreenStack *popupStack =
02187 GetMythMainWindow()->GetStack("popup stack");
02188 MythUISearchDialog *searchDialog = new MythUISearchDialog(popupStack,
02189 tr("Video Search"), childList, false, "");
02190
02191 if (searchDialog->Create())
02192 {
02193 connect(searchDialog, SIGNAL(haveResult(QString)),
02194 SLOT(searchComplete(QString)));
02195
02196 popupStack->AddScreen(searchDialog);
02197 }
02198 else
02199 delete searchDialog;
02200 }
02201
02206 bool VideoDialog::goBack()
02207 {
02208 bool handled = false;
02209
02210 if (m_d->m_currentNode != m_d->m_rootNode)
02211 {
02212 MythGenericTree *lparent = m_d->m_currentNode->getParent();
02213 if (lparent)
02214 {
02215 SetCurrentNode(lparent);
02216
02217 handled = true;
02218 }
02219 }
02220
02221 loadData();
02222
02223 return handled;
02224 }
02225
02230 void VideoDialog::SetCurrentNode(MythGenericTree *node)
02231 {
02232 if (!node)
02233 return;
02234
02235 m_d->m_currentNode = node;
02236 }
02237
02242 void VideoDialog::UpdatePosition()
02243 {
02244 MythUIButtonListItem *ci = GetItemCurrent();
02245 MythUIButtonList *currentList = ci ? ci->parent() : 0;
02246
02247 if (!currentList)
02248 return;
02249
02250 CheckedSet(m_positionText, tr("%1 of %2")
02251 .arg(currentList->IsEmpty() ? 0 : currentList->GetCurrentPos() + 1)
02252 .arg(currentList->GetCount()));
02253 }
02254
02259 void VideoDialog::UpdateText(MythUIButtonListItem *item)
02260 {
02261 if (!item)
02262 return;
02263
02264 MythUIButtonList *currentList = item->parent();
02265
02266 if (!currentList)
02267 return;
02268
02269 VideoMetadata *metadata = GetMetadata(item);
02270
02271 MythGenericTree *node = GetNodePtrFromButton(item);
02272
02273 if (!node)
02274 return;
02275
02276 if (metadata)
02277 {
02278 MetadataMap metadataMap;
02279 metadata->toMap(metadataMap);
02280 SetTextFromMap(metadataMap);
02281 }
02282 else
02283 {
02284 MetadataMap metadataMap;
02285 ClearMap(metadataMap);
02286 SetTextFromMap(metadataMap);
02287 }
02288
02289 ScreenCopyDest dest(this);
02290 CopyMetadataToUI(metadata, dest);
02291
02292 if (node->getInt() == kSubFolder && !metadata)
02293 {
02294 QString cover = GetFirstImage(node, "Coverart");
02295 QString fanart = GetFirstImage(node, "Fanart");
02296 QString banner = GetFirstImage(node, "Banners");
02297 QString screenshot = GetFirstImage(node, "Screenshots");
02298 CheckedSet(m_coverImage, cover);
02299 CheckedSet(m_fanart, fanart);
02300 CheckedSet(m_banner, banner);
02301 CheckedSet(m_screenshot, screenshot);
02302 }
02303
02304 if (!metadata)
02305 CheckedSet(m_titleText, item->GetText());
02306 UpdatePosition();
02307
02308 if (m_d->m_currentNode)
02309 {
02310 CheckedSet(m_crumbText, m_d->m_currentNode->getRouteByString().join(" > "));
02311 CheckedSet(this, "foldername", m_d->m_currentNode->GetText());
02312 }
02313
02314 if (node && node->getInt() == kSubFolder)
02315 CheckedSet(this, "childcount",
02316 QString("%1").arg(node->visibleChildCount()));
02317
02318 if (node)
02319 node->becomeSelectedChild();
02320 }
02321
02326 void VideoDialog::VideoMenu()
02327 {
02328 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02329 QString label;
02330
02331 if (metadata)
02332 {
02333 if (!metadata->GetSubtitle().isEmpty())
02334 label = tr("Video Options\n%1\n%2").arg(metadata->GetTitle())
02335 .arg(metadata->GetSubtitle());
02336 else
02337 label = tr("Video Options\n%1").arg(metadata->GetTitle());
02338 }
02339 else
02340 label = tr("Video Options");
02341
02342 MythMenu *menu = new MythMenu(label, this, "actions");
02343
02344 MythUIButtonListItem *item = GetItemCurrent();
02345 MythGenericTree *node = GetNodePtrFromButton(item);
02346 if (metadata)
02347 {
02348 if (!metadata->GetTrailer().isEmpty() ||
02349 gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0) ||
02350 m_d->m_altPlayerEnabled)
02351 menu->AddItem(tr("Play..."), NULL, CreatePlayMenu());
02352 else
02353 menu->AddItem(tr("Play"), SLOT(playVideo()));
02354 if (metadata->GetWatched())
02355 menu->AddItem(tr("Mark as Unwatched"), SLOT(ToggleWatched()));
02356 else
02357 menu->AddItem(tr("Mark as Watched"), SLOT(ToggleWatched()));
02358 menu->AddItem(tr("Video Info"), NULL, CreateInfoMenu());
02359 menu->AddItem(tr("Change Video Details"), NULL, CreateManageMenu());
02360 menu->AddItem(tr("Delete"), SLOT(RemoveVideo()));
02361 }
02362 else if (node && node->getInt() != kUpFolder)
02363 {
02364 menu->AddItem(tr("Play Folder"), SLOT(playFolder()));
02365 }
02366
02367
02368 m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
02369
02370 if (m_menuPopup->Create())
02371 m_popupStack->AddScreen(m_menuPopup);
02372 else
02373 delete m_menuPopup;
02374 }
02375
02381 MythMenu* VideoDialog::CreatePlayMenu()
02382 {
02383 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02384 QString label;
02385
02386 if (metadata)
02387 label = tr("Playback Options\n%1").arg(metadata->GetTitle());
02388 else
02389 return NULL;
02390
02391 MythMenu *menu = new MythMenu(label, this, "actions");
02392
02393 menu->AddItem(tr("Play"), SLOT(playVideo()));
02394
02395 if (m_d->m_altPlayerEnabled)
02396 {
02397 menu->AddItem(tr("Play in Alternate Player"), SLOT(playVideoAlt()));
02398 }
02399
02400 if (gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0))
02401 {
02402 menu->AddItem(tr("Play With Trailers"), SLOT(playVideoWithTrailers()));
02403 }
02404
02405 QString trailerFile = metadata->GetTrailer();
02406 if (QFile::exists(trailerFile) ||
02407 (!metadata->GetHost().isEmpty() && !trailerFile.isEmpty()))
02408 {
02409 menu->AddItem(tr("Play Trailer"), SLOT(playTrailer()));
02410 }
02411
02412 return menu;
02413 }
02414
02419 void VideoDialog::DisplayMenu()
02420 {
02421 QString label = tr("Video Display Menu");
02422
02423 MythMenu *menu = new MythMenu(label, this, "display");
02424
02425 menu->AddItem(tr("Scan For Changes"), SLOT(doVideoScan()));
02426 menu->AddItem(tr("Retrieve All Details"), SLOT(VideoAutoSearch()));
02427 menu->AddItem(tr("Filter Display"), SLOT(ChangeFilter()));
02428 menu->AddItem(tr("Browse By..."), NULL, CreateMetadataBrowseMenu());
02429 menu->AddItem(tr("Change View"), NULL, CreateViewMenu());
02430 menu->AddItem(tr("Settings"), NULL, CreateSettingsMenu());
02431
02432 m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
02433
02434 if (m_menuPopup->Create())
02435 m_popupStack->AddScreen(m_menuPopup);
02436 else
02437 delete m_menuPopup;
02438 }
02439
02444 MythMenu* VideoDialog::CreateViewMenu()
02445 {
02446 QString label = tr("Change View");
02447
02448 MythMenu *menu = new MythMenu(label, this, "view");
02449
02450 if (!(m_d->m_type & DLG_BROWSER))
02451 menu->AddItem(tr("Switch to Browse View"), SLOT(SwitchBrowse()));
02452
02453 if (!(m_d->m_type & DLG_GALLERY))
02454 menu->AddItem(tr("Switch to Gallery View"), SLOT(SwitchGallery()));
02455
02456 if (!(m_d->m_type & DLG_TREE))
02457 menu->AddItem(tr("Switch to List View"), SLOT(SwitchTree()));
02458
02459 if (!(m_d->m_type & DLG_MANAGER))
02460 menu->AddItem(tr("Switch to Manage View"), SLOT(SwitchManager()));
02461
02462 if (m_d->m_isFlatList)
02463 menu->AddItem(tr("Show Directory Structure"), SLOT(ToggleFlatView()));
02464 else
02465 menu->AddItem(tr("Hide Directory Structure"), SLOT(ToggleFlatView()));
02466
02467 if (m_d->m_isFileBrowser)
02468 menu->AddItem(tr("Browse Library (recommended)"), SLOT(ToggleBrowseMode()));
02469 else
02470 menu->AddItem(tr("Browse Filesystem (slow)"), SLOT(ToggleBrowseMode()));
02471
02472
02473 return menu;
02474 }
02475
02480 MythMenu* VideoDialog::CreateSettingsMenu()
02481 {
02482 QString label = tr("Video Settings");
02483
02484 MythMenu *menu = new MythMenu(label, this, "settings");
02485
02486 menu->AddItem(tr("Player Settings"), SLOT(ShowPlayerSettings()));
02487 menu->AddItem(tr("Metadata Settings"), SLOT(ShowMetadataSettings()));
02488 menu->AddItem(tr("File Type Settings"), SLOT(ShowExtensionSettings()));
02489
02490 return menu;
02491 }
02492
02497 void VideoDialog::ShowPlayerSettings()
02498 {
02499 PlayerSettings *ps = new PlayerSettings(m_mainStack, "player settings");
02500
02501 if (ps->Create())
02502 m_mainStack->AddScreen(ps);
02503 else
02504 delete ps;
02505 }
02506
02511 void VideoDialog::ShowMetadataSettings()
02512 {
02513 MetadataSettings *ms = new MetadataSettings(m_mainStack, "metadata settings");
02514
02515 if (ms->Create())
02516 m_mainStack->AddScreen(ms);
02517 else
02518 delete ms;
02519 }
02520
02525 void VideoDialog::ShowExtensionSettings()
02526 {
02527 FileAssocDialog *fa = new FileAssocDialog(m_mainStack, "fa dialog");
02528
02529 if (fa->Create())
02530 m_mainStack->AddScreen(fa);
02531 else
02532 delete fa;
02533 }
02534
02539 MythMenu* VideoDialog::CreateMetadataBrowseMenu()
02540 {
02541 QString label = tr("Browse By");
02542
02543 MythMenu *menu = new MythMenu(label, this, "metadata");
02544
02545 if (m_d->m_groupType != BRS_CAST)
02546 menu->AddItem(tr("Cast"), SLOT(SwitchVideoCastGroup()));
02547
02548 if (m_d->m_groupType != BRS_CATEGORY)
02549 menu->AddItem(tr("Category"), SLOT(SwitchVideoCategoryGroup()));
02550
02551 if (m_d->m_groupType != BRS_INSERTDATE)
02552 menu->AddItem(tr("Date Added"), SLOT(SwitchVideoInsertDateGroup()));
02553
02554 if (m_d->m_groupType != BRS_DIRECTOR)
02555 menu->AddItem(tr("Director"), SLOT(SwitchVideoDirectorGroup()));
02556
02557 if (m_d->m_groupType != BRS_STUDIO)
02558 menu->AddItem(tr("Studio"), SLOT(SwitchVideoStudioGroup()));
02559
02560 if (m_d->m_groupType != BRS_FOLDER)
02561 menu->AddItem(tr("Folder"), SLOT(SwitchVideoFolderGroup()));
02562
02563 if (m_d->m_groupType != BRS_GENRE)
02564 menu->AddItem(tr("Genre"), SLOT(SwitchVideoGenreGroup()));
02565
02566 if (m_d->m_groupType != BRS_TVMOVIE)
02567 menu->AddItem(tr("TV/Movies"),SLOT(SwitchVideoTVMovieGroup()));
02568
02569 if (m_d->m_groupType != BRS_USERRATING)
02570 menu->AddItem(tr("User Rating"), SLOT(SwitchVideoUserRatingGroup()));
02571
02572 if (m_d->m_groupType != BRS_YEAR)
02573 menu->AddItem(tr("Year"), SLOT(SwitchVideoYearGroup()));
02574
02575 return menu;
02576 }
02577
02582 MythMenu *VideoDialog::CreateInfoMenu()
02583 {
02584 QString label = tr("Video Info");
02585
02586 MythMenu *menu = new MythMenu(label, this, "info");
02587
02588 if (ItemDetailPopup::Exists())
02589 menu->AddItem(tr("View Details"), SLOT(DoItemDetailShow()));
02590
02591 menu->AddItem(tr("View Full Plot"), SLOT(ViewPlot()));
02592
02593 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02594 if (metadata)
02595 {
02596 if (!metadata->GetCast().empty())
02597 menu->AddItem(tr("View Cast"), SLOT(ShowCastDialog()));
02598 if (!metadata->GetHomepage().isEmpty())
02599 menu->AddItem(tr("View Homepage"), SLOT(ShowHomepage()));
02600 }
02601
02602 return menu;
02603 }
02604
02609 MythMenu *VideoDialog::CreateManageMenu()
02610 {
02611 QString label = tr("Manage Video Details");
02612
02613 MythMenu *menu = new MythMenu(label, this, "manage");
02614
02615 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02616
02617 menu->AddItem(tr("Edit Details"), SLOT(EditMetadata()));
02618 menu->AddItem(tr("Retrieve Details"), SLOT(VideoSearch()));
02619 if (metadata->GetProcessed())
02620 menu->AddItem(tr("Allow Updates"), SLOT(ToggleProcess()));
02621 else
02622 menu->AddItem(tr("Disable Updates"), SLOT(ToggleProcess()));
02623 menu->AddItem(tr("Reset Details"), SLOT(ResetMetadata()));
02624
02625 return menu;
02626 }
02627
02628 void VideoDialog::ToggleProcess()
02629 {
02630 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02631 if (metadata)
02632 {
02633 metadata->SetProcessed(!metadata->GetProcessed());
02634 metadata->UpdateDatabase();
02635
02636 refreshData();
02637 }
02638 }
02639
02644 void VideoDialog::ToggleBrowseMode()
02645 {
02646 m_d->m_isFileBrowser = !m_d->m_isFileBrowser;
02647 gCoreContext->SaveSetting("VideoDialogNoDB",
02648 QString("%1").arg((int)m_d->m_isFileBrowser));
02649 reloadData();
02650 }
02651
02656 void VideoDialog::ToggleFlatView()
02657 {
02658 m_d->m_isFlatList = !m_d->m_isFlatList;
02659 gCoreContext->SaveSetting(QString("mythvideo.folder_view_%1").arg(m_d->m_type),
02660 QString("%1").arg((int)m_d->m_isFlatList));
02661
02662
02663
02664 reloadData();
02665 }
02666
02671 void VideoDialog::handleDirSelect(MythGenericTree *node)
02672 {
02673 SetCurrentNode(node);
02674 loadData();
02675 }
02676
02681 void VideoDialog::handleDynamicDirSelect(MythGenericTree *node)
02682 {
02683 QStringList route = node->getRouteByString();
02684 if (m_d->m_videoList && m_d->m_videoList->refreshNode(node))
02685 reloadData();
02686 m_videoButtonTree->SetNodeByString(route);
02687 }
02688
02693 void VideoDialog::handleSelect(MythUIButtonListItem *item)
02694 {
02695 MythGenericTree *node = GetNodePtrFromButton(item);
02696 int nodeInt = node->getInt();
02697
02698 switch (nodeInt)
02699 {
02700 case kDynamicSubFolder:
02701 handleDynamicDirSelect(node);
02702 break;
02703 case kSubFolder:
02704 handleDirSelect(node);
02705 break;
02706 case kUpFolder:
02707 goBack();
02708 break;
02709 default:
02710 {
02711 bool doPlay = true;
02712 if (m_d->m_type == DLG_GALLERY)
02713 {
02714 doPlay = !DoItemDetailShow();
02715 }
02716
02717 if (doPlay)
02718 playVideo();
02719 }
02720 };
02721 }
02722
02727 void VideoDialog::SwitchTree()
02728 {
02729 SwitchLayout(DLG_TREE, m_d->m_browse);
02730 }
02731
02736 void VideoDialog::SwitchGallery()
02737 {
02738 SwitchLayout(DLG_GALLERY, m_d->m_browse);
02739 }
02740
02745 void VideoDialog::SwitchBrowse()
02746 {
02747 SwitchLayout(DLG_BROWSER, m_d->m_browse);
02748 }
02749
02754 void VideoDialog::SwitchManager()
02755 {
02756 SwitchLayout(DLG_MANAGER, m_d->m_browse);
02757 }
02758
02763 void VideoDialog::SwitchVideoFolderGroup()
02764 {
02765 SwitchLayout(m_d->m_type, BRS_FOLDER);
02766 }
02767
02772 void VideoDialog::SwitchVideoGenreGroup()
02773 {
02774 SwitchLayout(m_d->m_type, BRS_GENRE);
02775 }
02776
02781 void VideoDialog::SwitchVideoCategoryGroup()
02782 {
02783 SwitchLayout(m_d->m_type, BRS_CATEGORY);
02784 }
02785
02790 void VideoDialog::SwitchVideoYearGroup()
02791 {
02792 SwitchLayout(m_d->m_type, BRS_YEAR);
02793 }
02794
02799 void VideoDialog::SwitchVideoDirectorGroup()
02800 {
02801 SwitchLayout(m_d->m_type, BRS_DIRECTOR);
02802 }
02803
02808 void VideoDialog::SwitchVideoStudioGroup()
02809 {
02810 SwitchLayout(m_d->m_type, BRS_STUDIO);
02811 }
02812
02817 void VideoDialog::SwitchVideoCastGroup()
02818 {
02819 SwitchLayout(m_d->m_type, BRS_CAST);
02820 }
02821
02826 void VideoDialog::SwitchVideoUserRatingGroup()
02827 {
02828 SwitchLayout(m_d->m_type, BRS_USERRATING);
02829 }
02830
02835 void VideoDialog::SwitchVideoInsertDateGroup()
02836 {
02837 SwitchLayout(m_d->m_type, BRS_INSERTDATE);
02838 }
02839
02844 void VideoDialog::SwitchVideoTVMovieGroup()
02845 {
02846 SwitchLayout(m_d->m_type, BRS_TVMOVIE);
02847 }
02848
02853 void VideoDialog::SwitchLayout(DialogType type, BrowseType browse)
02854 {
02855 m_d->m_switchingLayout = true;
02856
02857
02858 SavePosition();
02859
02860 VideoDialog *mythvideo =
02861 new VideoDialog(GetMythMainWindow()->GetMainStack(), "mythvideo",
02862 m_d->m_videoList, type, browse);
02863
02864 if (mythvideo->Create())
02865 {
02866 gCoreContext->SaveSetting("Default MythVideo View", type);
02867 gCoreContext->SaveSetting("mythvideo.db_group_type", browse);
02868 MythScreenStack *screenStack = GetScreenStack();
02869 screenStack->AddScreen(mythvideo);
02870 screenStack->PopScreen(this, false, false);
02871 deleteLater();
02872 }
02873 else
02874 {
02875 ShowOkPopup(tr("An error occurred when switching views."));
02876 }
02877 }
02878
02883 void VideoDialog::ViewPlot()
02884 {
02885 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02886
02887 PlotDialog *plotdialog = new PlotDialog(m_popupStack, metadata);
02888
02889 if (plotdialog->Create())
02890 m_popupStack->AddScreen(plotdialog);
02891 }
02892
02897 bool VideoDialog::DoItemDetailShow()
02898 {
02899 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02900
02901 if (metadata)
02902 {
02903 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
02904 ItemDetailPopup *idp = new ItemDetailPopup(mainStack, metadata,
02905 m_d->m_videoList->getListCache());
02906
02907 if (idp->Create())
02908 {
02909 mainStack->AddScreen(idp);
02910 return true;
02911 }
02912 }
02913
02914 return false;
02915 }
02916
02921 void VideoDialog::ShowCastDialog()
02922 {
02923 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02924
02925 CastDialog *castdialog = new CastDialog(m_popupStack, metadata);
02926
02927 if (castdialog->Create())
02928 m_popupStack->AddScreen(castdialog);
02929 }
02930
02931 void VideoDialog::ShowHomepage()
02932 {
02933 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02934
02935 if (!metadata)
02936 return;
02937
02938 QString url = metadata->GetHomepage();
02939
02940 if (url.isEmpty())
02941 return;
02942
02943 QString browser = gCoreContext->GetSetting("WebBrowserCommand", "");
02944 QString zoom = gCoreContext->GetSetting("WebBrowserZoomLevel", "1.0");
02945
02946 if (browser.isEmpty())
02947 {
02948 ShowOkPopup(tr("No browser command set! MythVideo needs MythBrowser "
02949 "installed to display the homepage."));
02950 return;
02951 }
02952
02953 if (browser.toLower() == "internal")
02954 {
02955 GetMythMainWindow()->HandleMedia("WebBrowser", url);
02956 return;
02957 }
02958 else
02959 {
02960 QString cmd = browser;
02961 cmd.replace("%ZOOM%", zoom);
02962 cmd.replace("%URL%", url);
02963 cmd.replace('\'', "%27");
02964 cmd.replace("&","\\&");
02965 cmd.replace(";","\\;");
02966
02967 GetMythMainWindow()->AllowInput(false);
02968 myth_system(cmd, kMSDontDisableDrawing);
02969 GetMythMainWindow()->AllowInput(true);
02970 return;
02971 }
02972 }
02973
02978 void VideoDialog::playVideo()
02979 {
02980 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02981 if (metadata)
02982 PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
02983 }
02984
02989 void VideoDialog::playVideoAlt()
02990 {
02991 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02992 if (metadata)
02993 PlayVideo(metadata->GetFilename(),
02994 m_d->m_videoList->getListCache(), true);
02995 }
02996
03001 void VideoDialog::playFolder()
03002 {
03003 const int WATCHED_WATERMARK = 10000;
03004
03005
03006 QTime playing_time;
03007
03008 MythUIButtonListItem *item = GetItemCurrent();
03009 MythGenericTree *node = GetNodePtrFromButton(item);
03010 int list_count;
03011
03012 if (node && !(node->getInt() >= 0))
03013 list_count = node->childCount();
03014 else
03015 return;
03016
03017 if (list_count > 0)
03018 {
03019 bool video_started = false;
03020 int i = 0;
03021 while (i < list_count &&
03022 (!video_started || playing_time.elapsed() > WATCHED_WATERMARK))
03023 {
03024 MythGenericTree *subnode = node->getChildAt(i);
03025 if (subnode)
03026 {
03027 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
03028 if (metadata)
03029 {
03030 playing_time.start();
03031 video_started = true;
03032 PlayVideo(metadata->GetFilename(),
03033 m_d->m_videoList->getListCache());
03034 }
03035 }
03036 i++;
03037 }
03038 }
03039 }
03040
03041 namespace
03042 {
03043 struct SimpleCollect : public DirectoryHandler
03044 {
03045 SimpleCollect(QStringList &fileList) : m_fileList(fileList) {}
03046
03047 DirectoryHandler *newDir(const QString &dirName,
03048 const QString &fqDirName)
03049 {
03050 (void) dirName;
03051 (void) fqDirName;
03052 return this;
03053 }
03054
03055 void handleFile(const QString &fileName, const QString &fqFileName,
03056 const QString &extension, const QString &host)
03057 {
03058 (void) fileName;
03059 (void) extension;
03060 (void) host;
03061 m_fileList.push_back(fqFileName);
03062 }
03063
03064 private:
03065 QStringList &m_fileList;
03066 };
03067
03068 QStringList GetTrailersInDirectory(const QString &startDir)
03069 {
03070 FileAssociations::ext_ignore_list extensions;
03071 FileAssociations::getFileAssociation()
03072 .getExtensionIgnoreList(extensions);
03073 QStringList ret;
03074 SimpleCollect sc(ret);
03075
03076 (void) ScanVideoDirectory(startDir, &sc, extensions, false);
03077 return ret;
03078 }
03079 }
03080
03085 void VideoDialog::playVideoWithTrailers()
03086 {
03087 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03088 if (!metadata) return;
03089
03090 QStringList trailers = GetTrailersInDirectory(gCoreContext->
03091 GetSetting("mythvideo.TrailersDir"));
03092
03093 if (trailers.isEmpty())
03094 return;
03095
03096 const int trailersToPlay =
03097 gCoreContext->GetNumSetting("mythvideo.TrailersRandomCount");
03098
03099 int i = 0;
03100 while (!trailers.isEmpty() && i < trailersToPlay)
03101 {
03102 ++i;
03103 QString trailer = trailers.takeAt(random() % trailers.size());
03104
03105 LOG(VB_GENERAL, LOG_DEBUG,
03106 QString("Random trailer to play will be: %1").arg(trailer));
03107
03108 VideoPlayerCommand::PlayerFor(trailer).Play();
03109 }
03110
03111 PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
03112 }
03113
03118 void VideoDialog::playTrailer()
03119 {
03120 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03121 if (!metadata) return;
03122 QString url;
03123
03124 if (metadata->IsHostSet() && !metadata->GetTrailer().startsWith("/"))
03125 url = generate_file_url("Trailers", metadata->GetHost(),
03126 metadata->GetTrailer());
03127 else
03128 url = metadata->GetTrailer();
03129
03130 VideoPlayerCommand::PlayerFor(url).Play();
03131 }
03132
03137 void VideoDialog::setParentalLevel(const ParentalLevel::Level &level)
03138 {
03139 m_d->m_parentalLevel.SetLevel(level);
03140 }
03141
03146 void VideoDialog::shiftParental(int amount)
03147 {
03148 setParentalLevel(ParentalLevel(m_d->m_parentalLevel.GetLevel()
03149 .GetLevel() + amount).GetLevel());
03150 }
03151
03156 void VideoDialog::ChangeFilter()
03157 {
03158 MythScreenStack *mainStack = GetScreenStack();
03159
03160 VideoFilterDialog *filterdialog = new VideoFilterDialog(mainStack,
03161 "videodialogfilters", m_d->m_videoList.get());
03162
03163 if (filterdialog->Create())
03164 mainStack->AddScreen(filterdialog);
03165
03166 connect(filterdialog, SIGNAL(filterChanged()), SLOT(reloadData()));
03167 }
03168
03173 VideoMetadata *VideoDialog::GetMetadata(MythUIButtonListItem *item)
03174 {
03175 VideoMetadata *metadata = NULL;
03176
03177 if (item)
03178 {
03179 MythGenericTree *node = GetNodePtrFromButton(item);
03180 if (node)
03181 {
03182 int nodeInt = node->getInt();
03183
03184 if (nodeInt >= 0)
03185 metadata = GetMetadataPtrFromNode(node);
03186 }
03187 }
03188
03189 return metadata;
03190 }
03191
03192 void VideoDialog::customEvent(QEvent *levent)
03193 {
03194 if (levent->type() == MetadataFactoryMultiResult::kEventType)
03195 {
03196 MetadataFactoryMultiResult *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent);
03197
03198 if (!mfmr)
03199 return;
03200
03201 MetadataLookupList list = mfmr->results;
03202
03203 if (m_busyPopup)
03204 {
03205 m_busyPopup->Close();
03206 m_busyPopup = NULL;
03207 }
03208
03209 if (list.count() > 1)
03210 {
03211 MetadataResultsDialog *resultsdialog =
03212 new MetadataResultsDialog(m_popupStack, list);
03213
03214 connect(resultsdialog, SIGNAL(haveResult(MetadataLookup*)),
03215 SLOT(OnVideoSearchListSelection(MetadataLookup*)),
03216 Qt::QueuedConnection);
03217
03218 if (resultsdialog->Create())
03219 m_popupStack->AddScreen(resultsdialog);
03220 }
03221 }
03222 else if (levent->type() == MetadataFactorySingleResult::kEventType)
03223 {
03224 MetadataFactorySingleResult *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent);
03225
03226 if (!mfsr)
03227 return;
03228
03229 MetadataLookup *lookup = mfsr->result;
03230
03231 if (!lookup)
03232 return;
03233
03234 OnVideoSearchDone(lookup);
03235 }
03236 else if (levent->type() == MetadataFactoryNoResult::kEventType)
03237 {
03238 MetadataFactoryNoResult *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent);
03239
03240 if (!mfnr)
03241 return;
03242
03243 MetadataLookup *lookup = mfnr->result;
03244
03245 if (!lookup)
03246 return;
03247
03248 if (m_busyPopup)
03249 {
03250 m_busyPopup->Close();
03251 m_busyPopup = NULL;
03252 }
03253
03254 VideoMetadata *metadata =
03255 qVariantValue<VideoMetadata *>(lookup->GetData());
03256 if (metadata)
03257 {
03258 metadata->SetProcessed(true);
03259 metadata->UpdateDatabase();
03260 }
03261 LOG(VB_GENERAL, LOG_INFO,
03262 QString("No results found for %1 %2 %3").arg(lookup->GetTitle())
03263 .arg(lookup->GetSeason()).arg(lookup->GetEpisode()));
03264 }
03265 else if (levent->type() == DialogCompletionEvent::kEventType)
03266 {
03267 DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(levent);
03268 QString id = dce->GetId();
03269
03270 if (id == "scanprompt")
03271 {
03272 int result = dce->GetResult();
03273 if (result == 1)
03274 doVideoScan();
03275 }
03276 else
03277 m_menuPopup = NULL;
03278 }
03279 }
03280
03281 void VideoDialog::OnVideoImageSetDone(VideoMetadata *metadata)
03282 {
03283
03284 if (m_busyPopup)
03285 {
03286 m_busyPopup->Close();
03287 m_busyPopup = NULL;
03288 }
03289
03290 metadata->SetProcessed(true);
03291 metadata->UpdateDatabase();
03292
03293 MythUIButtonListItem *item = GetItemByMetadata(metadata);
03294 if (item != NULL)
03295 UpdateItem(item);
03296 }
03297
03298 MythUIButtonListItem *VideoDialog::GetItemCurrent()
03299 {
03300 if (m_videoButtonTree)
03301 {
03302 return m_videoButtonTree->GetItemCurrent();
03303 }
03304
03305 return m_videoButtonList->GetItemCurrent();
03306 }
03307
03308 MythUIButtonListItem *VideoDialog::GetItemByMetadata(VideoMetadata *metadata)
03309 {
03310 if (m_videoButtonTree)
03311 {
03312 return m_videoButtonTree->GetItemCurrent();
03313 }
03314
03315 QList<MythGenericTree*>::iterator it;
03316 QList<MythGenericTree*> *children;
03317 QMap<int, int> idPosition;
03318
03319 children = m_d->m_currentNode->getAllChildren();
03320
03321 for (it = children->begin(); it != children->end(); ++it)
03322 {
03323 MythGenericTree *child = *it;
03324 int nodeInt = child->getInt();
03325 if (nodeInt != kSubFolder && nodeInt != kUpFolder)
03326 {
03327 VideoMetadata *listmeta =
03328 GetMetadataPtrFromNode(child);
03329 if (listmeta)
03330 {
03331 int position = child->getPosition();
03332 int id = listmeta->GetID();
03333 idPosition.insert(id, position);
03334 }
03335 }
03336 }
03337
03338 return m_videoButtonList->GetItemAt(idPosition.value(metadata->GetID()));
03339 }
03340
03341 void VideoDialog::VideoSearch(MythGenericTree *node,
03342 bool automode)
03343 {
03344 if (!node)
03345 node = GetNodePtrFromButton(GetItemCurrent());
03346
03347 if (!node)
03348 return;
03349
03350 VideoMetadata *metadata = GetMetadataPtrFromNode(node);
03351
03352 if (!metadata)
03353 return;
03354
03355 m_metadataFactory->Lookup(metadata, automode, true);
03356
03357 if (!automode)
03358 {
03359 QString msg = tr("Fetching details for %1")
03360 .arg(metadata->GetTitle());
03361 if (!metadata->GetSubtitle().isEmpty())
03362 msg += QString(": %1").arg(metadata->GetSubtitle());
03363 if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
03364 msg += tr(" %1x%2").arg(metadata->GetSeason())
03365 .arg(metadata->GetEpisode());
03366 createBusyDialog(msg);
03367 }
03368 }
03369
03370 void VideoDialog::VideoAutoSearch(MythGenericTree *node)
03371 {
03372 if (!node)
03373 node = m_d->m_rootNode;
03374 typedef QList<MythGenericTree *> MGTreeChildList;
03375 MGTreeChildList *lchildren = node->getAllChildren();
03376
03377 LOG(VB_GENERAL, LOG_DEBUG,
03378 QString("Fetching details in %1").arg(node->GetText()));
03379
03380 for (MGTreeChildList::const_iterator p = lchildren->begin();
03381 p != lchildren->end(); ++p)
03382 {
03383 if (((*p)->getInt() == kSubFolder) ||
03384 ((*p)->getInt() == kUpFolder))
03385 VideoAutoSearch((*p));
03386 else
03387 {
03388 VideoMetadata *metadata = GetMetadataPtrFromNode((*p));
03389
03390 if (!metadata)
03391 continue;
03392
03393 if (!metadata->GetProcessed())
03394 VideoSearch((*p), true);
03395 }
03396 }
03397 }
03398
03399 void VideoDialog::ToggleWatched()
03400 {
03401 MythUIButtonListItem *item = GetItemCurrent();
03402 if (!item)
03403 return;
03404
03405 VideoMetadata *metadata = GetMetadata(item);
03406 if (metadata)
03407 {
03408 metadata->SetWatched(!metadata->GetWatched());
03409 metadata->UpdateDatabase();
03410 item->DisplayState(WatchedToState(metadata->GetWatched()),
03411 "watchedstate");
03412 }
03413 }
03414
03415 void VideoDialog::OnVideoSearchListSelection(MetadataLookup *lookup)
03416 {
03417 if (!lookup)
03418 return;
03419
03420 lookup->SetStep(kLookupData);
03421 m_metadataFactory->Lookup(lookup);
03422 }
03423
03424 void VideoDialog::OnParentalChange(int amount)
03425 {
03426 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03427 if (metadata)
03428 {
03429 ParentalLevel curshowlevel = metadata->GetShowLevel();
03430
03431 curshowlevel += amount;
03432
03433 if (curshowlevel.GetLevel() != metadata->GetShowLevel())
03434 {
03435 metadata->SetShowLevel(curshowlevel.GetLevel());
03436 metadata->UpdateDatabase();
03437 refreshData();
03438 }
03439 }
03440 }
03441
03442 void VideoDialog::EditMetadata()
03443 {
03444 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03445 if (!metadata)
03446 return;
03447
03448 MythScreenStack *screenStack = GetScreenStack();
03449
03450 EditMetadataDialog *md_editor = new EditMetadataDialog(screenStack,
03451 "mythvideoeditmetadata", metadata,
03452 m_d->m_videoList->getListCache());
03453
03454 connect(md_editor, SIGNAL(Finished()), SLOT(refreshData()));
03455
03456 if (md_editor->Create())
03457 screenStack->AddScreen(md_editor);
03458 }
03459
03460 void VideoDialog::RemoveVideo()
03461 {
03462 VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03463
03464 if (!metadata)
03465 return;
03466
03467 QString message = tr("Are you sure you want to permanently delete:\n%1")
03468 .arg(metadata->GetTitle());
03469
03470 MythConfirmationDialog *confirmdialog =
03471 new MythConfirmationDialog(m_popupStack,message);
03472
03473 if (confirmdialog->Create())
03474 m_popupStack->AddScreen(confirmdialog);
03475
03476 connect(confirmdialog, SIGNAL(haveResult(bool)),
03477 SLOT(OnRemoveVideo(bool)));
03478 }
03479
03480 void VideoDialog::OnRemoveVideo(bool dodelete)
03481 {
03482 if (!dodelete)
03483 return;
03484
03485 MythUIButtonListItem *item = GetItemCurrent();
03486 MythGenericTree *gtItem = GetNodePtrFromButton(item);
03487
03488 VideoMetadata *metadata = GetMetadata(item);
03489
03490 if (!metadata)
03491 return;
03492
03493 if (m_d->m_videoList->Delete(metadata->GetID()))
03494 {
03495 if (m_videoButtonTree)
03496 m_videoButtonTree->RemoveItem(item, false);
03497 else
03498 m_videoButtonList->RemoveItem(item);
03499
03500 MythGenericTree *parent = gtItem->getParent();
03501 parent->deleteNode(gtItem);
03502 }
03503 else
03504 {
03505 QString message = tr("Failed to delete file");
03506
03507 MythConfirmationDialog *confirmdialog =
03508 new MythConfirmationDialog(m_popupStack,message,false);
03509
03510 if (confirmdialog->Create())
03511 m_popupStack->AddScreen(confirmdialog);
03512 }
03513 }
03514
03515 void VideoDialog::ResetMetadata()
03516 {
03517 MythUIButtonListItem *item = GetItemCurrent();
03518 VideoMetadata *metadata = GetMetadata(item);
03519
03520 if (metadata)
03521 {
03522 metadata->Reset();
03523 metadata->UpdateDatabase();
03524 UpdateItem(item);
03525 }
03526 }
03527
03528 void VideoDialog::StartVideoImageSet(VideoMetadata *metadata)
03529 {
03530 if (!metadata)
03531 return;
03532
03533 QStringList cover_dirs;
03534 cover_dirs += m_d->m_artDir;
03535
03536 QString cover_file;
03537 QString inetref = metadata->GetInetRef();
03538 QString filename = metadata->GetFilename();
03539 QString title = metadata->GetTitle();
03540 int season = metadata->GetSeason();
03541 QString host = metadata->GetHost();
03542 int episode = metadata->GetEpisode();
03543
03544 if (metadata->GetCoverFile().isEmpty() ||
03545 IsDefaultCoverFile(metadata->GetCoverFile()))
03546 {
03547 if (GetLocalVideoImage(inetref, filename,
03548 cover_dirs, cover_file, title,
03549 season, host, "Coverart", episode))
03550 {
03551 metadata->SetCoverFile(cover_file);
03552 OnVideoImageSetDone(metadata);
03553 }
03554 }
03555
03556 QStringList fanart_dirs;
03557 fanart_dirs += m_d->m_fanDir;
03558
03559 QString fanart_file;
03560
03561 if (metadata->GetFanart().isEmpty())
03562 {
03563 if (GetLocalVideoImage(inetref, filename,
03564 fanart_dirs, fanart_file, title,
03565 season, host, "Fanart", episode))
03566 {
03567 metadata->SetFanart(fanart_file);
03568 OnVideoImageSetDone(metadata);
03569 }
03570 }
03571
03572 QStringList banner_dirs;
03573 banner_dirs += m_d->m_banDir;
03574
03575 QString banner_file;
03576
03577 if (metadata->GetBanner().isEmpty())
03578 {
03579 if (GetLocalVideoImage(inetref, filename,
03580 banner_dirs, banner_file, title,
03581 season, host, "Banners", episode))
03582 {
03583 metadata->SetBanner(banner_file);
03584 OnVideoImageSetDone(metadata);
03585 }
03586 }
03587
03588 QStringList screenshot_dirs;
03589 screenshot_dirs += m_d->m_sshotDir;
03590
03591 QString screenshot_file;
03592
03593 if (metadata->GetScreenshot().isEmpty())
03594 {
03595 if (GetLocalVideoImage(inetref, filename,
03596 screenshot_dirs, screenshot_file, title,
03597 season, host, "Screenshots", episode,
03598 true))
03599 {
03600 metadata->SetScreenshot(screenshot_file);
03601 OnVideoImageSetDone(metadata);
03602 }
03603 }
03604 }
03605
03606 void VideoDialog::OnVideoSearchDone(MetadataLookup *lookup)
03607 {
03608 if (m_busyPopup)
03609 {
03610 m_busyPopup->Close();
03611 m_busyPopup = NULL;
03612 }
03613
03614 if (!lookup)
03615 return;
03616
03617 VideoMetadata *metadata = qVariantValue<VideoMetadata *>(lookup->GetData());
03618
03619 if (!metadata)
03620 return;
03621
03622 metadata->SetTitle(lookup->GetTitle());
03623 metadata->SetSubtitle(lookup->GetSubtitle());
03624
03625 if (metadata->GetTagline().isEmpty())
03626 metadata->SetTagline(lookup->GetTagline());
03627 if (metadata->GetYear() == 1895 || metadata->GetYear() == 0)
03628 metadata->SetYear(lookup->GetYear());
03629 if (metadata->GetReleaseDate() == QDate())
03630 metadata->SetReleaseDate(lookup->GetReleaseDate());
03631 if (metadata->GetDirector() == VIDEO_DIRECTOR_UNKNOWN ||
03632 metadata->GetDirector().isEmpty())
03633 {
03634 QList<PersonInfo> director = lookup->GetPeople(kPersonDirector);
03635 if (director.count() > 0)
03636 metadata->SetDirector(director.takeFirst().name);
03637 }
03638 if (metadata->GetStudio().isEmpty())
03639 {
03640 QStringList studios = lookup->GetStudios();
03641 if (studios.count() > 0)
03642 metadata->SetStudio(studios.takeFirst());
03643 }
03644 if (metadata->GetPlot() == VIDEO_PLOT_DEFAULT ||
03645 metadata->GetPlot().isEmpty())
03646 metadata->SetPlot(lookup->GetDescription());
03647 if (metadata->GetUserRating() == 0)
03648 metadata->SetUserRating(lookup->GetUserRating());
03649 if (metadata->GetRating() == VIDEO_RATING_DEFAULT)
03650 metadata->SetRating(lookup->GetCertification());
03651 if (metadata->GetLength() == 0)
03652 metadata->SetLength(lookup->GetRuntime());
03653 if (metadata->GetSeason() == 0)
03654 metadata->SetSeason(lookup->GetSeason());
03655 if (metadata->GetEpisode() == 0)
03656 metadata->SetEpisode(lookup->GetEpisode());
03657 if (metadata->GetHomepage().isEmpty())
03658 metadata->SetHomepage(lookup->GetHomepage());
03659
03660 metadata->SetInetRef(lookup->GetInetref());
03661
03662 m_d->AutomaticParentalAdjustment(metadata);
03663
03664
03665 QList<PersonInfo> actors = lookup->GetPeople(kPersonActor);
03666 QList<PersonInfo> gueststars = lookup->GetPeople(kPersonGuestStar);
03667
03668 for (QList<PersonInfo>::const_iterator p = gueststars.begin();
03669 p != gueststars.end(); ++p)
03670 {
03671 actors.append(*p);
03672 }
03673
03674 VideoMetadata::cast_list cast;
03675 QStringList cl;
03676
03677 for (QList<PersonInfo>::const_iterator p = actors.begin();
03678 p != actors.end(); ++p)
03679 {
03680 cl.append((*p).name);
03681 }
03682
03683 for (QStringList::const_iterator p = cl.begin();
03684 p != cl.end(); ++p)
03685 {
03686 QString cn = (*p).trimmed();
03687 if (cn.length())
03688 {
03689 cast.push_back(VideoMetadata::cast_list::
03690 value_type(-1, cn));
03691 }
03692 }
03693
03694 metadata->SetCast(cast);
03695
03696
03697 VideoMetadata::genre_list video_genres;
03698 QStringList genres = lookup->GetCategories();
03699
03700 for (QStringList::const_iterator p = genres.begin();
03701 p != genres.end(); ++p)
03702 {
03703 QString genre_name = (*p).trimmed();
03704 if (genre_name.length())
03705 {
03706 video_genres.push_back(
03707 VideoMetadata::genre_list::value_type(-1, genre_name));
03708 }
03709 }
03710
03711 metadata->SetGenres(video_genres);
03712
03713
03714 VideoMetadata::country_list video_countries;
03715 QStringList countries = lookup->GetCountries();
03716
03717 for (QStringList::const_iterator p = countries.begin();
03718 p != countries.end(); ++p)
03719 {
03720 QString country_name = (*p).trimmed();
03721 if (country_name.length())
03722 {
03723 video_countries.push_back(
03724 VideoMetadata::country_list::value_type(-1,
03725 country_name));
03726 }
03727 }
03728
03729 metadata->SetCountries(video_countries);
03730 metadata->SetProcessed(true);
03731
03732 metadata->UpdateDatabase();
03733
03734 MythUIButtonListItem *item = GetItemByMetadata(metadata);
03735 if (item != NULL)
03736 UpdateItem(item);
03737
03738 delete lookup;
03739 lookup = NULL;
03740
03741 StartVideoImageSet(metadata);
03742 }
03743
03744 void VideoDialog::doVideoScan()
03745 {
03746 if (!m_d->m_scanner)
03747 m_d->m_scanner = new VideoScanner();
03748 connect(m_d->m_scanner, SIGNAL(finished(bool)), SLOT(scanFinished(bool)));
03749 m_d->m_scanner->doScan(GetVideoDirs());
03750 }
03751
03752 void VideoDialog::PromptToScan()
03753 {
03754 QString message = tr("There are no videos in the database, would you like "
03755 "to scan your video directories now?");
03756 MythConfirmationDialog *dialog = new MythConfirmationDialog(m_popupStack,
03757 message,
03758 true);
03759 dialog->SetReturnEvent(this, "scanprompt");
03760 if (dialog->Create())
03761 m_popupStack->AddScreen(dialog);
03762 else
03763 delete dialog;
03764 }
03765
03766 #include "videodlg.moc"