MythTV master
videometadata.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <cmath> // for isnan()
3
4#include <QDir>
5#include <QFile>
6#include <QFileInfo>
7#include <QRegularExpression>
8
11#include "libmythbase/mythdb.h"
13#include "libmythbase/mythmiscutil.h"// for FileHash
18
19#include "dbaccess.h"
20#include "globals.h"
22#include "videoutils.h"
23
25{
26 public:
30
31 public:
32 VideoMetadataImp(QString filename, QString sortFilename,
33 QString hash, QString trailer,
34 QString coverfile, QString screenshot, QString banner,
35 QString fanart, const QString &title, QString sortTitle,
36 const QString &subtitle, QString sortSubtitle,
37 QString tagline, int year, const QDate releasedate,
38 QString inetref, int collectionref, QString homepage,
39 QString director, QString studio,
40 QString plot, float userrating,
41 QString rating, int length, int playcount,
42 int season, int episode, const QDate insertdate,
43 int id, ParentalLevel::Level showlevel, int categoryID,
44 int childID, bool browse, bool watched,
45 QString playcommand, QString category,
46 genre_list genres,
47 country_list countries,
48 cast_list cast,
49 QString host = "",
50 bool processed = false,
51 VideoContentType contenttype = kContentUnknown) :
52 m_title(title), m_sortTitle(std::move(sortTitle)), m_subtitle(subtitle),
53 m_sortSubtitle(std::move(sortSubtitle)), m_tagline(std::move(tagline)),
54 m_inetref(std::move(inetref)), m_collectionref(collectionref),
55 m_homepage(std::move(homepage)), m_director(std::move(director)),
56 m_studio(std::move(studio)), m_plot(std::move(plot)),
57 m_rating(std::move(rating)), m_playcommand(std::move(playcommand)),
58 m_category(std::move(category)), m_genres(std::move(genres)),
59 m_countries(std::move(countries)), m_cast(std::move(cast)),
60 m_filename(std::move(filename)), m_sortFilename(std::move(sortFilename)),
61 m_hash(std::move(hash)), m_trailer(std::move(trailer)),
62 m_coverfile(std::move(coverfile)), m_screenshot(std::move(screenshot)),
63 m_banner(std::move(banner)), m_fanart(std::move(fanart)),
64 m_host(std::move(host)), m_categoryID(categoryID), m_childID(childID),
65 m_year(year), m_releasedate(releasedate), m_length(length), m_playcount(playcount),
66 m_season(season), m_episode(episode), m_insertdate(insertdate), m_showlevel(showlevel),
67 m_browse(browse), m_watched(watched), m_id(id),
68 m_userrating(userrating), m_processed(processed),
69 m_contenttype(contenttype)
70 {
71 // Try to glean data if none provided.
72 if (title.isEmpty() and subtitle.isEmpty()
73 and season == 0 and episode == 0)
74 {
79 }
80
82
84 }
85
86 explicit VideoMetadataImp(MSqlQuery &query)
87 {
88 fromDBRow(query);
90 }
91
93 {
94 *this = other;
95 }
96
98 {
99 if (this != &rhs)
100 {
101 m_title = rhs.m_title;
105 m_tagline = rhs.m_tagline;
106 m_inetref = rhs.m_inetref;
110 m_studio = rhs.m_studio;
111 m_plot = rhs.m_plot;
112 m_rating = rhs.m_rating;
115 m_genres = rhs.m_genres;
117 m_cast = rhs.m_cast;
120 m_hash = rhs.m_hash;
121 m_trailer = rhs.m_trailer;
124 m_banner = rhs.m_banner;
125 m_fanart = rhs.m_fanart;
126
128 m_childID = rhs.m_childID;
129 m_year = rhs.m_year;
131 m_length = rhs.m_length;
133 m_season = rhs.m_season;
134 m_episode = rhs.m_episode;
137 m_browse = rhs.m_browse;
138 m_watched = rhs.m_watched;
139 m_id = rhs.m_id;
141 m_host = rhs.m_host;
144
145 // No DB vars
146 m_prefix = rhs.m_prefix;
147
149 }
150
151 return *this;
152 }
153
155 {
156 std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
157 if (m_sortTitle.isEmpty() and not m_title.isEmpty())
158 m_sortTitle = sh->doTitle(m_title);
159 if (m_sortSubtitle.isEmpty() and not m_subtitle.isEmpty())
160 m_sortSubtitle = sh->doTitle(m_subtitle);
161 if (m_sortFilename.isEmpty() and not m_filename.isEmpty())
162 m_sortFilename = sh->doPathname(m_filename);
163 }
164
165 public:
166 const QString &GetPrefix() const { return m_prefix; }
167 void SetPrefix(const QString &prefix) { m_prefix = prefix; }
168
169 const QString &getTitle() const { return m_title; }
170 const QString &getSortTitle() const { return m_sortTitle; }
171 void SetTitle(const QString& title, const QString& sortTitle = "")
172 {
173 m_title = title;
174 m_sortTitle = sortTitle;
176 }
177
178 const QString &getSubtitle() const { return m_subtitle; }
179 const QString &getSortSubtitle() const { return m_sortSubtitle; }
180 void SetSubtitle(const QString &subtitle, const QString &sortSubtitle = "") {
181 m_subtitle = subtitle;
182 m_sortSubtitle = sortSubtitle;
184 }
185
186 const QString &GetTagline() const { return m_tagline; }
187 void SetTagline(const QString &tagline) { m_tagline = tagline; }
188
189 const QString &GetInetRef() const { return m_inetref; }
190 void SetInetRef(const QString &inetRef) { m_inetref = inetRef; }
191
192 int GetCollectionRef() const { return m_collectionref; }
193 void SetCollectionRef(int collectionref) { m_collectionref = collectionref; }
194
195 const QString &GetHomepage() const { return m_homepage; }
196 void SetHomepage(const QString &homepage) { m_homepage = homepage; }
197
198 const QString &getDirector() const { return m_director; }
199 void SetDirector(const QString &director) { m_director = director; }
200
201 const QString &getStudio() const { return m_studio; }
202 void SetStudio(const QString &studio) { m_studio = studio; }
203
204 const QString &getPlot() const { return m_plot; }
205 void SetPlot(const QString &plot) { m_plot = plot; }
206
207 const QString &GetRating() const { return m_rating; }
208 void SetRating(const QString &rating) { m_rating = rating; }
209
210 const QString &getPlayCommand() const { return m_playcommand; }
211 void SetPlayCommand(const QString &playCommand)
212 {
213 m_playcommand = playCommand;
214 }
215
216 const QString &GetCategory() const { return m_category; }
217// void SetCategory(const QString &category) { m_category = category; }
218
219 const genre_list &getGenres() const { return m_genres; }
220 void SetGenres(const genre_list &genres) { m_genres = genres; }
221
222 const country_list &GetCountries() const { return m_countries; }
223 void SetCountries(const country_list &countries)
224 {
225 m_countries = countries;
226 }
227
228 const cast_list &GetCast() const { return m_cast; }
229 void SetCast(const cast_list &cast) { m_cast = cast; }
230
231 const QString &GetHost() const { return m_host; }
232 void SetHost(const QString &host) { m_host = host; }
233
234 const QString &getFilename() const { return m_filename; }
235 const QString &getSortFilename() const { return m_sortFilename; }
236 void SetFilename(const QString &filename, const QString &sortFilename = "")
237 {
239 m_sortFilename = sortFilename;
241 }
242
243 bool sortBefore(const VideoMetadataImp *rhs) const;
244
245 const QString &GetHash() const { return m_hash; }
246 void SetHash(const QString &hash) { m_hash = hash; }
247
248 const QString &GetTrailer() const { return m_trailer; }
249 void SetTrailer(const QString &trailer) { m_trailer = trailer; }
250
251 const QString &GetCoverFile() const { return m_coverfile; }
252 void SetCoverFile(const QString &coverFile) { m_coverfile = coverFile; }
253
254 const QString &GetScreenshot() const { return m_screenshot; }
255 void SetScreenshot(const QString &screenshot) { m_screenshot = screenshot; }
256
257 const QString &GetBanner() const { return m_banner; }
258 void SetBanner(const QString &banner) { m_banner = banner; }
259
260 const QString &GetFanart() const { return m_fanart; }
261 void SetFanart(const QString &fanart) { m_fanart = fanart; }
262
263 int GetCategoryID() const
264 {
265 return m_categoryID;
266 }
267 void SetCategoryID(int id);
268
269 int GetChildID() const { return m_childID; }
270 void SetChildID(int childID) { m_childID = childID; }
271
272 int getYear() const { return m_year; }
273 void SetYear(int year) { m_year = year; }
274
275 QDate getReleaseDate() const { return m_releasedate; }
276 void SetReleaseDate(QDate releasedate) { m_releasedate = releasedate; }
277
278 std::chrono::minutes GetLength() const { return m_length; }
279 void SetLength(std::chrono::minutes length) { m_length = length; }
280
281 unsigned int GetPlayCount() const { return m_playcount; }
282 void SetPlayCount(int playcount) { m_playcount = playcount; }
283
284 int GetSeason() const { return m_season; }
285 void SetSeason(int season) { m_season = season; }
286
287 int GetEpisode() const { return m_episode; }
288 void SetEpisode(int episode) { m_episode = episode; }
289
290 QDate GetInsertdate() const { return m_insertdate;}
291 void SetInsertdate(QDate date) { m_insertdate = date;}
292
295 {
296 m_showlevel = ParentalLevel(showLevel).GetLevel();
297 }
298
299 bool GetBrowse() const { return m_browse; }
300 void SetBrowse(bool browse) { m_browse = browse; }
301
302 bool GetWatched() const { return m_watched; }
303 void SetWatched(bool watched) { m_watched = watched; }
304
305 unsigned int GetID() const { return m_id; }
306 void SetID(int id) { m_id = id; }
307
308 float GetUserRating() const { return m_userrating; }
309 void SetUserRating(float userRating) { m_userrating = userRating; }
310
311 bool GetProcessed() const { return m_processed; }
312 void SetProcessed(bool processed) { m_processed = processed; }
313
315 void SetContentType(VideoContentType contenttype) { m_contenttype = contenttype; }
316
318
319 void SaveToDatabase();
320 void UpdateDatabase();
321 bool DeleteFromDatabase();
322
323 bool DeleteFile();
324
325 void Reset();
326
327 bool IsHostSet() const;
328
329 void GetImageMap(InfoMap &imageMap) const;
330 QString GetImage(const QString &name) const;
331
332 private:
333 void fillCountries();
334 void updateCountries();
335 void fillGenres();
336 void fillCast();
337 void updateGenres();
338 void updateCast();
339 bool removeDir(const QString &dirName);
340 void fromDBRow(MSqlQuery &query);
341 void saveToDatabase();
342
343 private:
344 QString m_title;
345 QString m_sortTitle;
346 QString m_subtitle;
348 QString m_tagline;
349 QString m_inetref;
351 QString m_homepage;
352 QString m_director;
353 QString m_studio;
354 QString m_plot;
355 QString m_rating;
357 QString m_category;
361 QString m_filename;
363 QString m_hash;
364 QString m_trailer;
365 QString m_coverfile;
367 QString m_banner;
368 QString m_fanart;
369 QString m_host;
370
372 int m_childID {-1};
375 std::chrono::minutes m_length {0min};
376 int m_playcount {0};
377 int m_season {0};
378 int m_episode {0};
381 bool m_browse {true};
382 bool m_watched {false};
383 unsigned int m_id {0}; // videometadata.intid
384 float m_userrating {0.0};
385 bool m_processed {false};
387
388 // not in DB
389 QString m_prefix;
390};
391
395
399{
401 if (cmp == 0)
403 if (cmp == 0)
404 cmp = m_id <=> rhs->m_id;
405 return cmp < 0;
406}
407
408bool VideoMetadataImp::removeDir(const QString &dirName)
409{
410 QDir d(dirName);
411
412 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
413 QFileInfoList contents = d.entryInfoList();
414 if (contents.empty())
415 {
416 return d.rmdir(dirName);
417 }
418
419 for (const auto& entry : std::as_const(contents))
420 {
421 if (entry.isDir())
422 {
423 QString fileName = entry.fileName();
424 if (!removeDir(fileName))
425 return false;
426 }
427 else
428 {
429 if (!QFile(entry.fileName()).remove())
430 return false;
431 }
432 }
433 return d.rmdir(dirName);
434}
435
438{
439 bool isremoved = false;
440
441 if (!m_host.isEmpty())
442 {
443 QString url = StorageGroup::generate_file_url("Videos", m_host, m_filename);
444 isremoved = RemoteFile::DeleteFile(url);
445 }
446 else
447 {
448 QFileInfo fi(m_filename);
449 if (fi.isDir())
450 {
451 isremoved = removeDir(m_filename);
452 }
453 else
454 {
455 isremoved = QFile::remove(m_filename);
456 }
457 }
458
459 if (!isremoved)
460 {
461 LOG(VB_GENERAL, LOG_DEBUG, QString("Could not delete file: %1")
462 .arg(m_filename));
463 }
464
465 return isremoved;
466}
467
469{
470 VideoMetadataImp tmp(m_filename, QString(),
473 VIDEO_FANART_DEFAULT, QString(), QString(), QString(), QString(),
474 QString(), VIDEO_YEAR_DEFAULT,
475 QDate(), VIDEO_INETREF_DEFAULT, -1, QString(), VIDEO_DIRECTOR_DEFAULT,
476 QString(), VIDEO_PLOT_DEFAULT, 0.0,
478 0, 0, QDate(), m_id,
479 ParentalLevel::plLowest, 0, -1, true, false, "", "",
482 tmp.m_prefix = m_prefix;
483
484 *this = tmp;
485}
486
488{
489 return !m_host.isEmpty();
490}
491
493{
494 m_genres.clear();
497 if (vgm.get(m_id, genres))
498 {
500 for (long value : genres.values)
501 {
502 // Just add empty string for no-name genres
503 QString name;
504 vg.get(value, name);
505 m_genres.emplace_back(value, name);
506 }
507 }
508}
509
511{
512 m_countries.clear();
514 VideoCountryMap::entry countries;
515 if (vcm.get(m_id, countries))
516 {
518 for (long value : countries.values)
519 {
520 // Just add empty string for no-name countries
521 QString name;
522 vc.get(value, name);
523 m_countries.emplace_back(value, name);
524 }
525 }
526}
527
529{
530 m_cast.clear();
533 if (vcm.get(m_id, cast))
534 {
536 for (long value : cast.values)
537 {
538 // Just add empty string for no-name cast
539 QString name;
540 vc.get(value, name);
541 m_cast.emplace_back(value, name);
542 }
543 }
544}
545
551{
552 m_title = query.value(0).toString();
553 m_director = query.value(1).toString();
554 m_studio = query.value(2).toString();
555 m_plot = query.value(3).toString();
556 m_rating = query.value(4).toString();
557 m_year = query.value(5).toInt();
558 m_releasedate = query.value(6).toDate();
559 m_userrating = (float)query.value(7).toDouble();
560 if (std::isnan(m_userrating) || m_userrating < 0)
561 m_userrating = 0.0;
562 m_userrating = std::min(m_userrating, 10.0F);
563 m_length = std::chrono::minutes(query.value(8).toInt());
564 m_playcount = query.value(9).toInt();
565 m_filename = query.value(10).toString();
566 m_hash = query.value(11).toString();
567 m_showlevel = ParentalLevel(query.value(12).toInt()).GetLevel();
568 m_coverfile = query.value(13).toString();
569 m_inetref = query.value(14).toString();
570 m_collectionref = query.value(15).toUInt();
571 m_homepage = query.value(16).toString();
572 m_childID = query.value(17).toUInt();
573 m_browse = query.value(18).toBool();
574 m_watched = query.value(19).toBool();
575 m_playcommand = query.value(20).toString();
576 m_categoryID = query.value(21).toInt();
577 m_id = query.value(22).toInt();
578 m_trailer = query.value(23).toString();
579 m_screenshot = query.value(24).toString();
580 m_banner = query.value(25).toString();
581 m_fanart = query.value(26).toString();
582 m_subtitle = query.value(27).toString();
583 m_tagline = query.value(28).toString();
584 m_season = query.value(29).toInt();
585 m_episode = query.value(30).toInt();
586 m_host = query.value(31).toString();
587 m_insertdate = query.value(32).toDate();
588 m_processed = query.value(33).toBool();
589
590 m_contenttype = ContentTypeFromString(query.value(34).toString());
591
593
595
596 // Genres
597 fillGenres();
598
599 //Countries
601
602 // Cast
603 fillCast();
604}
605
607{
608 if (m_title.isEmpty())
610 if (m_hash.isEmpty())
612 if (m_subtitle.isEmpty())
614 if (m_director.isEmpty())
616 if (m_plot.isEmpty())
618 if (m_rating.isEmpty())
621
622 InfoMap metadataMap;
623 GetImageMap(metadataMap);
624 QString coverfile = metadataMap["coverfile"];
625 QString screenshot = metadataMap["screenshotfile"];
626 QString bannerfile = metadataMap["bannerfile"];
627 QString fanartfile = metadataMap["fanartfile"];
628
629 if (coverfile.isEmpty() || !RemoteFile::Exists(coverfile))
631 if (screenshot.isEmpty() || !RemoteFile::Exists(screenshot))
633 if (bannerfile.isEmpty() || !RemoteFile::Exists(bannerfile))
635 if (fanartfile.isEmpty() || !RemoteFile::Exists(fanartfile))
637 if (m_trailer.isEmpty())
639 if (m_inetref.isEmpty())
641 if (std::isnan(m_userrating))
642 m_userrating = 0.0;
643 if (m_userrating < -10.0F || m_userrating > 10.0F)
644 m_userrating = 0.0;
645 if (m_releasedate.toString().isEmpty())
646 m_releasedate = QDate::fromString("0000-00-00", "YYYY-MM-DD");
648 {
649 if (m_season > 0 || m_episode > 0)
651 else
653 }
654
655 bool inserting = m_id == 0;
656
658
659 if (inserting)
660 {
661 m_browse = true;
662
663 m_watched = false;
664
665 query.prepare("INSERT INTO videometadata (title,subtitle,tagline,director,studio,plot,"
666 "rating,year,userrating,length,season,episode,filename,hash,"
667 "showlevel,coverfile,inetref,homepage,browse,watched,trailer,"
668 "screenshot,banner,fanart,host,processed,contenttype) VALUES (:TITLE, :SUBTITLE, "
669 ":TAGLINE, :DIRECTOR, :STUDIO, :PLOT, :RATING, :YEAR, :USERRATING, "
670 ":LENGTH, :SEASON, :EPISODE, :FILENAME, :HASH, :SHOWLEVEL, "
671 ":COVERFILE, :INETREF, :HOMEPAGE, :BROWSE, :WATCHED, "
672 ":TRAILER, :SCREENSHOT, :BANNER, :FANART, :HOST, :PROCESSED, :CONTENTTYPE)");
673 }
674 else
675 {
676 query.prepare("UPDATE videometadata SET title = :TITLE, subtitle = :SUBTITLE, "
677 "tagline = :TAGLINE, director = :DIRECTOR, studio = :STUDIO, "
678 "plot = :PLOT, rating= :RATING, year = :YEAR, "
679 "releasedate = :RELEASEDATE, userrating = :USERRATING, "
680 "length = :LENGTH, playcount = :PLAYCOUNT, season = :SEASON, "
681 "episode = :EPISODE, filename = :FILENAME, hash = :HASH, trailer = :TRAILER, "
682 "showlevel = :SHOWLEVEL, coverfile = :COVERFILE, "
683 "screenshot = :SCREENSHOT, banner = :BANNER, fanart = :FANART, "
684 "inetref = :INETREF, collectionref = :COLLECTION, homepage = :HOMEPAGE, "
685 "browse = :BROWSE, watched = :WATCHED, host = :HOST, playcommand = :PLAYCOMMAND, "
686 "childid = :CHILDID, category = :CATEGORY, processed = :PROCESSED, "
687 "contenttype = :CONTENTTYPE WHERE intid = :INTID");
688
689 query.bindValue(":PLAYCOMMAND", m_playcommand);
690 query.bindValue(":CHILDID", m_childID);
691 query.bindValue(":CATEGORY", m_categoryID);
692 query.bindValue(":INTID", m_id);
693 }
694
695 query.bindValueNoNull(":TITLE", m_title);
696 query.bindValueNoNull(":SUBTITLE", m_subtitle);
697 query.bindValue(":TAGLINE", m_tagline);
698 query.bindValueNoNull(":DIRECTOR", m_director);
699 query.bindValue(":STUDIO", m_studio);
700 query.bindValue(":PLOT", m_plot);
701 query.bindValueNoNull(":RATING", m_rating);
702 query.bindValue(":YEAR", m_year);
703 query.bindValue(":RELEASEDATE", m_releasedate);
704 query.bindValue(":USERRATING", m_userrating);
705 query.bindValue(":LENGTH", static_cast<qint64>(m_length.count()));
706 query.bindValue(":PLAYCOUNT", m_playcount);
707 query.bindValue(":SEASON", m_season);
708 query.bindValue(":EPISODE", m_episode);
709 query.bindValue(":FILENAME", m_filename);
710 query.bindValue(":HASH", m_hash);
711 query.bindValueNoNull(":TRAILER", m_trailer);
712 query.bindValue(":SHOWLEVEL", m_showlevel);
713 query.bindValueNoNull(":COVERFILE", m_coverfile);
714 query.bindValueNoNull(":SCREENSHOT", m_screenshot);
715 query.bindValueNoNull(":BANNER", m_banner);
716 query.bindValueNoNull(":FANART", m_fanart);
717 query.bindValueNoNull(":INETREF", m_inetref);
718 query.bindValue(":COLLECTION", m_collectionref);
719 query.bindValueNoNull(":HOMEPAGE", m_homepage);
720 query.bindValue(":BROWSE", m_browse);
721 query.bindValue(":WATCHED", m_watched);
722 query.bindValue(":HOST", m_host);
723 query.bindValue(":PROCESSED", m_processed);
724 query.bindValue(":CONTENTTYPE", ContentTypeToString(m_contenttype));
725
726 if (!query.exec() || !query.isActive())
727 {
728 MythDB::DBError("video metadata update", query);
729 return;
730 }
731
732 if (inserting)
733 {
734 // Must make sure we have 'id' filled before we call updateGenres or
735 // updateCountries
736
737 if (!query.exec("SELECT LAST_INSERT_ID()") || !query.next())
738 {
739 MythDB::DBError("metadata id get", query);
740 return;
741 }
742
743 m_id = query.value(0).toUInt();
744
745 if (0 == m_id)
746 {
747 LOG(VB_GENERAL, LOG_ERR,
748 QString("%1: The id of the last inserted row to "
749 "videometadata seems to be 0. This is odd.")
750 .arg(__FILE__));
751 return;
752 }
753 }
754
755 updateGenres();
757 updateCast();
758}
759
761{
763}
764
766{
768}
769
771{
775
777 query.prepare("DELETE FROM videometadata WHERE intid = :ID");
778 query.bindValue(":ID", m_id);
779 if (!query.exec())
780 {
781 MythDB::DBError("delete from videometadata", query);
782 }
783
784 query.prepare("DELETE FROM filemarkup WHERE filename = :FILENAME");
785 query.bindValue(":FILENAME", m_filename);
786 if (!query.exec())
787 {
788 MythDB::DBError("delete from filemarkup", query);
789 }
790
791 return true;
792}
793
795{
796 if (id == 0)
797 {
798 m_category = "";
799 m_categoryID = id;
800 }
801 else
802 {
803 if (m_categoryID != id)
804 {
805 QString cat;
807 {
808 m_category = cat;
809 m_categoryID = id;
810 }
811 else
812 {
813 LOG(VB_GENERAL, LOG_ERR, "Unknown category id");
814 }
815 }
816 }
817}
818
820{
822
823 // ensure that all genres we have are in the DB
824 auto genre = m_genres.begin();
825 while (genre != m_genres.end())
826 {
827 if (!genre->second.trimmed().isEmpty())
828 {
829 genre->first = VideoGenre::getGenre().add(genre->second);
830 VideoGenreMap::getGenreMap().add(m_id, genre->first);
831 ++genre;
832 }
833 else
834 {
835 genre = m_genres.erase(genre);
836 }
837 }
838}
839
841{
842 // remove countries for this video
844
845 auto country = m_countries.begin();
846 while (country != m_countries.end())
847 {
848 if (!country->second.trimmed().isEmpty())
849 {
850 country->first = VideoCountry::getCountry().add(country->second);
851 VideoCountryMap::getCountryMap().add(m_id, country->first);
852 ++country;
853 }
854 else
855 {
856 country = m_countries.erase(country);
857 }
858 }
859}
860
862{
864
865 // ensure that all cast we have are in the DB
866 auto cast = m_cast.begin();
867 while (cast != m_cast.end())
868 {
869 if (!cast->second.trimmed().isEmpty())
870 {
871 cast->first = VideoCast::GetCast().add(cast->second);
872 VideoCastMap::getCastMap().add(m_id, cast->first);
873 ++cast;
874 }
875 else
876 {
877 cast = m_cast.erase(cast);
878 }
879 }
880}
881
883{
884 QString coverfile;
885 if (IsHostSet()
886 && !GetCoverFile().startsWith(u'/')
887 && !GetCoverFile().isEmpty()
889 {
890 coverfile = StorageGroup::generate_file_url(QStringLiteral(u"Coverart"), GetHost(),
891 GetCoverFile());
892 }
893 else
894 {
895 coverfile = GetCoverFile();
896 }
897
898 imageMap[QStringLiteral(u"coverfile")] = coverfile;
899 imageMap[QStringLiteral(u"coverart")] = coverfile;
900
901 QString screenshotfile;
902 if (IsHostSet() && !GetScreenshot().startsWith(u'/')
903 && !GetScreenshot().isEmpty())
904 {
905 screenshotfile = StorageGroup::generate_file_url(QStringLiteral(u"Screenshots"),
907 }
908 else
909 {
910 screenshotfile = GetScreenshot();
911 }
912
913 imageMap[QStringLiteral(u"screenshotfile")] = screenshotfile;
914 imageMap[QStringLiteral(u"screenshot")] = screenshotfile;
915
916 QString bannerfile;
917 if (IsHostSet() && !GetBanner().startsWith(u'/')
918 && !GetBanner().isEmpty())
919 {
920 bannerfile = StorageGroup::generate_file_url(QStringLiteral(u"Banners"), GetHost(),
921 GetBanner());
922 }
923 else
924 {
925 bannerfile = GetBanner();
926 }
927
928 imageMap[QStringLiteral(u"bannerfile")] = bannerfile;
929 imageMap[QStringLiteral(u"banner")] = bannerfile;
930
931 QString fanartfile;
932 if (IsHostSet() && !GetFanart().startsWith('/')
933 && !GetFanart().isEmpty())
934 {
935 fanartfile = StorageGroup::generate_file_url(QStringLiteral(u"Fanart"), GetHost(),
936 GetFanart());
937 }
938 else
939 {
940 fanartfile = GetFanart();
941 }
942
943 imageMap[QStringLiteral(u"fanartfile")] = fanartfile;
944 imageMap[QStringLiteral(u"fanart")] = fanartfile;
945
946 QString smartimage = coverfile;
947 if (!screenshotfile.isEmpty () && (GetSeason() > 0 || GetEpisode() > 0))
948 smartimage = screenshotfile;
949 imageMap[QStringLiteral(u"smartimage")] = smartimage;
950}
951
952// This should be the equivalent of GetImageMap, only the image names
953// are computed one at a time as needed.
954QString VideoMetadataImp::GetImage(const QString& name) const
955{
956 if ((name == QStringLiteral(u"coverfile")) ||
957 (name == QStringLiteral(u"coverart")))
958 {
959 QString coverfile = GetCoverFile();
960 if (IsHostSet()
961 && !coverfile.startsWith(u'/')
962 && !coverfile.isEmpty()
963 && !IsDefaultCoverFile(coverfile))
964 return StorageGroup::generate_file_url(QStringLiteral(u"Coverart"), GetHost(),
965 coverfile);
966 return coverfile;
967 }
968
969 if ((name == QStringLiteral(u"screenshotfile")) ||
970 (name == QStringLiteral(u"screenshot")))
971 {
972 QString screenshot = GetScreenshot();
973 if (IsHostSet() && !screenshot.startsWith(u'/')
974 && !screenshot.isEmpty())
975 return StorageGroup::generate_file_url(QStringLiteral(u"Screenshots"),
976 GetHost(), screenshot);
977 return screenshot;
978 }
979
980 if ((name == QStringLiteral(u"bannerfile")) ||
981 (name == QStringLiteral(u"banner")))
982 {
983 QString bannerfile = GetBanner();
984 if (IsHostSet() && !bannerfile.startsWith(u'/')
985 && !bannerfile.isEmpty())
986 return StorageGroup::generate_file_url(QStringLiteral(u"Banners"), GetHost(),
987 bannerfile);
988 return bannerfile;
989 }
990
991 if ((name == QStringLiteral(u"fanartfile")) ||
992 (name == QStringLiteral(u"fanart")))
993 {
994 QString fanartfile = GetFanart();
995 if (IsHostSet() && !fanartfile.startsWith('/')
996 && !fanartfile.isEmpty())
997 return StorageGroup::generate_file_url(QStringLiteral(u"Fanart"), GetHost(),
998 fanartfile);
999 return fanartfile;
1000 }
1001
1002 if ((name == QStringLiteral(u"smartimage")) ||
1003 (name == QStringLiteral(u"buttonimage")))
1004 {
1005 if (GetSeason() > 0 || GetEpisode() > 0)
1006 {
1007 QString screenshotfile = GetImage("screenshot");
1008 if (!screenshotfile.isEmpty())
1009 return screenshotfile;
1010 }
1011 return GetImage("coverart");
1012 }
1013
1014 return {};
1015}
1016
1020namespace
1021{
1022 QString eatBraces(const QString &title, const QString &left_brace,
1023 const QString &right_brace)
1024 {
1025 QString ret(title);
1026 bool keep_checking = true;
1027
1028 while (keep_checking)
1029 {
1030 int left_position = ret.indexOf(left_brace);
1031 int right_position = ret.indexOf(right_brace);
1032 if (left_position == -1 || right_position == -1)
1033 {
1034 //
1035 // No matching sets of these braces left.
1036 //
1037
1038 keep_checking = false;
1039 }
1040 else
1041 {
1042 if (left_position < right_position)
1043 {
1044 //
1045 // We have a matching set like: ( foo )
1046 //
1047
1048 ret = ret.left(left_position) +
1049 ret.right(ret.length() - right_position - 1);
1050 }
1051 else if (left_position > right_position)
1052 {
1053 //
1054 // We have a matching set like: ) foo (
1055 //
1056
1057 ret = ret.left(right_position) +
1058 ret.right(ret.length() - left_position - 1);
1059 }
1060 }
1061 }
1062
1063 return ret;
1064 }
1065}
1066
1068 const QString &file_name,
1069 const QString &host)
1070{
1072
1073 query.prepare("SELECT intid,filename FROM videometadata WHERE "
1074 "hash = :HASH");
1075 query.bindValue(":HASH", hash);
1076
1077 if (!query.exec() || !query.isActive())
1078 {
1079 MythDB::DBError("Video hashed metadata update", query);
1080 return -1;
1081 }
1082
1083 if (!query.next())
1084 return -1;
1085
1086 int intid = query.value(0).toInt();
1087 QString oldfilename = query.value(1).toString();
1088
1089 query.prepare("UPDATE videometadata SET filename = :FILENAME, "
1090 "host = :HOST WHERE intid = :INTID");
1091 query.bindValue(":FILENAME", file_name);
1092 query.bindValue(":HOST", host);
1093 query.bindValue(":INTID", intid);
1094
1095 if (!query.exec() || !query.isActive())
1096 {
1097 MythDB::DBError("Video hashed metadata update (videometadata)", query);
1098 return -1;
1099 }
1100
1101 query.prepare("UPDATE filemarkup SET filename = :FILENAME "
1102 "WHERE filename = :OLDFILENAME");
1103 query.bindValue(":FILENAME", file_name);
1104 query.bindValue(":OLDFILENAME", oldfilename);
1105
1106 if (!query.exec() || !query.isActive())
1107 {
1108 MythDB::DBError("Video hashed metadata update (filemarkup)", query);
1109 return -1;
1110 }
1111
1112 return intid;
1113}
1114
1115QString VideoMetadata::VideoFileHash(const QString &file_name,
1116 const QString &host)
1117{
1118 if (host.isEmpty())
1119 return FileHash(file_name);
1120
1122 {
1123 StorageGroup sgroup("Videos", host);
1124 QString fullname = sgroup.FindFile(file_name);
1125
1126 return FileHash(fullname);
1127 }
1128
1129 QString url = StorageGroup::generate_file_url("Videos", host, file_name);
1130
1131 return RemoteFile::GetFileHash(url);
1132}
1133
1134QString VideoMetadata::FilenameToMeta(const QString &file_name, int position)
1135{
1136 // position 1 returns title, 2 returns season,
1137 // 3 returns episode, 4 returns subtitle
1138
1139 QString cleanFilename = file_name.left(file_name.lastIndexOf('.'));
1140 static const QRegularExpression kSpaceRE { "%20" };
1141 static const QRegularExpression kUnderscoreRE { "_" };
1142 static const QRegularExpression kDotRE { "\\." };
1143 cleanFilename.replace(kSpaceRE, " ");
1144 cleanFilename.replace(kUnderscoreRE, " ");
1145 cleanFilename.replace(kDotRE, " ");
1146
1147 /*: Word(s) which should be recognized as "season" when parsing a video
1148 * file name. To list more than one word, separate them with a '|'.
1149 */
1150 QString season_translation = tr("Season", "Metadata file name parsing");
1151
1152 /*: Word(s) which should be recognized as "episode" when parsing a video
1153 * file name. To list more than one word, separate them with a '|'.
1154 */
1155 QString episode_translation = tr("Episode", "Metadata file name parsing");
1156
1157 // Primary Regexp
1158 QString separator = "(?:\\s?(?:-|/)?\\s?)?";
1159 QString regexp = QString(
1160 "^(.*[^s0-9])" // Title
1161 "%1" // optional separator
1162 "(?:s|(?:Season|%2))?" // season marker
1163 "%1" // optional separator
1164 "(\\d{1,4})" // Season
1165 "%1" // optional separator
1166 "(?:[ex/]|Episode|%3)" // episode marker
1167 "%1" // optional separator
1168 "(\\d{1,3})" // Episode
1169 "%1" // optional separator
1170 "(.*)$" // Subtitle
1171 ).arg(separator, season_translation, episode_translation);
1172 static const QRegularExpression filename_parse { regexp,
1173 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
1174
1175 // Cleanup Regexp
1176 QString regexp2 = QString("(%1(?:(?:Season|%2)%1\\d*%1)*%1)$")
1177 .arg(separator, season_translation);
1178 static const QRegularExpression title_parse {regexp2,
1179 QRegularExpression::CaseInsensitiveOption|QRegularExpression::UseUnicodePropertiesOption };
1180
1181 auto match = filename_parse.match(cleanFilename);
1182 if (match.hasMatch())
1183 {
1184 // Return requested value
1185 if (position == 1 && !match.capturedView(1).isEmpty())
1186 {
1187 // Clean up the title
1188 QString title = match.captured(1);
1189 match = title_parse.match(title);
1190 if (match.hasMatch())
1191 title = title.left(match.capturedStart());
1192 title = title.right(title.length() - title.lastIndexOf('/') -1);
1193 return title.trimmed();
1194 }
1195 if (position == 2)
1196 return match.captured(2).trimmed();
1197 if (position == 3)
1198 return match.captured(3).trimmed();
1199 if (position == 4)
1200 return match.captured(4).trimmed();
1201 }
1202 else if (position == 1)
1203 {
1204 QString title = cleanFilename;
1205
1206 // Clean up the title
1207 title = title.right(title.length() -
1208 title.lastIndexOf('/') -1);
1209
1210 // Allow parentheses "()", but remove content inside other braces
1211 title = eatBraces(title, "[", "]");
1212 title = eatBraces(title, "{", "}");
1213 return title.trimmed();
1214 }
1215 else if (position == 2 || position == 3)
1216 {
1217 return {"0"};
1218 }
1219
1220 return {};
1221}
1222
1223VideoMetadata::VideoMetadata(const QString &filename, const QString &sortFilename,
1224 const QString &hash, const QString &trailer, const QString &coverfile,
1225 const QString &screenshot, const QString &banner, const QString &fanart,
1226 const QString &title, const QString &sortTitle,
1227 const QString &subtitle, const QString &sortSubtitle, const QString &tagline,
1228 int year, const QDate releasedate, const QString &inetref, int collectionref,
1229 const QString &homepage, const QString &director, const QString &studio,
1230 const QString &plot, float userrating, const QString &rating,
1231 int length, int playcount, int season, int episode, const QDate insertdate,
1232 int id, ParentalLevel::Level showlevel, int categoryID,
1233 int childID, bool browse, bool watched,
1234 const QString &playcommand, const QString &category,
1235 const genre_list &genres,
1236 const country_list &countries,
1237 const cast_list &cast,
1238 const QString &host, bool processed,
1239 VideoContentType contenttype)
1240{
1241 m_imp = new VideoMetadataImp(filename, sortFilename, hash, trailer, coverfile,
1242 screenshot, banner, fanart, title, sortTitle, subtitle,
1243 sortSubtitle, tagline, year, releasedate, inetref,
1244 collectionref, homepage, director, studio, plot, userrating, rating,
1245 length, playcount, season, episode, insertdate, id, showlevel, categoryID,
1246 childID, browse, watched, playcommand, category, genres, countries,
1247 cast, host, processed, contenttype);
1248}
1249
1251{
1252 delete m_imp;
1253}
1254
1256 : m_imp(new VideoMetadataImp(query))
1257{
1258}
1259
1261{
1262 *this = rhs;
1263}
1264
1266{
1267 if (this != &rhs)
1268 {
1269 m_imp = new VideoMetadataImp(*(rhs.m_imp));
1270 }
1271
1272 return *this;
1273}
1274
1276{
1277 GetImageMap(metadataMap);
1278
1279 metadataMap[QStringLiteral(u"filename")] = GetFilename();
1280 metadataMap[QStringLiteral(u"sortfilename")] = GetSortFilename();
1281 metadataMap[QStringLiteral(u"title")] = GetTitle();
1282 metadataMap[QStringLiteral(u"sorttitle")] = GetSortTitle();
1283 metadataMap[QStringLiteral(u"subtitle")] = GetSubtitle();
1284 metadataMap[QStringLiteral(u"sortsubtitle")] = GetSortSubtitle();
1285 metadataMap[QStringLiteral(u"tagline")] = GetTagline();
1286 metadataMap[QStringLiteral(u"director")] = GetDirector();
1287 metadataMap[QStringLiteral(u"studio")] = GetStudio();
1288 metadataMap[QStringLiteral(u"description0")] = metadataMap[QStringLiteral(u"description")] = GetPlot();
1289 metadataMap[QStringLiteral(u"genres")] = GetDisplayGenres(*this);
1290 metadataMap[QStringLiteral(u"countries")] = GetDisplayCountries(*this);
1291 metadataMap[QStringLiteral(u"cast")] = GetDisplayCast(*this).join(", ");
1292 metadataMap[QStringLiteral(u"rating")] = GetDisplayRating(GetRating());
1293 metadataMap[QStringLiteral(u"length")] = GetDisplayLength(GetLength());
1294 metadataMap[QStringLiteral(u"playcount")] = QString::number(GetPlayCount());
1295 metadataMap[QStringLiteral(u"year")] = GetDisplayYear(GetYear());
1296
1297 metadataMap[QStringLiteral(u"releasedate")] = MythDate::toString(
1299
1300 metadataMap[QStringLiteral(u"userrating")] = GetDisplayUserRating(GetUserRating());
1301
1302 if (GetSeason() > 0 || GetEpisode() > 0)
1303 {
1304 metadataMap[QStringLiteral(u"season")] = StringUtil::intToPaddedString(GetSeason(), 1);
1305 metadataMap[QStringLiteral(u"episode")] = StringUtil::intToPaddedString(GetEpisode(), 1);
1306 QString usingSE = QStringLiteral(u"s%1e%2")
1309 metadataMap[QStringLiteral(u"s##e##")] = metadataMap[QStringLiteral(u"s00e00")] = usingSE;
1310 QString usingX = QStringLiteral(u"%1x%2")
1313 metadataMap[QStringLiteral(u"##x##")] = metadataMap[QStringLiteral(u"00x00")] = usingX;
1314 }
1315 else
1316 {
1317 metadataMap[QStringLiteral(u"s##e##")] = metadataMap[QStringLiteral(u"##x##")] = QString();
1318 metadataMap[QStringLiteral(u"s00e00")] = metadataMap[QStringLiteral(u"00x00")] = QString();
1319 metadataMap[QStringLiteral(u"season")] = metadataMap[QStringLiteral(u"episode")] = QString();
1320 }
1321
1322 GetStateMap(metadataMap);
1323
1324 metadataMap[QStringLiteral(u"insertdate")] = MythDate::toString(
1326 metadataMap[QStringLiteral(u"inetref")] = GetInetRef();
1327 metadataMap[QStringLiteral(u"homepage")] = GetHomepage();
1328 metadataMap[QStringLiteral(u"child_id")] = QString::number(GetChildID());
1329 metadataMap[QStringLiteral(u"browseable")] = GetDisplayBrowse(GetBrowse());
1330 metadataMap[QStringLiteral(u"watched")] = GetDisplayWatched(GetWatched());
1331 metadataMap[QStringLiteral(u"processed")] = GetDisplayProcessed(GetProcessed());
1332 metadataMap[QStringLiteral(u"category")] = GetCategory();
1333}
1334
1335// This should be the equivalent of toMap, only the text strings
1336// are computed one at a time as needed.
1337QString VideoMetadata::GetText(const QString& name) const
1338{
1339 if (name == QStringLiteral(u"filename"))
1340 return GetFilename();
1341 if (name == QStringLiteral(u"sortfilename"))
1342 return GetSortFilename();
1343 if (name == QStringLiteral(u"title"))
1344 return GetTitle();
1345 if (name == QStringLiteral(u"sorttitle"))
1346 return GetSortTitle();
1347 if (name == QStringLiteral(u"subtitle"))
1348 return GetSubtitle();
1349 if (name == QStringLiteral(u"sortsubtitle"))
1350 return GetSortSubtitle();
1351 if (name == QStringLiteral(u"tagline"))
1352 return GetTagline();
1353 if (name == QStringLiteral(u"director"))
1354 return GetDirector();
1355 if (name == QStringLiteral(u"studio"))
1356 return GetStudio();
1357 if ((name == QStringLiteral(u"description")) ||
1358 (name == QStringLiteral(u"description0")))
1359 return GetPlot();
1360 if (name == QStringLiteral(u"genres"))
1361 return GetDisplayGenres(*this);
1362 if (name == QStringLiteral(u"countries"))
1363 return GetDisplayCountries(*this);
1364 if (name == QStringLiteral(u"cast"))
1365 return GetDisplayCast(*this).join(", ");
1366 if (name == QStringLiteral(u"rating"))
1367 return GetDisplayRating(GetRating());
1368 if (name == QStringLiteral(u"length"))
1369 return GetDisplayLength(GetLength());
1370 if (name == QStringLiteral(u"playcount"))
1371 return QString::number(GetPlayCount());
1372 if (name == QStringLiteral(u"year"))
1373 return GetDisplayYear(GetYear());
1374
1375 if (name == QStringLiteral(u"releasedate"))
1377
1378 if (name == QStringLiteral(u"userrating"))
1380
1381 if (GetSeason() > 0 || GetEpisode() > 0)
1382 {
1383 if (name == QStringLiteral(u"season"))
1385 if (name == QStringLiteral(u"episode"))
1387 if ((name == QStringLiteral(u"s##e##")) ||
1388 (name == QStringLiteral(u"s00e00")))
1389 {
1390 return QStringLiteral(u"s%1e%2")
1393 }
1394 if ((name == QStringLiteral(u"##x##")) ||
1395 (name == QStringLiteral(u"00x00")))
1396 {
1397 return QStringLiteral(u"%1x%2")
1400 }
1401 }
1402
1403 if (name == QStringLiteral(u"insertdate"))
1404 return MythDate::toString(
1406 if (name == QStringLiteral(u"inetref"))
1407 return GetInetRef();
1408 if (name == QStringLiteral(u"homepage"))
1409 return GetHomepage();
1410 if (name == QStringLiteral(u"child_id"))
1411 return QString::number(GetChildID());
1412 if (name == QStringLiteral(u"browseable"))
1413 return GetDisplayBrowse(GetBrowse());
1414 if (name == QStringLiteral(u"watched"))
1415 return GetDisplayWatched(GetWatched());
1416 if (name == QStringLiteral(u"processed"))
1418 if (name == QStringLiteral(u"category"))
1419 return GetCategory();
1420 return {};
1421}
1422
1424{
1425 stateMap[QStringLiteral(u"trailerstate")] = TrailerToState(GetTrailer());
1426 stateMap[QStringLiteral(u"userratingstate")] =
1427 QString::number((int)(GetUserRating()));
1428 stateMap[QStringLiteral(u"watchedstate")] = WatchedToState(GetWatched());
1429 stateMap[QStringLiteral(u"videolevel")] = ParentalLevelToState(GetShowLevel());
1430}
1431
1432// This should be the equivalent of GetStateMap, only the state strings
1433// are computed one at a time as needed.
1434QString VideoMetadata::GetState(const QString& name) const
1435{
1436 if (name == QStringLiteral(u"trailerstate"))
1437 return TrailerToState(GetTrailer());
1438 if (name == QStringLiteral(u"userratingstate"))
1439 return QString::number((int)(GetUserRating()));
1440 if (name == QStringLiteral(u"watchedstate"))
1441 return WatchedToState(GetWatched());
1442 if (name == QStringLiteral(u"videolevel"))
1444 return {};
1445}
1446
1448{
1449 m_imp->GetImageMap(imageMap);
1450}
1451
1452QString VideoMetadata::GetImage(const QString& name) const
1453{
1454 return m_imp->GetImage(name);
1455}
1456
1457void ClearMap(InfoMap &metadataMap)
1458{
1459 metadataMap["coverfile"] = "";
1460 metadataMap["screenshotfile"] = "";
1461 metadataMap["bannerfile"] = "";
1462 metadataMap["fanartfile"] = "";
1463 metadataMap["filename"] = "";
1464 metadataMap["sortfilename"] = "";
1465 metadataMap["title"] = "";
1466 metadataMap["sorttitle"] = "";
1467 metadataMap["subtitle"] = "";
1468 metadataMap["sortsubtitle"] = "";
1469 metadataMap["tagline"] = "";
1470 metadataMap["director"] = "";
1471 metadataMap["studio"] = "";
1472 metadataMap["description"] = "";
1473 metadataMap["description0"] = "";
1474 metadataMap["genres"] = "";
1475 metadataMap["countries"] = "";
1476 metadataMap["cast"] = "";
1477 metadataMap["rating"] = "";
1478 metadataMap["length"] = "";
1479 metadataMap["playcount"] = "";
1480 metadataMap["year"] = "";
1481 metadataMap["releasedate"] = "";
1482 metadataMap["userrating"] = "";
1483 metadataMap["season"] = "";
1484 metadataMap["episode"] = "";
1485 metadataMap["s##e##"] = "";
1486 metadataMap["##x##"] = "";
1487 metadataMap["trailerstate"] = "";
1488 metadataMap["userratingstate"] = "";
1489 metadataMap["watchedstate"] = "";
1490 metadataMap["videolevel"] = "";
1491 metadataMap["insertdate"] = "";
1492 metadataMap["inetref"] = "";
1493 metadataMap["homepage"] = "";
1494 metadataMap["child_id"] = "";
1495 metadataMap["browseable"] = "";
1496 metadataMap["watched"] = "";
1497 metadataMap["category"] = "";
1498 metadataMap["processed"] = "";
1499}
1500
1501QString VideoMetadata::MetadataGetTextCb(const QString& name, void *data)
1502{
1503 if (data == nullptr)
1504 return {};
1505 auto *metadata = static_cast<VideoMetadata *>(data);
1506 QString result = metadata->GetText(name);
1507 if (!result.isEmpty())
1508 return result;
1509 result = metadata->GetImage(name);
1510 if (!result.isEmpty())
1511 return result;
1512 return metadata->GetState(name);
1513}
1514
1515QString VideoMetadata::MetadataGetImageCb(const QString& name, void *data)
1516{
1517 if (data == nullptr)
1518 return {};
1519 auto *metadata = static_cast<VideoMetadata *>(data);
1520 return metadata->GetImage(name);
1521}
1522
1523QString VideoMetadata::MetadataGetStateCb(const QString& name, void *data)
1524{
1525 if (data == nullptr)
1526 return {};
1527 auto *metadata = static_cast<VideoMetadata *>(data);
1528 return metadata->GetState(name);
1529}
1530
1531const QString &VideoMetadata::GetPrefix() const
1532{
1533 return m_imp->GetPrefix();
1534}
1535
1537{
1539}
1540
1541const QString &VideoMetadata::GetTitle() const
1542{
1543 return m_imp->getTitle();
1544}
1545
1546const QString &VideoMetadata::GetSortTitle() const
1547{
1548 return m_imp->getSortTitle();
1549}
1550
1551void VideoMetadata::SetTitle(const QString &title, const QString &sortTitle)
1552{
1553 m_imp->SetTitle(title, sortTitle);
1554}
1555
1556const QString &VideoMetadata::GetSubtitle() const
1557{
1558 return m_imp->getSubtitle();
1559}
1560
1562{
1563 return m_imp->getSortSubtitle();
1564}
1565
1566void VideoMetadata::SetSubtitle(const QString &subtitle, const QString &sortSubtitle)
1567{
1568 m_imp->SetSubtitle(subtitle, sortSubtitle);
1569}
1570
1571const QString &VideoMetadata::GetTagline() const
1572{
1573 return m_imp->GetTagline();
1574}
1575
1576void VideoMetadata::SetTagline(const QString &tagline)
1577{
1578 m_imp->SetTagline(tagline);
1579}
1580
1582{
1583 return m_imp->getYear();
1584}
1585
1587{
1588 m_imp->SetYear(year);
1589}
1590
1592{
1593 return m_imp->getReleaseDate();
1594}
1595
1596void VideoMetadata::SetReleaseDate(QDate releasedate)
1597{
1598 m_imp->SetReleaseDate(releasedate);
1599}
1600
1601const QString &VideoMetadata::GetInetRef() const
1602{
1603 return m_imp->GetInetRef();
1604}
1605
1606void VideoMetadata::SetInetRef(const QString &inetRef)
1607{
1608 m_imp->SetInetRef(inetRef);
1609}
1610
1612{
1613 return m_imp->GetCollectionRef();
1614}
1615
1616void VideoMetadata::SetCollectionRef(int collectionref)
1617{
1618 m_imp->SetCollectionRef(collectionref);
1619}
1620
1621const QString &VideoMetadata::GetHomepage() const
1622{
1623 return m_imp->GetHomepage();
1624}
1625
1626void VideoMetadata::SetHomepage(const QString &homepage)
1627{
1628 m_imp->SetHomepage(homepage);
1629}
1630
1631const QString &VideoMetadata::GetDirector() const
1632{
1633 return m_imp->getDirector();
1634}
1635
1636void VideoMetadata::SetDirector(const QString &director)
1637{
1638 m_imp->SetDirector(director);
1639}
1640
1641const QString &VideoMetadata::GetStudio() const
1642{
1643 return m_imp->getStudio();
1644}
1645
1646void VideoMetadata::SetStudio(const QString &studio)
1647{
1648 m_imp->SetStudio(studio);
1649}
1650
1651const QString &VideoMetadata::GetPlot() const
1652{
1653 return m_imp->getPlot();
1654}
1655
1656void VideoMetadata::SetPlot(const QString &plot)
1657{
1658 m_imp->SetPlot(plot);
1659}
1660
1662{
1663 return m_imp->GetUserRating();
1664}
1665
1666void VideoMetadata::SetUserRating(float userRating)
1667{
1668 m_imp->SetUserRating(userRating);
1669}
1670
1671const QString &VideoMetadata::GetRating() const
1672{
1673 return m_imp->GetRating();
1674}
1675
1677{
1679}
1680
1681std::chrono::minutes VideoMetadata::GetLength() const
1682{
1683 return m_imp->GetLength();
1684}
1685
1686void VideoMetadata::SetLength(std::chrono::minutes length)
1687{
1688 m_imp->SetLength(length);
1689}
1690
1692{
1693 return m_imp->GetPlayCount();
1694}
1695
1697{
1698 m_imp->SetPlayCount(count);
1699}
1700
1702{
1703 return m_imp->GetSeason();
1704}
1705
1707{
1708 m_imp->SetSeason(season);
1709}
1710
1712{
1713 return m_imp->GetEpisode();
1714}
1715
1717{
1718 m_imp->SetEpisode(episode);
1719}
1720
1722{
1723 return m_imp->GetInsertdate();
1724}
1725
1727{
1728 m_imp->SetInsertdate(date);
1729}
1730
1731unsigned int VideoMetadata::GetID() const
1732{
1733 return m_imp->GetID();
1734}
1735
1737{
1738 m_imp->SetID(id);
1739}
1740
1742{
1743 return m_imp->GetChildID();
1744}
1745
1747{
1748 m_imp->SetChildID(childID);
1749}
1750
1752{
1753 return m_imp->GetBrowse();
1754}
1755
1757{
1758 m_imp->SetBrowse(browse);
1759}
1760
1762{
1763 return m_imp->GetWatched();
1764}
1765
1767{
1768 m_imp->SetWatched(watched);
1769}
1770
1772{
1773 return m_imp->GetProcessed();
1774}
1775
1777{
1778 m_imp->SetProcessed(processed);
1779}
1780
1782{
1783 return m_imp->GetContentType();
1784}
1785
1787{
1788 m_imp->SetContentType(contenttype);
1789}
1790
1791const QString &VideoMetadata::GetPlayCommand() const
1792{
1793 return m_imp->getPlayCommand();
1794}
1795
1796void VideoMetadata::SetPlayCommand(const QString &playCommand)
1797{
1798 m_imp->SetPlayCommand(playCommand);
1799}
1800
1802{
1803 return m_imp->GetShowLevel();
1804}
1805
1807{
1808 m_imp->SetShowLevel(showLevel);
1809}
1810
1811const QString &VideoMetadata::GetFilename() const
1812{
1813 return m_imp->getFilename();
1814}
1815
1817{
1818 return m_imp->getSortFilename();
1819}
1820
1821const QString &VideoMetadata::GetHash() const
1822{
1823 return m_imp->GetHash();
1824}
1825
1826void VideoMetadata::SetHash(const QString &hash)
1827{
1828 m_imp->SetHash(hash);
1829}
1830
1831const QString &VideoMetadata::GetHost() const
1832{
1833 return m_imp->GetHost();
1834}
1835
1836void VideoMetadata::SetHost(const QString &host)
1837{
1838 m_imp->SetHost(host);
1839}
1840
1841void VideoMetadata::SetFilename(const QString &filename, const QString &sortFilename)
1842{
1843 m_imp->SetFilename(filename, sortFilename);
1844}
1845
1846const QString &VideoMetadata::GetTrailer() const
1847{
1848 return m_imp->GetTrailer();
1849}
1850
1851void VideoMetadata::SetTrailer(const QString &trailer)
1852{
1853 m_imp->SetTrailer(trailer);
1854}
1855
1856const QString &VideoMetadata::GetCoverFile() const
1857{
1858 return m_imp->GetCoverFile();
1859}
1860
1861void VideoMetadata::SetCoverFile(const QString &coverFile)
1862{
1863 m_imp->SetCoverFile(coverFile);
1864}
1865
1866const QString &VideoMetadata::GetScreenshot() const
1867{
1868 return m_imp->GetScreenshot();
1869}
1870
1871void VideoMetadata::SetScreenshot(const QString &screenshot)
1872{
1873 m_imp->SetScreenshot(screenshot);
1874}
1875
1876const QString &VideoMetadata::GetBanner() const
1877{
1878 return m_imp->GetBanner();
1879}
1880
1881void VideoMetadata::SetBanner(const QString &banner)
1882{
1883 m_imp->SetBanner(banner);
1884}
1885
1886const QString &VideoMetadata::GetFanart() const
1887{
1888 return m_imp->GetFanart();
1889}
1890
1891void VideoMetadata::SetFanart(const QString &fanart)
1892{
1893 m_imp->SetFanart(fanart);
1894}
1895
1896const QString &VideoMetadata::GetCategory() const
1897{
1898 return m_imp->GetCategory();
1899}
1900
1901//void VideoMetadata::SetCategory(const QString &category)
1902//{
1903// m_imp->SetCategory(category);
1904//}
1905
1907{
1908 return m_imp->getGenres();
1909}
1910
1912{
1913 m_imp->SetGenres(genres);
1914}
1915
1917{
1918 return m_imp->GetCast();
1919}
1920
1922{
1923 m_imp->SetCast(cast);
1924}
1925
1927{
1928 return m_imp->GetCountries();
1929}
1930
1932{
1933 m_imp->SetCountries(countries);
1934}
1935
1937{
1938 return m_imp->GetCategoryID();
1939}
1940
1942{
1943 m_imp->SetCategoryID(id);
1944}
1945
1947{
1949}
1950
1952{
1954}
1955
1957{
1958 return m_imp->DeleteFromDatabase();
1959}
1960
1961#if 0
1962bool VideoMetadata::fillDataFromID(const VideoMetadataListManager &cache)
1963{
1964 if (m_imp->getID() == 0)
1965 return false;
1966
1968 if (mp.get())
1969 {
1970 *this = *mp;
1971 return true;
1972 }
1973
1974 return false;
1975}
1976#endif
1977
1979{
1980 if (m_imp->getFilename().isEmpty())
1981 return false;
1982
1984 cache.byFilename(m_imp->getFilename());
1985 if (mp)
1986 {
1987 *this = *mp;
1988 return true;
1989 }
1990
1991 return false;
1992}
1993
1995{
1996 return m_imp->DeleteFile();
1997}
1998
2000{
2001 m_imp->Reset();
2002}
2003
2005{
2006 return m_imp->IsHostSet();
2007}
2008
2010{
2011 return m_imp->sortBefore(rhs.m_imp);
2012}
2013
2015{
2016 return a.GetFilename() == b.GetFilename();
2017}
2018
2020{
2021 return a.GetFilename() != b.GetFilename();
2022}
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:903
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
int add(int id, int value)
Definition: dbaccess.cpp:451
bool get(int id, entry &values)
Definition: dbaccess.cpp:456
void remove(int id, int value)
Definition: dbaccess.cpp:461
bool IsThisHost(const QString &addr)
is this address mapped to this host
bool IsMasterBackend(void)
is this the actual MBE process
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
Level GetLevel() const
static QString GetFileHash(const QString &url)
Definition: remotefile.cpp:555
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:420
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:463
bool get(int id, QString &category)
Definition: dbaccess.cpp:221
int add(const QString &name)
Definition: dbaccess.cpp:216
QString FindFile(const QString &filename)
static QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
static VideoCastMap & getCastMap()
Definition: dbaccess.cpp:579
static VideoCast & GetCast()
Definition: dbaccess.cpp:535
static VideoCategory & GetCategory()
Definition: dbaccess.cpp:493
static VideoCountryMap & getCountryMap()
Definition: dbaccess.cpp:564
static VideoCountry & getCountry()
Definition: dbaccess.cpp:507
static VideoGenreMap & getGenreMap()
Definition: dbaccess.cpp:549
static VideoGenre & getGenre()
Definition: dbaccess.cpp:521
float GetUserRating() const
bool GetProcessed() const
const QString & getStudio() const
void SetHost(const QString &host)
void SetChildID(int childID)
void SetGenres(const genre_list &genres)
VideoMetadata::cast_list cast_list
const QString & GetHash() const
const QString & getPlot() const
unsigned int m_id
int GetSeason() const
const QString & GetTagline() const
QString GetImage(const QString &name) const
void SetWatched(bool watched)
void SetHash(const QString &hash)
int GetCategoryID() const
const cast_list & GetCast() const
const QString & getPlayCommand() const
void SetCategoryID(int id)
bool sortBefore(const VideoMetadataImp *rhs) const
Returns true if the object should appear before the argument.
void SetReleaseDate(QDate releasedate)
void SetShowLevel(ParentalLevel::Level showLevel)
void SetPlayCommand(const QString &playCommand)
const QString & GetPrefix() const
void SetStudio(const QString &studio)
bool GetWatched() const
void SetCast(const cast_list &cast)
bool IsHostSet() const
const QString & getDirector() const
void SetTrailer(const QString &trailer)
int getYear() const
void SetContentType(VideoContentType contenttype)
int GetEpisode() const
const QString & GetInetRef() const
const QString & GetHomepage() const
void SetYear(int year)
void ensureSortFields(void)
ParentalLevel::Level m_showlevel
const QString & getSortFilename() const
bool DeleteFile()
Deletes the file associated with a metadata entry.
void SetSeason(int season)
void fromDBRow(MSqlQuery &query)
Sets metadata from a DB row.
unsigned int GetPlayCount() const
VideoContentType GetContentType() const
int GetCollectionRef() const
VideoMetadata::country_list country_list
const QString & GetHost() const
std::chrono::minutes GetLength() const
const genre_list & getGenres() const
ParentalLevel::Level GetShowLevel() const
QDate getReleaseDate() const
const QString & GetRating() const
VideoMetadataImp(QString filename, QString sortFilename, QString hash, QString trailer, QString coverfile, QString screenshot, QString banner, QString fanart, const QString &title, QString sortTitle, const QString &subtitle, QString sortSubtitle, QString tagline, int year, const QDate releasedate, QString inetref, int collectionref, QString homepage, QString director, QString studio, QString plot, float userrating, QString rating, int length, int playcount, int season, int episode, const QDate insertdate, int id, ParentalLevel::Level showlevel, int categoryID, int childID, bool browse, bool watched, QString playcommand, QString category, genre_list genres, country_list countries, cast_list cast, QString host="", bool processed=false, VideoContentType contenttype=kContentUnknown)
void SetTagline(const QString &tagline)
void SetCollectionRef(int collectionref)
void SetDirector(const QString &director)
const QString & getTitle() const
const QString & GetScreenshot() const
void SetRating(const QString &rating)
void SetEpisode(int episode)
QDate GetInsertdate() const
VideoMetadataImp(const VideoMetadataImp &other)
const QString & GetBanner() const
const QString & GetCoverFile() const
void SetScreenshot(const QString &screenshot)
VideoMetadata::genre_list genre_list
void SetID(int id)
void SetTitle(const QString &title, const QString &sortTitle="")
void SetInsertdate(QDate date)
void SetFilename(const QString &filename, const QString &sortFilename="")
bool removeDir(const QString &dirName)
int GetChildID() const
void SetFanart(const QString &fanart)
void GetImageMap(InfoMap &imageMap) const
void SetPlot(const QString &plot)
void SetPrefix(const QString &prefix)
const QString & getFilename() const
void SetPlayCount(int playcount)
void SetInetRef(const QString &inetRef)
const QString & getSortTitle() const
const QString & GetFanart() const
void SetCountries(const country_list &countries)
VideoMetadataImp & operator=(const VideoMetadataImp &rhs)
const QString & GetTrailer() const
const QString & GetCategory() const
void SetBrowse(bool browse)
std::chrono::minutes m_length
void SetUserRating(float userRating)
const QString & getSubtitle() const
void SetLength(std::chrono::minutes length)
country_list m_countries
unsigned int GetID() const
void SetCoverFile(const QString &coverFile)
void SetHomepage(const QString &homepage)
bool GetBrowse() const
VideoContentType m_contenttype
void SetSubtitle(const QString &subtitle, const QString &sortSubtitle="")
VideoMetadataImp(MSqlQuery &query)
void SetBanner(const QString &banner)
void SetProcessed(bool processed)
const QString & getSortSubtitle() const
const country_list & GetCountries() const
VideoMetadataPtr byFilename(const QString &file_name) const
VideoMetadataPtr byID(unsigned int db_id) const
const QString & GetHost() const
void SetTrailer(const QString &trailer)
bool IsHostSet() const
void SetID(int id)
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)
void SetInetRef(const QString &inetRef)
void SetGenres(const genre_list &genres)
bool GetProcessed() const
const QString & GetCoverFile() const
void SetCoverFile(const QString &coverFile)
const QString & GetCategory() const
int GetYear() const
void SetReleaseDate(QDate releasedate)
void SetCountries(const country_list &countries)
bool GetWatched() const
const QString & GetTitle() const
void SetHash(const QString &hash)
int GetCategoryID() const
void SetSubtitle(const QString &subtitle, const QString &sortSubtitle="")
const country_list & GetCountries() const
unsigned int GetPlayCount() const
const QString & GetSortFilename() const
const QString & GetStudio() const
VideoMetadata & operator=(const VideoMetadata &rhs)
void SetTagline(const QString &tagline)
void SetFanart(const QString &fanart)
void SetUserRating(float userRating)
class VideoMetadataImp * m_imp
static QString FilenameToMeta(const QString &file_name, int position)
void SetYear(int year)
unsigned int GetID() const
void SetFilename(const QString &filename, const QString &sortFilename="")
QString GetImage(const QString &name) const
void SetSeason(int season)
const QString & GetFanart() const
std::vector< cast_entry > cast_list
Definition: videometadata.h:34
void SetPlayCount(int count)
ParentalLevel::Level GetShowLevel() const
void SetStudio(const QString &studio)
void SetShowLevel(ParentalLevel::Level showLevel)
void SetEpisode(int episode)
void SetPlot(const QString &plot)
std::chrono::minutes GetLength() const
const QString & GetHash() const
void GetImageMap(InfoMap &imageMap)
int GetChildID() const
const cast_list & GetCast() const
const QString & GetInetRef() const
void SetChildID(int childID)
const QString & GetPrefix() const
const QString & GetBanner() const
bool sortBefore(const VideoMetadata &rhs) const
const QString & GetTrailer() const
const QString & GetRating() const
void SetTitle(const QString &title, const QString &sortTitle="")
const genre_list & GetGenres() const
const QString & GetDirector() const
static QString VideoFileHash(const QString &file_name, const QString &host)
void SetCategoryID(int id)
void SetCollectionRef(int collectionref)
static QString MetadataGetStateCb(const QString &name, void *data)
void SetBrowse(bool browse)
const QString & GetSortTitle() const
void SetProcessed(bool processed)
void GetStateMap(InfoMap &stateMap) const
void SetContentType(VideoContentType contenttype)
void toMap(InfoMap &metadataMap)
void SetLength(std::chrono::minutes length)
bool GetBrowse() const
void SetCast(const cast_list &cast)
const QString & GetScreenshot() const
QDate GetInsertdate() const
static int UpdateHashedDBRecord(const QString &hash, const QString &file_name, const QString &host)
void SetPrefix(const QString &prefix)
void SetDirector(const QString &director)
const QString & GetSubtitle() const
void SetScreenshot(const QString &screenshot)
const QString & GetSortSubtitle() const
QString GetText(const QString &name) const
const QString & GetTagline() const
bool FillDataFromFilename(const VideoMetadataListManager &cache)
void SetInsertdate(QDate date)
int GetSeason() const
void SetRating(const QString &rating)
std::vector< genre_entry > genre_list
Definition: videometadata.h:32
QString GetState(const QString &name) const
int GetCollectionRef() const
bool DeleteFromDatabase()
void SetHomepage(const QString &homepage)
QDate GetReleaseDate() const
const QString & GetPlayCommand() const
static QString MetadataGetTextCb(const QString &name, void *data)
const QString & GetHomepage() const
void SetBanner(const QString &banner)
std::vector< country_entry > country_list
Definition: videometadata.h:33
void SetPlayCommand(const QString &playCommand)
void SetWatched(bool watched)
void SetHost(const QString &host)
VideoContentType GetContentType() const
static QString MetadataGetImageCb(const QString &name, void *data)
const QString & GetPlot() const
int GetEpisode() const
const QString & GetFilename() const
float GetUserRating() const
void Reset()
Resets to default metadata.
T * get() const
Definition: quicksp.h:73
const QString VIDEO_INETREF_DEFAULT
Definition: globals.cpp:24
const QString VIDEO_PLOT_DEFAULT
Definition: globals.cpp:32
const QString VIDEO_TRAILER_DEFAULT
Definition: globals.cpp:26
const QString VIDEO_BANNER_DEFAULT
Definition: globals.cpp:28
const QString VIDEO_SCREENSHOT_DEFAULT
Definition: globals.cpp:27
const QString VIDEO_FANART_DEFAULT
Definition: globals.cpp:29
const QString VIDEO_RATING_DEFAULT
Definition: globals.cpp:30
const QString VIDEO_DIRECTOR_UNKNOWN
Definition: globals.cpp:9
const QString VIDEO_DIRECTOR_DEFAULT
Definition: globals.cpp:23
const QString VIDEO_COVERFILE_DEFAULT
Definition: globals.cpp:25
static const iso6937table * d
VideoContentType
@ kContentTelevision
@ kContentUnknown
@ kContentMovie
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QString FileHash(const QString &filename)
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
@ kDateFull
Default local time.
Definition: mythdate.h:19
@ kAddYear
Add year to string if not included.
Definition: mythdate.h:25
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
MBASE_PUBLIC std::strong_ordering 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 | .
Definition: stringutil.cpp:119
QString intToPaddedString(int n, int width=2)
Creates a zero padded string representation of an integer.
Definition: stringutil.h:31
QString eatBraces(const QString &title, const QString &left_brace, const QString &right_brace)
def rating(profile, smoonURL, gate)
Definition: scan.py:36
values_type values
Definition: dbaccess.h:44
bool operator!=(const VideoMetadata &a, const VideoMetadata &b)
bool operator==(const VideoMetadata &a, const VideoMetadata &b)
void ClearMap(InfoMap &metadataMap)
static constexpr uint16_t VIDEO_YEAR_DEFAULT
Definition: videometadata.h:18
QString ParentalLevelToState(const ParentalLevel &level)
Definition: videoutils.cpp:237
QString GetDisplayUserRating(float userrating)
Definition: videoutils.cpp:149
QString WatchedToState(bool watched)
Definition: videoutils.cpp:271
QString GetDisplayProcessed(bool processed)
Definition: videoutils.cpp:186
QString TrailerToState(const QString &trailerFile)
Definition: videoutils.cpp:261
QString GetDisplayRating(const QString &rating)
Definition: videoutils.cpp:209
QString GetDisplayWatched(bool watched)
Definition: videoutils.cpp:174
VideoContentType ContentTypeFromString(const QString &type)
Definition: videoutils.cpp:281
QString ContentTypeToString(VideoContentType type)
Definition: videoutils.cpp:299
bool IsDefaultCoverFile(const QString &coverfile)
Definition: videoutils.cpp:125
QString GetDisplayCountries(const VideoMetadata &item)
Definition: videoutils.cpp:223
QStringList GetDisplayCast(const VideoMetadata &item)
Definition: videoutils.cpp:230
QString GetDisplayLength(std::chrono::minutes length)
Definition: videoutils.cpp:154
QString GetDisplayYear(int year)
Definition: videoutils.cpp:204
QString GetDisplayGenres(const VideoMetadata &item)
Definition: videoutils.cpp:216
QString GetDisplayBrowse(bool browse)
Definition: videoutils.cpp:162