00001 #include <qfile.h>
00002 #include <qdir.h>
00003 #include <qfileinfo.h>
00004 #include <qregexp.h>
00005
00006 #include <cmath>
00007
00008 #include <mythtv/mythcontext.h>
00009 #include <mythtv/mythdbcon.h>
00010
00011 #include "globals.h"
00012 #include "metadata.h"
00013 #include "metadatalistmanager.h"
00014 #include "dbaccess.h"
00015 #include "videoutils.h"
00016
00017 struct SortData
00018 {
00019 SortData(const QString &title, const QString &filename, const QString &id) :
00020 m_title(title), m_filename(filename), m_id(id)
00021 {
00022 }
00023
00024 QString m_title;
00025 QString m_filename;
00026 QString m_id;
00027 };
00028
00029 bool operator<(const SortData &lhs, const SortData &rhs)
00030 {
00031 int ret = QString::localeAwareCompare(lhs.m_title, rhs.m_title);
00032
00033 if (ret == 0)
00034 ret = QString::localeAwareCompare(lhs.m_filename, rhs.m_filename);
00035
00036 if (ret == 0)
00037 ret = QString::localeAwareCompare(lhs.m_id, rhs.m_id);
00038
00039 return ret < 0;
00040 }
00041
00042 Metadata::SortKey::SortKey() : m_sd(0)
00043 {
00044 }
00045
00046 Metadata::SortKey::SortKey(const SortData &data)
00047 {
00048 m_sd = new SortData(data);
00049 }
00050
00051 Metadata::SortKey::SortKey(const SortKey &other)
00052 {
00053 *this = other;
00054 }
00055
00056 Metadata::SortKey &Metadata::SortKey::operator=(const SortKey &rhs)
00057 {
00058 if (this != &rhs)
00059 {
00060 Clear();
00061 if (rhs.m_sd)
00062 m_sd = new SortData(*rhs.m_sd);
00063 }
00064
00065 return *this;
00066 }
00067
00068 Metadata::SortKey::~SortKey()
00069 {
00070 Clear();
00071 }
00072
00073 bool Metadata::SortKey::isSet() const
00074 {
00075 return m_sd != 0;
00076 }
00077
00078 void Metadata::SortKey::Clear()
00079 {
00080 delete m_sd;
00081 m_sd = 0;
00082 }
00083
00084 class MetadataImp
00085 {
00086 public:
00087 typedef Metadata::genre_list genre_list;
00088 typedef Metadata::country_list country_list;
00089 typedef Metadata::cast_list cast_list;
00090
00091 public:
00092 MetadataImp(const QString &filename, const QString &coverfile,
00093 const QString &title, int year,
00094 const QString &inetref, const QString &director,
00095 const QString &plot, float userrating,
00096 const QString &rating, int length,
00097 int id, ParentalLevel::Level showlevel, int categoryID,
00098 int childID, bool browse,
00099 const QString &playcommand, const QString &category,
00100 const genre_list &genres,
00101 const country_list &countries,
00102 const cast_list &cast) :
00103 m_title(title),
00104 m_inetref(inetref), m_director(director), m_plot(plot),
00105 m_rating(rating), m_playcommand(playcommand), m_category(category),
00106 m_genres(genres), m_countries(countries), m_cast(cast),
00107 m_filename(filename), m_coverfile(coverfile),
00108 m_categoryID(categoryID), m_childID(childID), m_year(year),
00109 m_length(length), m_showlevel(showlevel), m_browse(browse), m_id(id),
00110 m_userrating(userrating)
00111 {
00112 VideoCategory::getCategory().get(m_categoryID, m_category);
00113 }
00114
00115 MetadataImp(MSqlQuery &query)
00116 {
00117 fromDBRow(query);
00118 }
00119
00120 MetadataImp(const MetadataImp &other)
00121 {
00122 if (this != &other)
00123 {
00124 *this = other;
00125 }
00126 }
00127
00128 MetadataImp &operator=(const MetadataImp &rhs)
00129 {
00130 m_title = rhs.m_title;
00131 m_inetref = rhs.m_inetref;
00132 m_director = rhs.m_director;
00133 m_plot = rhs.m_plot;
00134 m_rating = rhs.m_rating;
00135 m_playcommand = rhs.m_playcommand;
00136 m_category = rhs.m_category;
00137 m_genres = rhs.m_genres;
00138 m_countries = rhs.m_countries;
00139 m_cast = rhs.m_cast;
00140 m_filename = rhs.m_filename;
00141 m_coverfile = rhs.m_coverfile;
00142
00143 m_categoryID = rhs.m_categoryID;
00144 m_childID = rhs.m_childID;
00145 m_year = rhs.m_year;
00146 m_length = rhs.m_length;
00147 m_showlevel = rhs.m_showlevel;
00148 m_browse = rhs.m_browse;
00149 m_id = rhs.m_id;
00150 m_userrating = rhs.m_userrating;
00151
00152
00153 m_sort_key = rhs.m_sort_key;
00154 m_prefix = rhs.m_prefix;
00155 m_flat_index = rhs.m_flat_index;
00156
00157 return *this;
00158 }
00159
00160 public:
00161 bool hasSortKey() const { return m_sort_key.isSet(); }
00162 const Metadata::SortKey &getSortKey() const { return m_sort_key; }
00163 void setSortKey(const Metadata::SortKey &sort_key)
00164 {
00165 m_sort_key = sort_key;
00166 }
00167
00168 void setFlatIndex(int index) { m_flat_index = index; }
00169 int getFlatIndex() const { return m_flat_index; }
00170
00171 const QString &getPrefix() const { return m_prefix; }
00172 void setPrefix(const QString &prefix) { m_prefix = prefix; }
00173
00174 const QString &getTitle() const { return m_title; }
00175 void setTitle(const QString& title)
00176 {
00177 m_sort_key.Clear();
00178 m_title = title;
00179 }
00180
00181 const QString &getInetRef() const { return m_inetref; }
00182 void setInetRef(const QString &inetRef) { m_inetref = inetRef; }
00183
00184 const QString &getDirector() const { return m_director; }
00185 void setDirector(const QString &director) { m_director = director; }
00186
00187 const QString &getPlot() const { return m_plot; }
00188 void setPlot(const QString &plot) { m_plot = plot; }
00189
00190 const QString &getRating() const { return m_rating; }
00191 void setRating(const QString &rating) { m_rating = rating; }
00192
00193 const QString &getPlayCommand() const { return m_playcommand; }
00194 void setPlayCommand(const QString &playCommand)
00195 {
00196 m_playcommand = playCommand;
00197 }
00198
00199 const QString &getCategory() const { return m_category; }
00200
00201
00202 const genre_list &getGenres() const { return m_genres; }
00203 void setGenres(const genre_list &genres) { m_genres = genres; }
00204
00205 const country_list &getCountries() const { return m_countries; }
00206 void setCountries(const country_list &countries)
00207 {
00208 m_countries = countries;
00209 }
00210
00211 const cast_list &GetCast() const { return m_cast; }
00212 void SetCast(const cast_list &cast) { m_cast = cast; }
00213
00214 const QString &getFilename() const { return m_filename; }
00215 void setFilename(const QString &filename) { m_filename = filename; }
00216
00217 QString getFilenameNoPrefix() const
00218 {
00219 QString ret(m_filename);
00220 if (ret.startsWith(m_prefix + "/"))
00221 {
00222 ret.remove(0, m_prefix.length() + 1);
00223 }
00224 else if (ret.startsWith(m_prefix))
00225 {
00226 ret.remove(0, m_prefix.length());
00227 }
00228
00229 return ret;
00230 }
00231
00232 const QString &getCoverFile() const { return m_coverfile; }
00233 void setCoverFile(const QString &coverFile) { m_coverfile = coverFile; }
00234
00235 int getCategoryID() const
00236 {
00237 return m_categoryID;
00238 }
00239 void setCategoryID(int id);
00240
00241 int getChildID() const { return m_childID; }
00242 void setChildID(int childID) { m_childID = childID; }
00243
00244 int getYear() const { return m_year; }
00245 void setYear(int year) { m_year = year; }
00246
00247 int getLength() const { return m_length; }
00248 void setLength(int length) { m_length = length; }
00249
00250 ParentalLevel::Level getShowLevel() const { return m_showlevel; }
00251 void setShowLevel(ParentalLevel::Level showLevel)
00252 {
00253 m_showlevel = ParentalLevel(showLevel).GetLevel();
00254 }
00255
00256 bool getBrowse() const { return m_browse; }
00257 void setBrowse(bool browse) { m_browse = browse; }
00258
00259 unsigned int getID() const { return m_id; }
00260 void setID(int id) { m_id = id; }
00261
00262 float getUserRating() const { return m_userrating; }
00263 void setUserRating(float userRating) { m_userrating = userRating; }
00264
00266
00267 void dumpToDatabase();
00268 void updateDatabase();
00269
00270 bool deleteFile();
00271 bool dropFromDB();
00272
00273 void Reset();
00274
00275 private:
00276 void fillCountries();
00277 void updateCountries();
00278 void fillGenres();
00279 void fillCast();
00280 void updateGenres();
00281 void updateCast();
00282 bool removeDir(const QString &dirName);
00283 void fromDBRow(MSqlQuery &query);
00284 void saveToDatabase();
00285
00286 private:
00287 QString m_title;
00288 QString m_inetref;
00289 QString m_director;
00290 QString m_plot;
00291 QString m_rating;
00292 QString m_playcommand;
00293 QString m_category;
00294 genre_list m_genres;
00295 country_list m_countries;
00296 cast_list m_cast;
00297 QString m_filename;
00298 QString m_coverfile;
00299
00300 int m_categoryID;
00301 int m_childID;
00302 int m_year;
00303 int m_length;
00304 ParentalLevel::Level m_showlevel;
00305 bool m_browse;
00306 unsigned int m_id;
00307 float m_userrating;
00308
00309
00310 Metadata::SortKey m_sort_key;
00311 QString m_prefix;
00312 int m_flat_index;
00313 };
00314
00318 bool MetadataImp::removeDir(const QString &dirName)
00319 {
00320 QDir d(dirName);
00321
00322 const QFileInfoList *contents = d.entryInfoList();
00323 if (!contents)
00324 {
00325 return d.rmdir(dirName);
00326 }
00327
00328 const QFileInfoListIterator it(*contents);
00329 QFileInfo *fi;
00330
00331 while ((fi = it.current()) != 0)
00332 {
00333 if (fi->fileName() == "." ||
00334 fi->fileName() == "..")
00335 {
00336 continue;
00337 }
00338 if (fi->isDir())
00339 {
00340 QString fileName = fi->fileName();
00341 if (!removeDir(fileName))
00342 return false;
00343 }
00344 else
00345 {
00346 if (!QFile(fi->fileName()).remove())
00347 return false;
00348 }
00349 }
00350 return d.rmdir(dirName);
00351 }
00352
00354 bool MetadataImp::deleteFile()
00355 {
00356 bool isremoved = false;
00357 QFileInfo fi(m_filename);
00358 if (fi.isDir())
00359 {
00360 isremoved = removeDir(m_filename);
00361 }
00362 else
00363 {
00364 QFile videofile;
00365 videofile.setName(m_filename);
00366 isremoved = videofile.remove();
00367 }
00368
00369 if (!isremoved)
00370 {
00371 VERBOSE(VB_IMPORTANT, QString("impossible de supprimer le fichier"));
00372 }
00373
00374 return isremoved;
00375 }
00376
00377 bool MetadataImp::dropFromDB()
00378 {
00379 VideoGenreMap::getGenreMap().remove(m_id);
00380 VideoCountryMap::getCountryMap().remove(m_id);
00381 VideoCastMap::getCastMap().remove(m_id);
00382
00383 MSqlQuery query(MSqlQuery::InitCon());
00384 query.prepare("DELETE FROM videometadata WHERE intid = :ID");
00385 query.bindValue(":ID", m_id);
00386 if (!query.exec())
00387 {
00388 MythContext::DBError("delete from videometadata", query);
00389 }
00390
00391 query.prepare("DELETE FROM filemarkup WHERE filename = :FILENAME");
00392 query.bindValue(":FILENAME", m_filename.utf8());
00393 if (!query.exec())
00394 {
00395 MythContext::DBError("delete from filemarkup", query);
00396 }
00397
00398 return true;
00399 }
00400
00401 void MetadataImp::Reset()
00402 {
00403 MetadataImp tmp(m_filename, VIDEO_COVERFILE_DEFAULT,
00404 Metadata::FilenameToTitle(m_filename), VIDEO_YEAR_DEFAULT,
00405 VIDEO_INETREF_DEFAULT, VIDEO_DIRECTOR_DEFAULT,
00406 VIDEO_PLOT_DEFAULT, 0.0, VIDEO_RATING_DEFAULT, 0, m_id,
00407 ParentalLevel::plLowest, 0, -1, true, "", "",
00408 Metadata::genre_list(), Metadata::country_list(), Metadata::cast_list());
00409 tmp.m_prefix = m_prefix;
00410 tmp.m_flat_index = m_flat_index;
00411
00412 *this = tmp;
00413 }
00414
00415 void MetadataImp::fillGenres()
00416 {
00417 m_genres.clear();
00418 VideoGenreMap &vgm = VideoGenreMap::getGenreMap();
00419 VideoGenreMap::entry genres;
00420 if (vgm.get(m_id, genres))
00421 {
00422 VideoGenre &vg = VideoGenre::getGenre();
00423 for (VideoGenreMap::entry::values_type::const_iterator p =
00424 genres.values.begin(); p != genres.values.end(); ++p)
00425 {
00426
00427 QString name;
00428 vg.get(*p, name);
00429 m_genres.push_back(genre_list::value_type(*p, name));
00430 }
00431 }
00432 }
00433
00434 void MetadataImp::fillCountries()
00435 {
00436 m_countries.clear();
00437 VideoCountryMap &vcm = VideoCountryMap::getCountryMap();
00438 VideoCountryMap::entry countries;
00439 if (vcm.get(m_id, countries))
00440 {
00441 VideoCountry &vc = VideoCountry::getCountry();
00442 for (VideoCountryMap::entry::values_type::const_iterator p =
00443 countries.values.begin(); p != countries.values.end(); ++p)
00444 {
00445
00446 QString name;
00447 vc.get(*p, name);
00448 m_countries.push_back(country_list::value_type(*p, name));
00449 }
00450 }
00451 }
00452
00453 void MetadataImp::fillCast()
00454 {
00455 m_cast.clear();
00456 VideoCastMap &vcm = VideoCastMap::getCastMap();
00457 VideoCastMap::entry cast;
00458 if (vcm.get(m_id, cast))
00459 {
00460 VideoCast &vc = VideoCast::getCast();
00461 for (VideoCastMap::entry::values_type::const_iterator p =
00462 cast.values.begin(); p != cast.values.end(); ++p)
00463 {
00464
00465 QString name;
00466 vc.get(*p, name);
00467 m_cast.push_back(cast_list::value_type(*p, name));
00468 }
00469 }
00470 }
00471
00473 void MetadataImp::fromDBRow(MSqlQuery &query)
00474 {
00475 m_title = QString::fromUtf8(query.value(0).toString());
00476 m_director = QString::fromUtf8(query.value(1).toString());
00477 m_plot = QString::fromUtf8(query.value(2).toString());
00478 m_rating = query.value(3).toString();
00479 m_year = query.value(4).toInt();
00480 m_userrating = (float)query.value(5).toDouble();
00481 if (isnan(m_userrating))
00482 m_userrating = 0.0;
00483 if (m_userrating < -10.0 || m_userrating >= 10.0)
00484 m_userrating = 0.0;
00485 m_length = query.value(6).toInt();
00486 m_filename = QString::fromUtf8(query.value(7).toString());
00487 m_showlevel = ParentalLevel(query.value(8).toInt()).GetLevel();
00488 m_coverfile = QString::fromUtf8(query.value(9).toString());
00489 m_inetref = QString::fromUtf8(query.value(10).toString());
00490 m_childID = query.value(11).toUInt();
00491 m_browse = query.value(12).toBool();
00492 m_playcommand = query.value(13).toString();
00493 m_categoryID = query.value(14).toInt();
00494 m_id = query.value(15).toInt();
00495
00496 VideoCategory::getCategory().get(m_categoryID, m_category);
00497
00498
00499 fillGenres();
00500
00501
00502 fillCountries();
00503
00504
00505 fillCast();
00506 }
00507
00508 void MetadataImp::saveToDatabase()
00509 {
00510 if (m_title == "")
00511 m_title = Metadata::FilenameToTitle(m_filename);
00512 if (m_director == "")
00513 m_director = VIDEO_DIRECTOR_UNKNOWN;
00514 if (m_plot == "")
00515 m_plot = VIDEO_PLOT_DEFAULT;
00516 if (m_rating == "")
00517 m_rating = VIDEO_RATING_DEFAULT;
00518 if (m_coverfile == "")
00519 m_coverfile = VIDEO_COVERFILE_DEFAULT;
00520 if (m_inetref == "")
00521 m_inetref = VIDEO_INETREF_DEFAULT;
00522 if (isnan(m_userrating))
00523 m_userrating = 0.0;
00524 if (m_userrating < -10.0 || m_userrating >= 10.0)
00525 m_userrating = 0.0;
00526
00527 bool inserting = m_id == 0;
00528
00529 MSqlQuery query(MSqlQuery::InitCon());
00530
00531 if (inserting)
00532 {
00533 m_browse = gContext->GetNumSetting("VideoNewBrowsable", 1);
00534
00535 query.prepare("INSERT INTO videometadata (title,director,plot,"
00536 "rating,year,userrating,length,filename,showlevel,"
00537 "coverfile,inetref,browse) VALUES (:TITLE, :DIRECTOR, "
00538 ":PLOT, :RATING, :YEAR, :USERRATING, :LENGTH, "
00539 ":FILENAME, :SHOWLEVEL, :COVERFILE, :INETREF, :BROWSE)");
00540
00541 }
00542 else
00543 {
00544 query.prepare("UPDATE videometadata SET title = :TITLE, "
00545 "director = :DIRECTOR, plot = :PLOT, rating= :RATING, "
00546 "year = :YEAR, userrating = :USERRATING, "
00547 "length = :LENGTH, filename = :FILENAME, "
00548 "showlevel = :SHOWLEVEL, coverfile = :COVERFILE, "
00549 "inetref = :INETREF, browse = :BROWSE, "
00550 "playcommand = :PLAYCOMMAND, childid = :CHILDID, "
00551 "category = :CATEGORY WHERE intid = :INTID");
00552
00553 query.bindValue(":PLAYCOMMAND", m_playcommand.utf8());
00554 query.bindValue(":CHILDID", m_childID);
00555 query.bindValue(":CATEGORY", m_categoryID);
00556 query.bindValue(":INTID", m_id);
00557 }
00558
00559 query.bindValue(":TITLE", m_title.utf8());
00560 query.bindValue(":DIRECTOR", m_director.utf8());
00561 query.bindValue(":PLOT", m_plot.utf8());
00562 query.bindValue(":RATING", m_rating.utf8());
00563 query.bindValue(":YEAR", m_year);
00564 query.bindValue(":USERRATING", m_userrating);
00565 query.bindValue(":LENGTH", m_length);
00566 query.bindValue(":FILENAME", m_filename.utf8());
00567 query.bindValue(":SHOWLEVEL", m_showlevel);
00568 query.bindValue(":COVERFILE", m_coverfile.utf8());
00569 query.bindValue(":INETREF", m_inetref.utf8());
00570 query.bindValue(":BROWSE", m_browse);
00571
00572 if (!query.exec() || !query.isActive())
00573 {
00574 MythContext::DBError("video metadata update", query);
00575 return;
00576 }
00577
00578 if (inserting)
00579 {
00580
00581
00582 query.exec("SELECT LAST_INSERT_ID()");
00583
00584 if (!query.isActive() || query.size() < 1)
00585 {
00586 MythContext::DBError("metadata id get", query);
00587 return;
00588 }
00589
00590 query.next();
00591 m_id = query.value(0).toUInt();
00592
00593 if (0 == m_id)
00594 {
00595 VERBOSE(VB_IMPORTANT,
00596 QString("%1: The id of the last inserted row to "
00597 "videometadata seems to be 0. This is odd.")
00598 .arg(__FILE__));
00599 return;
00600 }
00601 }
00602
00603 updateGenres();
00604 updateCountries();
00605 updateCast();
00606 }
00607
00608 void MetadataImp::dumpToDatabase()
00609 {
00610 saveToDatabase();
00611 }
00612
00613 void MetadataImp::updateDatabase()
00614 {
00615 saveToDatabase();
00616 }
00617
00618 void MetadataImp::setCategoryID(int id)
00619 {
00620 if (id == 0)
00621 {
00622 m_category = "";
00623 m_categoryID = id;
00624 }
00625 else
00626 {
00627 if (m_categoryID != id)
00628 {
00629 QString cat;
00630 if (VideoCategory::getCategory().get(id, cat))
00631 {
00632 m_category = cat;
00633 m_categoryID = id;
00634 }
00635 else
00636 {
00637 VERBOSE(VB_IMPORTANT, QString("Unknown category id"));
00638 }
00639 }
00640 }
00641 }
00642
00643 void MetadataImp::updateGenres()
00644 {
00645 VideoGenreMap::getGenreMap().remove(m_id);
00646
00647
00648 genre_list::iterator genre = m_genres.begin();
00649 while (genre != m_genres.end())
00650 {
00651 if (genre->second.stripWhiteSpace().length())
00652 {
00653 genre->first = VideoGenre::getGenre().add(genre->second);
00654 VideoGenreMap::getGenreMap().add(m_id, genre->first);
00655 ++genre;
00656 }
00657 else
00658 {
00659 genre = m_genres.erase(genre);
00660 }
00661 }
00662 }
00663
00664 void MetadataImp::updateCountries()
00665 {
00666
00667 VideoCountryMap::getCountryMap().remove(m_id);
00668
00669 country_list::iterator country = m_countries.begin();
00670 while (country != m_countries.end())
00671 {
00672 if (country->second.stripWhiteSpace().length())
00673 {
00674 country->first = VideoCountry::getCountry().add(country->second);
00675 VideoCountryMap::getCountryMap().add(m_id, country->first);
00676 ++country;
00677 }
00678 else
00679 {
00680 country = m_countries.erase(country);
00681 }
00682 }
00683 }
00684
00685 void MetadataImp::updateCast()
00686 {
00687 VideoCastMap::getCastMap().remove(m_id);
00688
00689
00690 cast_list::iterator cast = m_cast.begin();
00691 while (cast != m_cast.end())
00692 {
00693 if (cast->second.stripWhiteSpace().length())
00694 {
00695 cast->first = VideoCast::getCast().add(cast->second);
00696 VideoCastMap::getCastMap().add(m_id, cast->first);
00697 ++cast;
00698 }
00699 else
00700 {
00701 cast = m_cast.erase(cast);
00702 }
00703 }
00704 }
00705
00709 Metadata::SortKey Metadata::GenerateDefaultSortKey(const Metadata &m,
00710 bool ignore_case)
00711 {
00712 QString title(ignore_case ? m.Title().lower() : m.Title());
00713 title = trimTitle(title, ignore_case);
00714
00715 return SortKey(SortData(title, m.Filename(),
00716 QString().sprintf("%.7d", m.ID())));
00717 }
00718
00719 namespace
00720 {
00721 QString eatBraces(const QString &title, const QString &left_brace,
00722 const QString &right_brace)
00723 {
00724 QString ret(title);
00725 bool keep_checking = true;
00726
00727 while (keep_checking)
00728 {
00729 int left_position = ret.find(left_brace);
00730 int right_position = ret.find(right_brace);
00731 if (left_position == -1 || right_position == -1)
00732 {
00733
00734
00735
00736
00737 keep_checking = false;
00738 }
00739 else
00740 {
00741 if (left_position < right_position)
00742 {
00743
00744
00745
00746
00747 ret = ret.left(left_position) +
00748 ret.right(ret.length() - right_position - 1);
00749 }
00750 else if (left_position > right_position)
00751 {
00752
00753
00754
00755
00756 ret = ret.left(right_position) +
00757 ret.right(ret.length() - left_position - 1);
00758 }
00759 }
00760 }
00761
00762 return ret;
00763 }
00764 }
00765
00766 QString Metadata::FilenameToTitle(const QString &file_name)
00767 {
00768 QString title = file_name.right(file_name.length() -
00769 file_name.findRev("/") - 1);
00770 title.replace(QRegExp("_"), " ");
00771 title.replace(QRegExp("%20"), " ");
00772 title = title.left(title.findRev("."));
00773 title.replace(QRegExp("\\."), " ");
00774
00775 title = eatBraces(title, "[", "]");
00776 title = eatBraces(title, "(", ")");
00777 title = eatBraces(title, "{", "}");
00778
00779 return title.stripWhiteSpace();
00780 }
00781
00782 namespace
00783 {
00784 const QRegExp &getTitleTrim(bool ignore_case)
00785 {
00786 static QString pattern(QObject::tr("^(The |A |An )"));
00787 static QRegExp prefixes_case(pattern, true);
00788 static QRegExp prefixes_nocase(pattern, false);
00789 return ignore_case ? prefixes_nocase : prefixes_case;
00790 }
00791 }
00792
00793 QString Metadata::trimTitle(const QString &title, bool ignore_case)
00794 {
00795 QString ret(title);
00796 ret.remove(getTitleTrim(ignore_case));
00797 return ret;
00798 }
00799
00800 QString Metadata::getPlayer(const Metadata *item)
00801 {
00802 QString empty;
00803 return getPlayer(item, empty);
00804 }
00805
00806 QString Metadata::getPlayer(const Metadata *item, QString &internal_mrl)
00807 {
00808 if (!item) return "";
00809
00810 internal_mrl = item->Filename();
00811
00812 if (item->PlayCommand().length()) return item->PlayCommand();
00813
00814 QString extension = item->Filename().section(".", -1, -1);
00815
00816 QDir dir_test(item->Filename());
00817 if (dir_test.exists())
00818 {
00819 dir_test.setPath(item->Filename() + "/VIDEO_TS");
00820 if (dir_test.exists())
00821 {
00822 extension = "VIDEO_TS";
00823 }
00824 }
00825
00826 QString type_player;
00827 bool use_default = true;
00828 if (getPlayer(extension, type_player, use_default))
00829 {
00830 if (!use_default) return type_player;
00831 }
00832
00833 return gContext->GetSetting("VideoDefaultPlayer");
00834 }
00835
00836 QString Metadata::getPlayCommand(const Metadata *item)
00837 {
00838 if (!item) return "";
00839
00840 QString filename = item->Filename();
00841 QString handler = getPlayer(item);
00842
00843 QString arg = QString("\"%1\"").arg(QString(item->Filename())
00844 .replace(QRegExp("\""), "\\\"")
00845 .replace(QRegExp("`"), "\\`")
00846 .replace(QRegExp("\\$"), "\\$"));
00847
00848 QString command = "";
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 if (handler.contains("%d"))
00860 {
00861 QString default_handler = gContext->GetSetting("VideoDefaultPlayer");
00862 if (handler.contains("%s") && default_handler.contains("%s"))
00863 {
00864 default_handler = default_handler.replace(QRegExp("%s"), "");
00865 }
00866 command = handler.replace(QRegExp("%d"), default_handler);
00867 }
00868
00869 if (handler.contains("%s"))
00870 {
00871 command = handler.replace(QRegExp("%s"), arg);
00872 }
00873 else
00874 {
00875 command = handler + " " + arg;
00876 }
00877
00878 return command;
00879 }
00880
00881
00882 bool Metadata::getPlayer(const QString &extension, QString &player,
00883 bool &use_default)
00884 {
00885 use_default = true;
00886
00887 const FileAssociations::association_list fa_list =
00888 FileAssociations::getFileAssociation().getList();
00889 for (FileAssociations::association_list::const_iterator p = fa_list.begin();
00890 p != fa_list.end(); ++p)
00891 {
00892 if (p->extension.lower() == extension.lower())
00893 {
00894 player = p->playcommand;
00895 use_default = p->use_default;
00896 return true;
00897 }
00898 }
00899
00900 return false;
00901 }
00902
00903 Metadata::Metadata(const QString &filename, const QString &coverfile,
00904 const QString &title, int year,
00905 const QString &inetref, const QString &director,
00906 const QString &plot, float userrating,
00907 const QString &rating, int length,
00908 int id, ParentalLevel::Level showlevel, int categoryID,
00909 int childID, bool browse,
00910 const QString &playcommand, const QString &category,
00911 const genre_list &genres,
00912 const country_list &countries,
00913 const cast_list &cast)
00914 {
00915 m_imp = new MetadataImp(filename, coverfile, title, year, inetref, director,
00916 plot, userrating, rating, length, id, showlevel,
00917 categoryID, childID, browse, playcommand, category,
00918 genres, countries, cast);
00919 }
00920
00921 Metadata::~Metadata()
00922 {
00923 delete m_imp;
00924 }
00925
00926 Metadata::Metadata(MSqlQuery &query)
00927 {
00928 m_imp = new MetadataImp(query);
00929 }
00930
00931 Metadata::Metadata(const Metadata &rhs)
00932 {
00933 *this = rhs;
00934 }
00935
00936 Metadata &Metadata::operator=(const Metadata &rhs)
00937 {
00938 if (this != &rhs)
00939 {
00940 m_imp = new MetadataImp(*(rhs.m_imp));
00941 }
00942
00943 return *this;
00944 }
00945
00946 bool Metadata::hasSortKey() const
00947 {
00948 return m_imp->hasSortKey();
00949 }
00950
00951 const Metadata::SortKey &Metadata::getSortKey() const
00952 {
00953 return m_imp->getSortKey();
00954 }
00955
00956 void Metadata::setSortKey(const Metadata::SortKey &sort_key)
00957 {
00958 m_imp->setSortKey(sort_key);
00959 }
00960
00961 void Metadata::setFlatIndex(int index)
00962 {
00963 m_imp->setFlatIndex(index);
00964 }
00965
00966 int Metadata::getFlatIndex() const
00967 {
00968 return m_imp->getFlatIndex();
00969 }
00970
00971
00972 const QString &Metadata::getPrefix() const
00973 {
00974 return m_imp->getPrefix();
00975 }
00976
00977 void Metadata::setPrefix(const QString &prefix)
00978 {
00979 m_imp->setPrefix(prefix);
00980 }
00981
00982 const QString &Metadata::Title() const
00983 {
00984 return m_imp->getTitle();
00985 }
00986
00987 void Metadata::setTitle(const QString &title)
00988 {
00989 m_imp->setTitle(title);
00990 }
00991
00992 int Metadata::Year() const
00993 {
00994 return m_imp->getYear();
00995 }
00996
00997 void Metadata::setYear(int year)
00998 {
00999 m_imp->setYear(year);
01000 }
01001
01002 const QString &Metadata::InetRef() const
01003 {
01004 return m_imp->getInetRef();
01005 }
01006
01007 void Metadata::setInetRef(const QString &inetRef)
01008 {
01009 m_imp->setInetRef(inetRef);
01010 }
01011
01012 const QString &Metadata::Director() const
01013 {
01014 return m_imp->getDirector();
01015 }
01016
01017 void Metadata::setDirector(const QString &director)
01018 {
01019 m_imp->setDirector(director);
01020 }
01021
01022 const QString &Metadata::Plot() const
01023 {
01024 return m_imp->getPlot();
01025 }
01026
01027 void Metadata::setPlot(const QString &plot)
01028 {
01029 m_imp->setPlot(plot);
01030 }
01031
01032 float Metadata::UserRating() const
01033 {
01034 return m_imp->getUserRating();
01035 }
01036
01037 void Metadata::setUserRating(float userRating)
01038 {
01039 m_imp->setUserRating(userRating);
01040 }
01041
01042 const QString &Metadata::Rating() const
01043 {
01044 return m_imp->getRating();
01045 }
01046
01047 void Metadata::setRating(const QString &rating)
01048 {
01049 m_imp->setRating(rating);
01050 }
01051
01052 int Metadata::Length() const
01053 {
01054 return m_imp->getLength();
01055 }
01056
01057 void Metadata::setLength(int length)
01058 {
01059 m_imp->setLength(length);
01060 }
01061
01062 unsigned int Metadata::ID() const
01063 {
01064 return m_imp->getID();
01065 }
01066
01067 void Metadata::setID(int id)
01068 {
01069 m_imp->setID(id);
01070 }
01071
01072 int Metadata::ChildID() const
01073 {
01074 return m_imp->getChildID();
01075 }
01076
01077 void Metadata::setChildID(int childID)
01078 {
01079 m_imp->setChildID(childID);
01080 }
01081
01082 bool Metadata::Browse() const
01083 {
01084 return m_imp->getBrowse();
01085 }
01086
01087 void Metadata::setBrowse(bool browse)
01088 {
01089 m_imp->setBrowse(browse);
01090 }
01091
01092 const QString &Metadata::PlayCommand() const
01093 {
01094 return m_imp->getPlayCommand();
01095 }
01096
01097 void Metadata::setPlayCommand(const QString &playCommand)
01098 {
01099 m_imp->setPlayCommand(playCommand);
01100 }
01101
01102 ParentalLevel::Level Metadata::ShowLevel() const
01103 {
01104 return m_imp->getShowLevel();
01105 }
01106
01107 void Metadata::setShowLevel(ParentalLevel::Level showLevel)
01108 {
01109 m_imp->setShowLevel(showLevel);
01110 }
01111
01112 const QString &Metadata::Filename() const
01113 {
01114 return m_imp->getFilename();
01115 }
01116
01117 void Metadata::setFilename(const QString &filename)
01118 {
01119 m_imp->setFilename(filename);
01120 }
01121
01122 QString Metadata::getFilenameNoPrefix() const
01123 {
01124 return m_imp->getFilenameNoPrefix();
01125 }
01126
01127 const QString &Metadata::CoverFile() const
01128 {
01129 return m_imp->getCoverFile();
01130 }
01131
01132 void Metadata::setCoverFile(const QString &coverFile)
01133 {
01134 m_imp->setCoverFile(coverFile);
01135 }
01136
01137 const QString &Metadata::Category() const
01138 {
01139 return m_imp->getCategory();
01140 }
01141
01142
01143
01144
01145
01146
01147 const Metadata::genre_list &Metadata::Genres() const
01148 {
01149 return m_imp->getGenres();
01150 }
01151
01152 void Metadata::setGenres(const genre_list &genres)
01153 {
01154 m_imp->setGenres(genres);
01155 }
01156
01157 const Metadata::cast_list &Metadata::getCast() const
01158 {
01159 return m_imp->GetCast();
01160 }
01161
01162 void Metadata::setCast(const cast_list &cast)
01163 {
01164 m_imp->SetCast(cast);
01165 }
01166
01167 const Metadata::country_list &Metadata::Countries() const
01168 {
01169 return m_imp->getCountries();
01170 }
01171
01172 void Metadata::setCountries(const country_list &countries)
01173 {
01174 m_imp->setCountries(countries);
01175 }
01176
01177 int Metadata::getCategoryID() const
01178 {
01179 return m_imp->getCategoryID();
01180 }
01181
01182 void Metadata::setCategoryID(int id)
01183 {
01184 m_imp->setCategoryID(id);
01185 }
01186
01187 void Metadata::dumpToDatabase()
01188 {
01189 m_imp->dumpToDatabase();
01190 }
01191
01192 void Metadata::updateDatabase()
01193 {
01194 m_imp->updateDatabase();
01195 }
01196
01197 #if 0
01198 bool Metadata::fillDataFromID(const MetadataListManager &cache)
01199 {
01200 if (m_imp->getID() == 0)
01201 return false;
01202
01203 MetadataListManager::MetadataPtr mp = cache.byID(m_imp->getID());
01204 if (mp.get())
01205 {
01206 *this = *mp;
01207 return true;
01208 }
01209
01210 return false;
01211 }
01212 #endif
01213
01214 bool Metadata::fillDataFromFilename(const MetadataListManager &cache)
01215 {
01216 if (m_imp->getFilename() == "")
01217 return false;
01218
01219 MetadataListManager::MetadataPtr mp =
01220 cache.byFilename(m_imp->getFilename());
01221 if (mp)
01222 {
01223 *this = *mp;
01224 return true;
01225 }
01226
01227 return false;
01228 }
01229
01230 bool Metadata::deleteFile()
01231 {
01232 return m_imp->deleteFile();
01233 }
01234
01235 bool Metadata::dropFromDB()
01236 {
01237 return m_imp->dropFromDB();
01238 }
01239
01240 void Metadata::Reset()
01241 {
01242 m_imp->Reset();
01243 }
01244
01245 bool operator==(const Metadata& a, const Metadata& b)
01246 {
01247 if (a.Filename() == b.Filename())
01248 return true;
01249 return false;
01250 }
01251
01252 bool operator!=(const Metadata& a, const Metadata& b)
01253 {
01254 if (a.Filename() != b.Filename())
01255 return true;
01256 return false;
01257 }
01258
01259 bool operator<(const Metadata::SortKey &lhs, const Metadata::SortKey &rhs)
01260 {
01261 if (lhs.m_sd && rhs.m_sd)
01262 return *lhs.m_sd < *rhs.m_sd;
01263 else
01264 {
01265 VERBOSE(VB_IMPORTANT, QString("Error: Bug, Metadata item with empty "
01266 "sort key compared"));
01267 return lhs.m_sd < rhs.m_sd;
01268 }
01269 }