|
MythTV
0.26-pre
|
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
1.7.6.1