MythTV  0.26-pre
metadatafactory.cpp
Go to the documentation of this file.
00001 #include <QApplication>
00002 #include <QList>
00003 #include <QUrl>
00004 
00005 #include "mythcontext.h"
00006 #include "videoutils.h"
00007 #include "mythlogging.h"
00008 #include "compat.h"
00009 #include "remoteutil.h"
00010 
00011 // Needed to perform a lookup
00012 #include "metadatadownload.h"
00013 #include "metadataimagedownload.h"
00014 
00015 // Needed for video scanning
00016 #include "videometadatalistmanager.h"
00017 #include "globals.h"
00018 
00019 // Input for a lookup
00020 #include "videometadata.h"
00021 #include "programinfo.h"
00022 #include "recordingrule.h"
00023 
00024 #include "metadatafactory.h"
00025 
00026 QEvent::Type MetadataFactoryNoResult::kEventType =
00027     (QEvent::Type) QEvent::registerEventType();
00028 
00029 QEvent::Type MetadataFactorySingleResult::kEventType =
00030     (QEvent::Type) QEvent::registerEventType();
00031 
00032 QEvent::Type MetadataFactoryMultiResult::kEventType =
00033     (QEvent::Type) QEvent::registerEventType();
00034 
00035 QEvent::Type MetadataFactoryVideoChanges::kEventType =
00036     (QEvent::Type) QEvent::registerEventType();
00037 
00038 MetadataFactory::MetadataFactory(QObject *parent) :
00039     m_parent(parent), m_scanning(false),
00040     m_returnList(), m_sync(false)
00041 {
00042     m_lookupthread = new MetadataDownload(this);
00043     m_imagedownload = new MetadataImageDownload(this);
00044     m_videoscanner = new VideoScannerThread(this);
00045 
00046     m_mlm = new VideoMetadataListManager();
00047 }
00048 
00049 MetadataFactory::~MetadataFactory()
00050 {
00051     if (m_lookupthread)
00052     {
00053         m_lookupthread->cancel();
00054         delete m_lookupthread;
00055         m_lookupthread = NULL;
00056     }
00057 
00058     if (m_imagedownload)
00059     {
00060         m_imagedownload->cancel();
00061         delete m_imagedownload;
00062         m_imagedownload = NULL;
00063     }
00064 
00065     if (m_videoscanner && m_videoscanner->wait())
00066         delete m_videoscanner;
00067 }
00068 
00069 void MetadataFactory::Lookup(RecordingRule *recrule, bool automatic,
00070                              bool getimages, bool allowgeneric)
00071 {
00072     if (!recrule)
00073         return;
00074 
00075     MetadataLookup *lookup = new MetadataLookup();
00076     lookup->SetStep(kLookupSearch);
00077     lookup->SetType(kMetadataRecording);
00078     lookup->SetSubtype(GuessLookupType(recrule));
00079     lookup->SetData(qVariantFromValue(recrule));
00080     lookup->SetAutomatic(automatic);
00081     lookup->SetHandleImages(getimages);
00082     lookup->SetAllowGeneric(allowgeneric);
00083     lookup->SetHost(gCoreContext->GetMasterHostName());
00084     lookup->SetTitle(recrule->m_title);
00085     lookup->SetSubtitle(recrule->m_subtitle);
00086     lookup->SetInetref(recrule->m_inetref);
00087     lookup->SetSeason(recrule->m_season);
00088     lookup->SetEpisode(recrule->m_episode);
00089 
00090     if (m_lookupthread->isRunning())
00091         m_lookupthread->prependLookup(lookup);
00092     else
00093         m_lookupthread->addLookup(lookup);
00094 }
00095 
00096 void MetadataFactory::Lookup(ProgramInfo *pginfo, bool automatic,
00097                              bool getimages, bool allowgeneric)
00098 {
00099     if (!pginfo)
00100         return;
00101 
00102     MetadataLookup *lookup = new MetadataLookup();
00103     lookup->SetStep(kLookupSearch);
00104     lookup->SetType(kMetadataRecording);
00105     lookup->SetSubtype(GuessLookupType(pginfo));
00106     lookup->SetData(qVariantFromValue(pginfo));
00107     lookup->SetAutomatic(automatic);
00108     lookup->SetHandleImages(getimages);
00109     lookup->SetAllowGeneric(allowgeneric);
00110     lookup->SetHost(gCoreContext->GetMasterHostName());
00111     lookup->SetTitle(pginfo->GetTitle());
00112     lookup->SetSubtitle(pginfo->GetSubtitle());
00113     lookup->SetSeason(pginfo->GetSeason());
00114     lookup->SetEpisode(pginfo->GetEpisode());
00115     lookup->SetInetref(pginfo->GetInetRef());
00116 
00117     if (m_lookupthread->isRunning())
00118         m_lookupthread->prependLookup(lookup);
00119     else
00120         m_lookupthread->addLookup(lookup);
00121 }
00122 
00123 void MetadataFactory::Lookup(VideoMetadata *metadata, bool automatic,
00124                              bool getimages, bool allowgeneric)
00125 {
00126     if (!metadata)
00127         return;
00128 
00129     MetadataLookup *lookup = new MetadataLookup();
00130     lookup->SetStep(kLookupSearch);
00131     lookup->SetType(kMetadataVideo);
00132     if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
00133         lookup->SetSubtype(kProbableTelevision);
00134     else if (metadata->GetSubtitle().isEmpty())
00135         lookup->SetSubtype(kProbableMovie);
00136     else
00137         lookup->SetSubtype(kUnknownVideo);
00138     lookup->SetData(qVariantFromValue(metadata));
00139     lookup->SetAutomatic(automatic);
00140     lookup->SetHandleImages(getimages);
00141     lookup->SetAllowGeneric(allowgeneric);
00142     lookup->SetHost(metadata->GetHost());
00143     lookup->SetTitle(metadata->GetTitle());
00144     lookup->SetSubtitle(metadata->GetSubtitle());
00145     lookup->SetSeason(metadata->GetSeason());
00146     lookup->SetEpisode(metadata->GetEpisode());
00147     lookup->SetInetref(metadata->GetInetRef());
00148     QString fntmp;
00149     if (metadata->GetHost().isEmpty())
00150         fntmp = metadata->GetFilename();
00151     else
00152         fntmp = generate_file_url("Videos", metadata->GetHost(),
00153                                       metadata->GetFilename());
00154     lookup->SetFilename(fntmp);
00155 
00156     if (m_lookupthread->isRunning())
00157         m_lookupthread->prependLookup(lookup);
00158     else
00159         m_lookupthread->addLookup(lookup);
00160 }
00161 
00162 void MetadataFactory::Lookup(MetadataLookup *lookup)
00163 {
00164     if (!lookup)
00165         return;
00166 
00167     if (m_lookupthread->isRunning())
00168         m_lookupthread->prependLookup(lookup);
00169     else
00170         m_lookupthread->addLookup(lookup);
00171 }
00172 
00173 META_PUBLIC MetadataLookupList MetadataFactory::SynchronousLookup(QString title,
00174                                                       QString subtitle,
00175                                                       QString inetref,
00176                                                       int season,
00177                                                       int episode,
00178                                                       QString grabber,
00179                                                       bool allowgeneric)
00180 {
00181     MetadataLookup *lookup = new MetadataLookup();
00182     lookup->SetStep(kLookupSearch);
00183     lookup->SetType(kMetadataRecording);
00184     lookup->SetAutomatic(false);
00185     lookup->SetHandleImages(false);
00186     lookup->SetAllowGeneric(allowgeneric);
00187     lookup->SetTitle(title);
00188     lookup->SetSubtitle(subtitle);
00189     lookup->SetSeason(season);
00190     lookup->SetEpisode(episode);
00191     lookup->SetInetref(inetref);
00192     if (grabber.toLower() == "movie")
00193         lookup->SetSubtype(kProbableMovie);
00194     else if (grabber.toLower() == "tv" ||
00195              grabber.toLower() == "television")
00196         lookup->SetSubtype(kProbableTelevision);
00197     else
00198         lookup->SetSubtype(GuessLookupType(lookup));
00199 
00200     return SynchronousLookup(lookup);
00201 }
00202 
00203 MetadataLookupList MetadataFactory::SynchronousLookup(MetadataLookup *lookup)
00204 {
00205     if (!lookup)
00206         return MetadataLookupList();
00207 
00208     m_sync = true;
00209 
00210     if (m_lookupthread->isRunning())
00211         m_lookupthread->prependLookup(lookup);
00212     else
00213         m_lookupthread->addLookup(lookup);
00214 
00215     while (m_returnList.isEmpty() && m_sync)
00216     {
00217         sleep(1);
00218         qApp->processEvents();
00219     }
00220 
00221     m_sync = false;
00222 
00223     delete lookup;
00224 
00225     return m_returnList;
00226 }
00227 
00228 bool MetadataFactory::VideoGrabbersFunctional()
00229 {
00230     return (m_lookupthread->MovieGrabberWorks() &&
00231             m_lookupthread->TelevisionGrabberWorks());
00232 }
00233 
00234 void MetadataFactory::VideoScan()
00235 {
00236     if (IsRunning())
00237         return;
00238 
00239     QStringList hosts;
00240     if (!RemoteGetActiveBackends(&hosts))
00241     {
00242         LOG(VB_GENERAL, LOG_WARNING, "Could not retrieve list of "
00243                             "available backends.");
00244         return;
00245     }
00246 
00247     VideoScan(hosts);
00248 }
00249 
00250 void MetadataFactory::VideoScan(QStringList hosts)
00251 {
00252     if (IsRunning())
00253         return;
00254 
00255     m_scanning = true;
00256 
00257     m_videoscanner->SetHosts(hosts);
00258     m_videoscanner->SetDirs(GetVideoDirs());
00259     m_videoscanner->start();
00260 }
00261 
00262 void MetadataFactory::OnMultiResult(MetadataLookupList list)
00263 {
00264     if (!list.size())
00265         return;
00266 
00267     if (m_parent)
00268         QCoreApplication::postEvent(m_parent,
00269             new MetadataFactoryMultiResult(list));
00270 }
00271 
00272 void MetadataFactory::OnSingleResult(MetadataLookup *lookup)
00273 {
00274     if (!lookup)
00275         return;
00276 
00277     if (lookup->GetHandleImages())
00278     {
00279         DownloadMap map;
00280 
00281         ArtworkList coverartlist = lookup->GetArtwork(kArtworkCoverart);
00282         if (coverartlist.size())
00283         {
00284             ArtworkInfo info;
00285             info.url = coverartlist.takeLast().url;
00286             map.insert(kArtworkCoverart, info);
00287         }
00288 
00289         ArtworkList fanartlist = lookup->GetArtwork(kArtworkFanart);
00290         if (fanartlist.size())
00291         {
00292             ArtworkInfo info;
00293             int index = 0;
00294             int season = (int)lookup->GetSeason();
00295             if (season > 0 && season <= fanartlist.count())
00296                 index = season - 1;
00297             info.url = fanartlist.takeAt(index).url;
00298             map.insert(kArtworkFanart, info);
00299         }
00300 
00301         ArtworkList bannerlist = lookup->GetArtwork(kArtworkBanner);
00302         if (bannerlist.size())
00303         {
00304             ArtworkInfo info;
00305             info.url = bannerlist.takeLast().url;
00306             map.insert(kArtworkBanner, info);
00307         }
00308 
00309         if (!lookup->GetType() == kMetadataRecording)
00310         {
00311             ArtworkList screenshotlist = lookup->GetArtwork(kArtworkScreenshot);
00312             if (screenshotlist.size())
00313             {
00314                 ArtworkInfo info;
00315                 info.url = screenshotlist.takeLast().url;
00316                 map.insert(kArtworkScreenshot, info);
00317             }
00318         }
00319         lookup->SetDownloads(map);
00320         m_imagedownload->addDownloads(lookup);
00321     }
00322     else
00323     {
00324         if (m_scanning)
00325             OnVideoResult(lookup);
00326         else if (m_parent)
00327             QCoreApplication::postEvent(m_parent,
00328                 new MetadataFactorySingleResult(lookup));
00329     }
00330 }
00331 
00332 void MetadataFactory::OnNoResult(MetadataLookup *lookup)
00333 {
00334     if (!lookup)
00335         return;
00336 
00337     if (m_parent)
00338         QCoreApplication::postEvent(m_parent,
00339             new MetadataFactoryNoResult(lookup));
00340 }
00341 
00342 void MetadataFactory::OnImageResult(MetadataLookup *lookup)
00343 {
00344     if (!lookup)
00345         return;
00346 
00347     if (m_parent)
00348         QCoreApplication::postEvent(m_parent,
00349             new MetadataFactorySingleResult(lookup));
00350 }
00351 
00352 void MetadataFactory::OnVideoResult(MetadataLookup *lookup)
00353 {
00354     if (!lookup)
00355        return;
00356 
00357     VideoMetadata *metadata = qVariantValue<VideoMetadata *>(lookup->GetData());
00358 
00359     if (!metadata)
00360         return;
00361 
00362     metadata->SetTitle(lookup->GetTitle());
00363     metadata->SetSubtitle(lookup->GetSubtitle());
00364 
00365     if (metadata->GetTagline().isEmpty())
00366         metadata->SetTagline(lookup->GetTagline());
00367     if (metadata->GetYear() == 1895 || metadata->GetYear() == 0)
00368         metadata->SetYear(lookup->GetYear());
00369     if (metadata->GetReleaseDate() == QDate())
00370         metadata->SetReleaseDate(lookup->GetReleaseDate());
00371     if (metadata->GetDirector() == VIDEO_DIRECTOR_UNKNOWN ||
00372         metadata->GetDirector().isEmpty())
00373     {
00374         QList<PersonInfo> director = lookup->GetPeople(kPersonDirector);
00375         if (director.count() > 0)
00376             metadata->SetDirector(director.takeFirst().name);
00377     }
00378     if (metadata->GetStudio().isEmpty())
00379     {
00380         QStringList studios = lookup->GetStudios();
00381         if (studios.count() > 0)
00382             metadata->SetStudio(studios.takeFirst());
00383     }
00384     if (metadata->GetPlot() == VIDEO_PLOT_DEFAULT ||
00385         metadata->GetPlot().isEmpty())
00386         metadata->SetPlot(lookup->GetDescription());
00387     if (metadata->GetUserRating() == 0)
00388         metadata->SetUserRating(lookup->GetUserRating());
00389     if (metadata->GetRating() == VIDEO_RATING_DEFAULT)
00390         metadata->SetRating(lookup->GetCertification());
00391     if (metadata->GetLength() == 0)
00392         metadata->SetLength(lookup->GetRuntime());
00393     if (metadata->GetSeason() == 0)
00394         metadata->SetSeason(lookup->GetSeason());
00395     if (metadata->GetEpisode() == 0)
00396         metadata->SetEpisode(lookup->GetEpisode());
00397     if (metadata->GetHomepage().isEmpty())
00398         metadata->SetHomepage(lookup->GetHomepage());
00399 
00400     metadata->SetInetRef(lookup->GetInetref());
00401 
00402 //    m_d->AutomaticParentalAdjustment(metadata);
00403 
00404     // Cast
00405     QList<PersonInfo> actors = lookup->GetPeople(kPersonActor);
00406     QList<PersonInfo> gueststars = lookup->GetPeople(kPersonGuestStar);
00407 
00408     for (QList<PersonInfo>::const_iterator p = gueststars.begin();
00409         p != gueststars.end(); ++p)
00410     {
00411         actors.append(*p);
00412     }
00413 
00414     VideoMetadata::cast_list cast;
00415     QStringList cl;
00416 
00417     for (QList<PersonInfo>::const_iterator p = actors.begin();
00418         p != actors.end(); ++p)
00419     {
00420         cl.append((*p).name);
00421     }
00422 
00423     for (QStringList::const_iterator p = cl.begin();
00424         p != cl.end(); ++p)
00425     {
00426         QString cn = (*p).trimmed();
00427         if (cn.length())
00428         {
00429             cast.push_back(VideoMetadata::cast_list::
00430                         value_type(-1, cn));
00431         }
00432     }
00433 
00434     metadata->SetCast(cast);
00435 
00436     // Genres
00437     VideoMetadata::genre_list video_genres;
00438     QStringList genres = lookup->GetCategories();
00439 
00440     for (QStringList::const_iterator p = genres.begin();
00441         p != genres.end(); ++p)
00442     {
00443         QString genre_name = (*p).trimmed();
00444         if (genre_name.length())
00445         {
00446             video_genres.push_back(
00447                     VideoMetadata::genre_list::value_type(-1, genre_name));
00448         }
00449     }
00450 
00451     metadata->SetGenres(video_genres);
00452 
00453     // Countries
00454     VideoMetadata::country_list video_countries;
00455     QStringList countries = lookup->GetCountries();
00456 
00457     for (QStringList::const_iterator p = countries.begin();
00458         p != countries.end(); ++p)
00459     {
00460         QString country_name = (*p).trimmed();
00461         if (country_name.length())
00462         {
00463             video_countries.push_back(
00464                     VideoMetadata::country_list::value_type(-1,
00465                             country_name));
00466         }
00467     }
00468 
00469     metadata->SetCountries(video_countries);
00470 
00471     ArtworkMap map = lookup->GetDownloads();
00472 
00473     QUrl coverurl(map.value(kArtworkCoverart).url);
00474     if (!coverurl.path().isEmpty())
00475         metadata->SetCoverFile(coverurl.path().remove(0,1));
00476 
00477     QUrl fanarturl(map.value(kArtworkFanart).url);
00478     if (!fanarturl.path().isEmpty())
00479         metadata->SetFanart(fanarturl.path().remove(0,1));
00480 
00481     QUrl bannerurl(map.value(kArtworkBanner).url);
00482     if (!bannerurl.path().isEmpty())
00483         metadata->SetBanner(bannerurl.path().remove(0,1));
00484 
00485     QUrl sshoturl(map.value(kArtworkScreenshot).url);
00486     if (!sshoturl.path().isEmpty())
00487         metadata->SetScreenshot(sshoturl.path().remove(0,1));
00488 
00489     metadata->SetProcessed(true);
00490     metadata->UpdateDatabase();
00491 
00492     if (gCoreContext->HasGUI() && m_parent)
00493     {
00494         QCoreApplication::postEvent(m_parent,
00495             new MetadataFactorySingleResult(lookup));
00496     }
00497     else
00498     {
00499         lookup->deleteLater();
00500     }
00501 }
00502 
00503 void MetadataFactory::customEvent(QEvent *levent)
00504 {
00505     if (levent->type() == MetadataLookupEvent::kEventType)
00506     {
00507         MetadataLookupEvent *lue = (MetadataLookupEvent *)levent;
00508 
00509         MetadataLookupList lul = lue->lookupList;
00510 
00511         if (lul.isEmpty())
00512             return;
00513 
00514         if (m_sync)
00515         {
00516             m_returnList = lul;
00517         }
00518         else if (lul.count() == 1)
00519         {
00520             OnSingleResult(lul.takeFirst());
00521         }
00522         else
00523         {
00524             OnMultiResult(lul);
00525         }
00526     }
00527     else if (levent->type() == MetadataLookupFailure::kEventType)
00528     {
00529         MetadataLookupFailure *luf = (MetadataLookupFailure *)levent;
00530 
00531         MetadataLookupList lul = luf->lookupList;
00532 
00533         if (lul.isEmpty())
00534             return;
00535 
00536         if (m_sync)
00537         {
00538             m_returnList = MetadataLookupList();
00539             m_sync = false;
00540         }
00541         if (lul.size())
00542         {
00543             OnNoResult(lul.takeFirst());
00544         }
00545     }
00546     else if (levent->type() == ImageDLEvent::kEventType)
00547     {
00548         ImageDLEvent *ide = (ImageDLEvent *)levent;
00549 
00550         MetadataLookup *lookup = ide->item;
00551 
00552         if (!lookup)
00553             return;
00554 
00555         if (m_scanning)
00556             OnVideoResult(lookup);
00557         else
00558             OnImageResult(lookup);
00559     }
00560     else if (levent->type() == VideoScanChanges::kEventType)
00561     {
00562         VideoScanChanges *vsc = (VideoScanChanges *)levent;
00563 
00564         if (!vsc)
00565             return;
00566 
00567         QList<int> additions = vsc->additions;
00568         QList<int> moves = vsc->moved;
00569         QList<int> deletions = vsc->deleted;
00570 
00571         if (!m_scanning)
00572         {
00573             LOG(VB_GENERAL, LOG_INFO,
00574                 QString("Video Scan Complete: a(%1) m(%2) d(%3)")
00575                 .arg(additions.count()).arg(moves.count())
00576                 .arg(deletions.count()));
00577 
00578             if (m_parent)
00579                 QCoreApplication::postEvent(m_parent,
00580                     new MetadataFactoryVideoChanges(additions, moves,
00581                                                     deletions));
00582         }
00583         else
00584         {
00585             LOG(VB_GENERAL, LOG_INFO,
00586                 QString("Video Scan Complete: a(%1) m(%2) d(%3)")
00587                 .arg(additions.count()).arg(moves.count())
00588                 .arg(deletions.count()));
00589 
00590             VideoMetadataListManager::metadata_list ml;
00591             VideoMetadataListManager::loadAllFromDatabase(ml);
00592             m_mlm->setList(ml);
00593 
00594             for (QList<int>::const_iterator it = additions.begin();
00595                 it != additions.end(); ++it)
00596             {
00597                 VideoMetadata *metadata = m_mlm->byID(*it).get();
00598 
00599                 if (metadata)
00600                     Lookup(metadata, true, true);
00601             }
00602         }
00603         m_videoscanner->ResetCounts();
00604     }
00605 }
00606 
00607 // These functions exist to determine if we have enough
00608 // information to conclusively call something a Show vs. Movie
00609 
00610 LookupType GuessLookupType(ProgramInfo *pginfo)
00611 {
00612     LookupType ret = kUnknownVideo;
00613 
00614     QString catType = pginfo->GetCategoryType();
00615     if (catType.isEmpty())
00616         catType = pginfo->QueryCategoryType();
00617 
00618     if ((!pginfo->GetSubtitle().isEmpty() || pginfo->GetEpisode() > 0) &&
00619        (catType == "series" || catType == "tvshow" ||
00620         catType == "show"))
00621         ret = kProbableTelevision;
00622     else if (catType == "movie" || catType == "film")
00623         ret = kProbableMovie;
00624     else if (pginfo->GetSeason() > 0 || pginfo->GetEpisode() > 0 ||
00625         !pginfo->GetSubtitle().isEmpty())
00626         ret = kProbableTelevision;
00627     else
00628     {
00629         // Before committing to something being a movie, we
00630         // want to check its rule.  If the rule has a season
00631         // or episode number, but the recording doesn't,
00632         // and the rec doesn't have a subtitle, this is a
00633         // generic recording. If neither the rule nor the
00634         // recording have an inetref, season, episode, or
00635         // subtitle, it's *probably* a movie.  If it's some
00636         // weird combination of both, we've got to try everything.
00637         RecordingRule *rule = new RecordingRule();
00638         rule->m_recordID = pginfo->GetRecordingRuleID();
00639         rule->Load();
00640         int ruleepisode = rule->m_episode;
00641         delete rule;
00642 
00643         if (ruleepisode == 0 && pginfo->GetEpisode() == 0 &&
00644             pginfo->GetSubtitle().isEmpty())
00645             ret = kProbableMovie;
00646         else if (ruleepisode > 0 && pginfo->GetSubtitle().isEmpty())
00647             ret = kProbableGenericTelevision;
00648         else
00649             ret = kUnknownVideo;
00650     }
00651 
00652     return ret;
00653 }
00654 
00655 LookupType GuessLookupType(MetadataLookup *lookup)
00656 {
00657     LookupType ret = kUnknownVideo;
00658 
00659     if (lookup->GetSeason() > 0 || lookup->GetEpisode() > 0 ||
00660         !lookup->GetSubtitle().isEmpty())
00661         ret = kProbableTelevision;
00662     else
00663         ret = kProbableMovie;
00664 
00665     return ret;
00666 }
00667 
00668 
00669 LookupType GuessLookupType(RecordingRule *recrule)
00670 {
00671     LookupType ret = kUnknownVideo;
00672 
00673     if (recrule->m_season > 0 || recrule->m_episode > 0 ||
00674         !recrule->m_subtitle.isEmpty())
00675         ret = kProbableTelevision;
00676     else
00677         ret = kProbableMovie;
00678 
00679     return ret;
00680 }
00681 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends