diff --git a/mythtv/bindings/python/tmdb3/tmdb3/lookup.py b/mythtv/bindings/python/tmdb3/tmdb3/lookup.py index 614797a7e9c..8830de63557 100644 --- a/mythtv/bindings/python/tmdb3/tmdb3/lookup.py +++ b/mythtv/bindings/python/tmdb3/tmdb3/lookup.py @@ -12,7 +12,7 @@ #----------------------- __title__ = "TheMovieDB.org V3" __author__ = "Raymond Wagner, Roland Ernst" -__version__ = "0.3.11" +__version__ = "0.3.12" # 0.1.0 Initial version # 0.2.0 Add language support, move cache to home directory # 0.3.0 Enable version detection to allow use in MythTV @@ -32,6 +32,7 @@ # 0.3.9 Support TV lookup # 0.3.10 Use new API for release dates for movies # 0.3.11 Allow queries for specials in series in TV lookup +# 0.3.12 `buildMovieList` searches now for movies with year # ~ from optparse import OptionParser import sys @@ -189,10 +190,10 @@ def buildMovieList(query, opts): # as negative to all text that comes afterwards query = query.replace('-',' ') - from MythTV.tmdb3 import searchMovie + from MythTV.tmdb3 import searchMovieWithYear from MythTV import VideoMetadata from lxml import etree - results = iter(searchMovie(query)) + results = iter(searchMovieWithYear(query)) tree = etree.XML('') mapping = [['runtime', 'runtime'], ['title', 'originaltitle'], ['releasedate', 'releasedate'], ['tagline', 'tagline'], diff --git a/mythtv/libs/libmythmetadata/metadatadownload.cpp b/mythtv/libs/libmythmetadata/metadatadownload.cpp index a272fc3db7c..ecfeed8e0e3 100644 --- a/mythtv/libs/libmythmetadata/metadatadownload.cpp +++ b/mythtv/libs/libmythmetadata/metadatadownload.cpp @@ -6,6 +6,7 @@ #include #include #include +#include // myth #include "libmythbase/mythcorecontext.h" @@ -199,7 +200,7 @@ void MetadataDownload::run() MetadataLookup *newlookup = list.takeFirst(); // pass through automatic type - newlookup->SetAutomatic(true); // ### XXX RER + newlookup->SetAutomatic(true); newlookup->SetStep(kLookupData); // Type may have changed LookupType ret = GuessLookupType(newlookup); @@ -252,11 +253,20 @@ unsigned int MetadataDownload::findExactMatchCount(MetadataLookupList list, { unsigned int exactMatches = 0; unsigned int exactMatchesWithArt = 0; + static const QRegularExpression year { R"( \(\d{4}\)$)" }; for (const auto& lkup : std::as_const(list)) { - // Consider exact title matches (ignoring case) - if ((QString::compare(lkup->GetTitle(), originaltitle, Qt::CaseInsensitive) == 0)) + // Consider exact title matches with or without trailing '(year)' (ignoring case) + QString titlewoyear = originaltitle; + auto match = year.match(titlewoyear); + if (match.hasMatch()) + { + titlewoyear.remove(match.capturedStart(), match.capturedLength()); + } + + if ((QString::compare(lkup->GetTitle(), originaltitle, Qt::CaseInsensitive) == 0) || + (QString::compare(lkup->GetTitle(), titlewoyear, Qt::CaseInsensitive) == 0)) { // In lookup by name, the television database tends to only include Banner artwork. // In lookup by name, the movie database tends to include only Fan and Cover artwork. @@ -285,24 +295,53 @@ MetadataLookup* MetadataDownload::findBestMatch(MetadataLookupList list, int exactMatches = 0; int exactMatchesWithArt = 0; bool foundMatchWithArt = false; + bool foundMatchWithYear = false; + uint year = 0; + + QString titlewoyear = originaltitle; + + static const QRegularExpression regexyear { R"( \(\d{4}\)$)" }; + + auto match = regexyear.match(titlewoyear); + if (match.hasMatch()) + { + titlewoyear.remove(match.capturedStart(), match.capturedLength()); + year = match.captured(0).replace(" (","").replace(")","").toUInt(); + LOG(VB_GENERAL, LOG_DEBUG, QString("Looking for: '%1' with release year: '%2'") + .arg(titlewoyear, QString::number(year))); + } // Build a list of all the titles for (const auto& lkup : std::as_const(list)) { QString title = lkup->GetTitle(); - LOG(VB_GENERAL, LOG_INFO, QString("Comparing metadata title '%1' [%2] to recording title '%3'") - .arg(title, lkup->GetReleaseDate().toString(), originaltitle)); - // Consider exact title matches (ignoring case), which have some artwork available. - if (QString::compare(title, originaltitle, Qt::CaseInsensitive) == 0) + LOG(VB_GENERAL, LOG_INFO, + QString("Comparing metadata title '%1' [%2] to recording title '%3' [%4]") + .arg(title, lkup->GetReleaseDate().toString(), titlewoyear, + (year == 0) ? "N/A" : QString::number(year))); + + // Consider exact title matches with or without trailing '(year)' (ignoring case), + // which have some artwork available. + if ((QString::compare(title, originaltitle, Qt::CaseInsensitive) == 0) || + (QString::compare(title, titlewoyear, Qt::CaseInsensitive) == 0)) { bool hasArtwork = ((!(lkup->GetArtwork(kArtworkFanart)).empty()) || (!(lkup->GetArtwork(kArtworkCoverart)).empty()) || (!(lkup->GetArtwork(kArtworkBanner)).empty())); - LOG(VB_GENERAL, LOG_INFO, QString("'%1', popularity = %2, ReleaseDate = %3") + if ((lkup->GetYear() != 0) && (year == lkup->GetYear())) + { + exactTitleDate = lkup->GetReleaseDate(); + exactTitlePopularity = lkup->GetPopularity(); + foundMatchWithYear = true; + ret = lkup; + } + + LOG(VB_GENERAL, LOG_INFO, QString("'%1', popularity = %2, ReleaseDate = %3, Year = %4") .arg(title) .arg(lkup->GetPopularity()) - .arg(lkup->GetReleaseDate().toString())); + .arg(lkup->GetReleaseDate().toString()) + .arg(lkup->GetYear())); // After the first exact match, prefer any more popular one. // Most of the Movie database entries have Popularity fields. @@ -310,8 +349,9 @@ MetadataLookup* MetadataDownload::findBestMatch(MetadataLookupList list, // so if none are found so far in the search, pick the most recently // released entry with artwork. Also, if the first exact match had // no artwork, prefer any later exact match with artwork. + // Stop searching if we have already found a match with correct year. if ((ret == nullptr) || - (hasArtwork && + (hasArtwork && !foundMatchWithYear && ((!foundMatchWithArt) || ((lkup->GetPopularity() > exactTitlePopularity)) || ((exactTitlePopularity == 0.0F) && (lkup->GetReleaseDate() > exactTitleDate))))) @@ -320,6 +360,7 @@ MetadataLookup* MetadataDownload::findBestMatch(MetadataLookupList list, exactTitlePopularity = lkup->GetPopularity(); ret = lkup; } + exactMatches++; if (hasArtwork) { @@ -348,8 +389,10 @@ MetadataLookup* MetadataDownload::findBestMatch(MetadataLookupList list, { LOG(VB_GENERAL, LOG_INFO, QString("Multiple exact title matches found for '%1'. " - "Selecting most popular or most recent [%2]") - .arg(originaltitle, exactTitleDate.toString())); + "Selecting by exact year [%2] or most popular or most recent [%3]") + .arg(originaltitle, + (year == 0) ? "N/A" : QString::number(year), + exactTitleDate.toString())); } return ret; } diff --git a/mythtv/libs/libmythmetadata/test/test_videometadata/test_videometadata.h b/mythtv/libs/libmythmetadata/test/test_videometadata/test_videometadata.h index 58e2d0094a0..3f510fc96ea 100644 --- a/mythtv/libs/libmythmetadata/test/test_videometadata/test_videometadata.h +++ b/mythtv/libs/libmythmetadata/test/test_videometadata/test_videometadata.h @@ -62,7 +62,7 @@ class Testvideometadata: public QObject { // With Spaces as separator TestMetadata(QString("A Movie Title (1984).mpg"), - QString("A Movie Title"), + QString("A Movie Title (1984)"), QString(""), 0, 0); diff --git a/mythtv/libs/libmythmetadata/videometadata.cpp b/mythtv/libs/libmythmetadata/videometadata.cpp index 347a898d151..e4f50d0bec2 100644 --- a/mythtv/libs/libmythmetadata/videometadata.cpp +++ b/mythtv/libs/libmythmetadata/videometadata.cpp @@ -1210,8 +1210,8 @@ QString VideoMetadata::FilenameToMeta(const QString &file_name, int position) title = title.right(title.length() - title.lastIndexOf('/') -1); + // Allow parentheses "()", but remove content inside other braces title = eatBraces(title, "[", "]"); - title = eatBraces(title, "(", ")"); title = eatBraces(title, "{", "}"); return title.trimmed(); }