Go to the documentation of this file.
7 #include <QRegularExpression>
36 QString hash, QString trailer,
37 QString coverfile, QString screenshot, QString banner,
38 QString fanart,
const QString &title, QString sortTitle,
39 const QString &subtitle, QString sortSubtitle,
40 QString tagline,
int year,
const QDate releasedate,
41 QString inetref,
int collectionref, QString homepage,
42 QString director, QString studio,
43 QString plot,
float userrating,
44 QString
rating,
int length,
int playcount,
45 int season,
int episode,
const QDate insertdate,
47 int childID,
bool browse,
bool watched,
48 QString playcommand, QString category,
53 bool processed =
false,
75 if (title.isEmpty() and subtitle.isEmpty()
76 and season == 0 and episode == 0)
174 void SetTitle(
const QString& title,
const QString& sortTitle =
"")
183 void SetSubtitle(
const QString &subtitle,
const QString &sortSubtitle =
"") {
333 QString
GetImage(
const QString &name)
const;
415 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
416 QFileInfoList contents =
d.entryInfoList();
417 if (contents.empty())
419 return d.rmdir(dirName);
422 for (
const auto& entry : std::as_const(contents))
426 QString fileName = entry.fileName();
432 if (!QFile(entry.fileName()).remove())
436 return d.rmdir(dirName);
442 bool isremoved =
false;
464 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Could not delete file: %1")
503 for (
long value : genres.
values)
521 for (
long value : countries.
values)
539 for (
long value : cast.
values)
544 m_cast.emplace_back(value, name);
627 QString coverfile = metadataMap[
"coverfile"];
628 QString screenshot = metadataMap[
"screenshotfile"];
629 QString bannerfile = metadataMap[
"bannerfile"];
630 QString fanartfile = metadataMap[
"fanartfile"];
646 if (m_userrating < -10.0F || m_userrating > 10.0F)
658 bool inserting =
m_id == 0;
668 query.
prepare(
"INSERT INTO videometadata (title,subtitle,tagline,director,studio,plot,"
669 "rating,year,userrating,length,season,episode,filename,hash,"
670 "showlevel,coverfile,inetref,homepage,browse,watched,trailer,"
671 "screenshot,banner,fanart,host,processed,contenttype) VALUES (:TITLE, :SUBTITLE, "
672 ":TAGLINE, :DIRECTOR, :STUDIO, :PLOT, :RATING, :YEAR, :USERRATING, "
673 ":LENGTH, :SEASON, :EPISODE, :FILENAME, :HASH, :SHOWLEVEL, "
674 ":COVERFILE, :INETREF, :HOMEPAGE, :BROWSE, :WATCHED, "
675 ":TRAILER, :SCREENSHOT, :BANNER, :FANART, :HOST, :PROCESSED, :CONTENTTYPE)");
679 query.
prepare(
"UPDATE videometadata SET title = :TITLE, subtitle = :SUBTITLE, "
680 "tagline = :TAGLINE, director = :DIRECTOR, studio = :STUDIO, "
681 "plot = :PLOT, rating= :RATING, year = :YEAR, "
682 "releasedate = :RELEASEDATE, userrating = :USERRATING, "
683 "length = :LENGTH, playcount = :PLAYCOUNT, season = :SEASON, "
684 "episode = :EPISODE, filename = :FILENAME, hash = :HASH, trailer = :TRAILER, "
685 "showlevel = :SHOWLEVEL, coverfile = :COVERFILE, "
686 "screenshot = :SCREENSHOT, banner = :BANNER, fanart = :FANART, "
687 "inetref = :INETREF, collectionref = :COLLECTION, homepage = :HOMEPAGE, "
688 "browse = :BROWSE, watched = :WATCHED, host = :HOST, playcommand = :PLAYCOMMAND, "
689 "childid = :CHILDID, category = :CATEGORY, processed = :PROCESSED, "
690 "contenttype = :CONTENTTYPE WHERE intid = :INTID");
740 if (!query.
exec(
"SELECT LAST_INSERT_ID()") || !query.
next())
750 LOG(VB_GENERAL, LOG_ERR,
751 QString(
"%1: The id of the last inserted row to "
752 "videometadata seems to be 0. This is odd.")
780 query.
prepare(
"DELETE FROM videometadata WHERE intid = :ID");
787 query.
prepare(
"DELETE FROM filemarkup WHERE filename = :FILENAME");
816 LOG(VB_GENERAL, LOG_ERR,
"Unknown category id");
830 if (!genre->second.trimmed().isEmpty())
851 if (!country->second.trimmed().isEmpty())
869 auto cast =
m_cast.begin();
870 while (cast !=
m_cast.end())
872 if (!cast->second.trimmed().isEmpty())
880 cast =
m_cast.erase(cast);
901 imageMap[QStringLiteral(u
"coverfile")] = coverfile;
902 imageMap[QStringLiteral(u
"coverart")] = coverfile;
904 QString screenshotfile;
916 imageMap[QStringLiteral(u
"screenshotfile")] = screenshotfile;
917 imageMap[QStringLiteral(u
"screenshot")] = screenshotfile;
931 imageMap[QStringLiteral(u
"bannerfile")] = bannerfile;
932 imageMap[QStringLiteral(u
"banner")] = bannerfile;
946 imageMap[QStringLiteral(u
"fanartfile")] = fanartfile;
947 imageMap[QStringLiteral(u
"fanart")] = fanartfile;
949 QString smartimage = coverfile;
951 smartimage = screenshotfile;
952 imageMap[QStringLiteral(u
"smartimage")] = smartimage;
959 if ((name == QStringLiteral(u
"coverfile")) ||
960 (name == QStringLiteral(u
"coverart")))
964 && !coverfile.startsWith(u
'/')
965 && !coverfile.isEmpty()
972 if ((name == QStringLiteral(u
"screenshotfile")) ||
973 (name == QStringLiteral(u
"screenshot")))
976 if (
IsHostSet() && !screenshot.startsWith(u
'/')
977 && !screenshot.isEmpty())
983 if ((name == QStringLiteral(u
"bannerfile")) ||
984 (name == QStringLiteral(u
"banner")))
987 if (
IsHostSet() && !bannerfile.startsWith(u
'/')
988 && !bannerfile.isEmpty())
994 if ((name == QStringLiteral(u
"fanartfile")) ||
995 (name == QStringLiteral(u
"fanart")))
998 if (
IsHostSet() && !fanartfile.startsWith(
'/')
999 && !fanartfile.isEmpty())
1005 if ((name == QStringLiteral(u
"smartimage")) ||
1006 (name == QStringLiteral(u
"buttonimage")))
1010 QString screenshotfile =
GetImage(
"screenshot");
1011 if (!screenshotfile.isEmpty())
1012 return screenshotfile;
1025 QString
eatBraces(
const QString &title,
const QString &left_brace,
1026 const QString &right_brace)
1029 bool keep_checking =
true;
1031 while (keep_checking)
1033 int left_position = ret.indexOf(left_brace);
1034 int right_position = ret.indexOf(right_brace);
1035 if (left_position == -1 || right_position == -1)
1041 keep_checking =
false;
1045 if (left_position < right_position)
1051 ret = ret.left(left_position) +
1052 ret.right(ret.length() - right_position - 1);
1054 else if (left_position > right_position)
1060 ret = ret.left(right_position) +
1061 ret.right(ret.length() - left_position - 1);
1071 const QString &file_name,
1072 const QString &host)
1076 query.
prepare(
"SELECT intid,filename FROM videometadata WHERE "
1089 int intid = query.
value(0).toInt();
1090 QString oldfilename = query.
value(1).toString();
1092 query.
prepare(
"UPDATE videometadata SET filename = :FILENAME, "
1093 "host = :HOST WHERE intid = :INTID");
1094 query.
bindValue(
":FILENAME", file_name);
1100 MythDB::DBError(
"Video hashed metadata update (videometadata)", query);
1104 query.
prepare(
"UPDATE filemarkup SET filename = :FILENAME "
1105 "WHERE filename = :OLDFILENAME");
1106 query.
bindValue(
":FILENAME", file_name);
1107 query.
bindValue(
":OLDFILENAME", oldfilename);
1119 const QString &host)
1127 QString fullname = sgroup.
FindFile(file_name);
1142 QString cleanFilename = file_name.left(file_name.lastIndexOf(
'.'));
1143 static const QRegularExpression kSpaceRE {
"%20" };
1144 static const QRegularExpression kUnderscoreRE {
"_" };
1145 static const QRegularExpression kDotRE {
"\\." };
1146 cleanFilename.replace(kSpaceRE,
" ");
1147 cleanFilename.replace(kUnderscoreRE,
" ");
1148 cleanFilename.replace(kDotRE,
" ");
1153 QString season_translation = tr(
"Season",
"Metadata file name parsing");
1158 QString episode_translation = tr(
"Episode",
"Metadata file name parsing");
1161 QString separator =
"(?:\\s?(?:-|/)?\\s?)?";
1162 QString regexp = QString(
1165 "(?:s|(?:Season|%2))?"
1169 "(?:[ex/]|Episode|%3)"
1174 ).arg(separator, season_translation, episode_translation);
1175 static const QRegularExpression filename_parse { regexp,
1176 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
1179 QString regexp2 = QString(
"(%1(?:(?:Season|%2)%1\\d*%1)*%1)$")
1180 .arg(separator, season_translation);
1181 static const QRegularExpression title_parse {regexp2,
1182 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
1184 auto match = filename_parse.match(cleanFilename);
1185 if (match.hasMatch())
1188 if (position == 1 && !match.capturedView(1).isEmpty())
1191 QString title = match.captured(1);
1192 match = title_parse.match(title);
1193 if (match.hasMatch())
1194 title = title.left(match.capturedStart());
1195 title = title.right(title.length() - title.lastIndexOf(
'/') -1);
1196 return title.trimmed();
1199 return match.captured(2).trimmed();
1201 return match.captured(3).trimmed();
1203 return match.captured(4).trimmed();
1205 else if (position == 1)
1207 QString title = cleanFilename;
1210 title = title.right(title.length() -
1211 title.lastIndexOf(
'/') -1);
1216 return title.trimmed();
1218 else if (position == 2 || position == 3)
1227 const QString &hash,
const QString &trailer,
const QString &coverfile,
1228 const QString &screenshot,
const QString &banner,
const QString &fanart,
1229 const QString &title,
const QString &sortTitle,
1230 const QString &subtitle,
const QString &sortSubtitle,
const QString &tagline,
1231 int year,
const QDate releasedate,
const QString &inetref,
int collectionref,
1232 const QString &homepage,
const QString &director,
const QString &studio,
1233 const QString &plot,
float userrating,
const QString &
rating,
1234 int length,
int playcount,
int season,
int episode,
const QDate insertdate,
1236 int childID,
bool browse,
bool watched,
1237 const QString &playcommand,
const QString &category,
1241 const QString &host,
bool processed,
1245 screenshot, banner, fanart, title, sortTitle, subtitle,
1246 sortSubtitle, tagline, year, releasedate, inetref,
1247 collectionref, homepage, director, studio, plot, userrating,
rating,
1248 length, playcount, season, episode, insertdate,
id, showlevel, categoryID,
1249 childID, browse, watched, playcommand, category, genres, countries,
1250 cast, host, processed, contenttype);
1282 metadataMap[QStringLiteral(u
"filename")] =
GetFilename();
1284 metadataMap[QStringLiteral(u
"title")] =
GetTitle();
1285 metadataMap[QStringLiteral(u
"sorttitle")] =
GetSortTitle();
1286 metadataMap[QStringLiteral(u
"subtitle")] =
GetSubtitle();
1288 metadataMap[QStringLiteral(u
"tagline")] =
GetTagline();
1289 metadataMap[QStringLiteral(u
"director")] =
GetDirector();
1290 metadataMap[QStringLiteral(u
"studio")] =
GetStudio();
1291 metadataMap[QStringLiteral(u
"description0")] = metadataMap[QStringLiteral(u
"description")] =
GetPlot();
1294 metadataMap[QStringLiteral(u
"cast")] =
GetDisplayCast(*this).join(
", ");
1297 metadataMap[QStringLiteral(u
"playcount")] = QString::number(
GetPlayCount());
1309 QString usingSE = QStringLiteral(u
"s%1e%2")
1312 metadataMap[QStringLiteral(u
"s##e##")] = metadataMap[QStringLiteral(u
"s00e00")] = usingSE;
1313 QString usingX = QStringLiteral(u
"%1x%2")
1316 metadataMap[QStringLiteral(u
"##x##")] = metadataMap[QStringLiteral(u
"00x00")] = usingX;
1320 metadataMap[QStringLiteral(u
"s##e##")] = metadataMap[QStringLiteral(u
"##x##")] = QString();
1321 metadataMap[QStringLiteral(u
"s00e00")] = metadataMap[QStringLiteral(u
"00x00")] = QString();
1322 metadataMap[QStringLiteral(u
"season")] = metadataMap[QStringLiteral(u
"episode")] = QString();
1329 metadataMap[QStringLiteral(u
"inetref")] =
GetInetRef();
1330 metadataMap[QStringLiteral(u
"homepage")] =
GetHomepage();
1331 metadataMap[QStringLiteral(u
"child_id")] = QString::number(
GetChildID());
1335 metadataMap[QStringLiteral(u
"category")] =
GetCategory();
1342 if (name == QStringLiteral(u
"filename"))
1344 if (name == QStringLiteral(u
"sortfilename"))
1346 if (name == QStringLiteral(u
"title"))
1348 if (name == QStringLiteral(u
"sorttitle"))
1350 if (name == QStringLiteral(u
"subtitle"))
1352 if (name == QStringLiteral(u
"sortsubtitle"))
1354 if (name == QStringLiteral(u
"tagline"))
1356 if (name == QStringLiteral(u
"director"))
1358 if (name == QStringLiteral(u
"studio"))
1360 if ((name == QStringLiteral(u
"description")) ||
1361 (name == QStringLiteral(u
"description0")))
1363 if (name == QStringLiteral(u
"genres"))
1365 if (name == QStringLiteral(u
"countries"))
1367 if (name == QStringLiteral(u
"cast"))
1369 if (name == QStringLiteral(u
"rating"))
1371 if (name == QStringLiteral(u
"length"))
1373 if (name == QStringLiteral(u
"playcount"))
1375 if (name == QStringLiteral(u
"year"))
1378 if (name == QStringLiteral(u
"releasedate"))
1381 if (name == QStringLiteral(u
"userrating"))
1386 if (name == QStringLiteral(u
"season"))
1388 if (name == QStringLiteral(u
"episode"))
1390 if ((name == QStringLiteral(u
"s##e##")) ||
1391 (name == QStringLiteral(u
"s00e00")))
1393 return QStringLiteral(u
"s%1e%2")
1397 if ((name == QStringLiteral(u
"##x##")) ||
1398 (name == QStringLiteral(u
"00x00")))
1400 return QStringLiteral(u
"%1x%2")
1406 if (name == QStringLiteral(u
"insertdate"))
1409 if (name == QStringLiteral(u
"inetref"))
1411 if (name == QStringLiteral(u
"homepage"))
1413 if (name == QStringLiteral(u
"child_id"))
1415 if (name == QStringLiteral(u
"browseable"))
1417 if (name == QStringLiteral(u
"watched"))
1419 if (name == QStringLiteral(u
"processed"))
1421 if (name == QStringLiteral(u
"category"))
1429 stateMap[QStringLiteral(u
"userratingstate")] =
1439 if (name == QStringLiteral(u
"trailerstate"))
1441 if (name == QStringLiteral(u
"userratingstate"))
1443 if (name == QStringLiteral(u
"watchedstate"))
1445 if (name == QStringLiteral(u
"videolevel"))
1462 metadataMap[
"coverfile"] =
"";
1463 metadataMap[
"screenshotfile"] =
"";
1464 metadataMap[
"bannerfile"] =
"";
1465 metadataMap[
"fanartfile"] =
"";
1466 metadataMap[
"filename"] =
"";
1467 metadataMap[
"sortfilename"] =
"";
1468 metadataMap[
"title"] =
"";
1469 metadataMap[
"sorttitle"] =
"";
1470 metadataMap[
"subtitle"] =
"";
1471 metadataMap[
"sortsubtitle"] =
"";
1472 metadataMap[
"tagline"] =
"";
1473 metadataMap[
"director"] =
"";
1474 metadataMap[
"studio"] =
"";
1475 metadataMap[
"description"] =
"";
1476 metadataMap[
"description0"] =
"";
1477 metadataMap[
"genres"] =
"";
1478 metadataMap[
"countries"] =
"";
1479 metadataMap[
"cast"] =
"";
1480 metadataMap[
"rating"] =
"";
1481 metadataMap[
"length"] =
"";
1482 metadataMap[
"playcount"] =
"";
1483 metadataMap[
"year"] =
"";
1484 metadataMap[
"releasedate"] =
"";
1485 metadataMap[
"userrating"] =
"";
1486 metadataMap[
"season"] =
"";
1487 metadataMap[
"episode"] =
"";
1488 metadataMap[
"s##e##"] =
"";
1489 metadataMap[
"##x##"] =
"";
1490 metadataMap[
"trailerstate"] =
"";
1491 metadataMap[
"userratingstate"] =
"";
1492 metadataMap[
"watchedstate"] =
"";
1493 metadataMap[
"videolevel"] =
"";
1494 metadataMap[
"insertdate"] =
"";
1495 metadataMap[
"inetref"] =
"";
1496 metadataMap[
"homepage"] =
"";
1497 metadataMap[
"child_id"] =
"";
1498 metadataMap[
"browseable"] =
"";
1499 metadataMap[
"watched"] =
"";
1500 metadataMap[
"category"] =
"";
1501 metadataMap[
"processed"] =
"";
1506 if (data ==
nullptr)
1509 QString result = metadata->
GetText(name);
1510 if (!result.isEmpty())
1512 result = metadata->GetImage(name);
1513 if (!result.isEmpty())
1515 return metadata->GetState(name);
1520 if (data ==
nullptr)
1528 if (data ==
nullptr)
1967 if (
m_imp->getID() == 0)
bool isActive(void) const
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
QString WatchedToState(bool watched)
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.
int add(const QString &name)
static bool Exists(const QString &url, struct stat *fileinfo)
QString FindFile(const QString &filename)
QVariant value(int i) const
QString GetDisplayLength(std::chrono::minutes length)
QString GetDisplayProcessed(bool processed)
VideoContentType ContentTypeFromString(const QString &type)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
QString ContentTypeToString(VideoContentType type)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QString doPathname(const QString &pathname) const
Create the sortable form of an item.
QHash< QString, QString > InfoMap
static VideoGenreMap & getGenreMap()
bool IsMasterBackend(void)
is this the actual MBE process
QString GetDisplayRating(const QString &rating)
static VideoGenre & getGenre()
QString doTitle(const QString &title) const
Create the sortable form of an title string.
QString GetDisplayUserRating(float userrating)
int add(int id, int value)
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
QString GetDisplayCountries(const VideoMetadata &item)
static void DBError(const QString &where, const MSqlQuery &query)
def rating(profile, smoonURL, gate)
MBASE_PUBLIC int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity=Qt::CaseSensitive)
This method chops the input a and b into pieces of digits and non-digits (a1.05 becomes a | 1 | .
const QString VIDEO_COVERFILE_DEFAULT
const QString VIDEO_PLOT_DEFAULT
static QString GetFileHash(const QString &url)
QString GetDisplayBrowse(bool browse)
static VideoCountry & getCountry()
int ternary_compare(const QDateTime &a, const QDateTime &b)
balanced ternary (three way) comparison This is equivalent to C++20's operator <=>.
QString intToPaddedString(int n, int width=2)
Creates a zero padded string representation of an integer.
static bool DeleteFile(const QString &url)
static VideoCategory & GetCategory()
const QString VIDEO_TRAILER_DEFAULT
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
const QString VIDEO_INETREF_DEFAULT
const QString VIDEO_FANART_DEFAULT
QString ParentalLevelToState(const ParentalLevel &level)
bool IsDefaultCoverFile(const QString &coverfile)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
static VideoCountryMap & getCountryMap()
@ kAddYear
Add year to string if not included.
static VideoCast & GetCast()
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
const QString VIDEO_RATING_DEFAULT
bool get(int id, entry &values)
void remove(int id, int value)
VideoMetadata(const QString &filename=QString(), const QString &sortFilename=QString(), const QString &hash=QString(), const QString &trailer=QString(), const QString &coverfile=QString(), const QString &screenshot=QString(), const QString &banner=QString(), const QString &fanart=QString(), const QString &title=QString(), const QString &sortTitle=QString(), const QString &subtitle=QString(), const QString &sortSubtitle=QString(), const QString &tagline=QString(), int year=VIDEO_YEAR_DEFAULT, QDate releasedate=QDate(), const QString &inetref=QString(), int collectionref=0, const QString &homepage=QString(), const QString &director=QString(), const QString &studio=QString(), const QString &plot=QString(), float userrating=0.0, const QString &rating=QString(), int length=0, int playcount=0, int season=0, int episode=0, QDate insertdate=QDate(), int id=0, ParentalLevel::Level showlevel=ParentalLevel::plLowest, int categoryID=0, int childID=-1, bool browse=true, bool watched=false, const QString &playcommand=QString(), const QString &category=QString(), const genre_list &genres=genre_list(), const country_list &countries=country_list(), const cast_list &cast=cast_list(), const QString &host="", bool processed=false, VideoContentType contenttype=kContentUnknown)
@ kDateFull
Default local time.
QString GetDisplayGenres(const VideoMetadata &item)
bool IsThisHost(const QString &addr)
is this address mapped to this host
static VideoCastMap & getCastMap()
QString TrailerToState(const QString &trailerFile)
const QString VIDEO_BANNER_DEFAULT
static const iso6937table * d
QString FileHash(const QString &filename)
QString GetDisplayWatched(bool watched)
QStringList GetDisplayCast(const VideoMetadata &item)
bool get(int id, QString &category)
const QString VIDEO_DIRECTOR_DEFAULT
const QString VIDEO_SCREENSHOT_DEFAULT
QString GetDisplayYear(int year)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
const QString VIDEO_DIRECTOR_UNKNOWN