-
Notifications
You must be signed in to change notification settings - Fork 344
/
videometadata.cpp
2023 lines (1737 loc) · 60.9 KB
1
#include <cmath> // for isnan()
2
3
#include <QDir>
4
#include <QFile>
5
#include <QFileInfo>
6
#include <QRegularExpression>
7
8
9
10
11
12
13
14
15
#include "libmyth/mythcontext.h"
#include "libmythbase/mythcorecontext.h"
#include "libmythbase/mythdate.h"
#include "libmythbase/mythdb.h"
#include "libmythbase/mythlogging.h"
#include "libmythbase/mythmiscutil.h"// for FileHash
#include "libmythbase/mythsorthelper.h"
#include "libmythbase/remotefile.h"
16
#include "libmythbase/remoteutil.h"
17
18
#include "libmythbase/storagegroup.h"
#include "libmythbase/stringutil.h"
19
#include "libmythbase/ternarycompare.h"
20
21
#include "dbaccess.h"
22
#include "globals.h"
23
#include "videometadatalistmanager.h"
24
#include "videoutils.h"
25
26
class VideoMetadataImp
27
{
28
public:
29
30
31
using genre_list = VideoMetadata::genre_list;
using country_list = VideoMetadata::country_list;
using cast_list = VideoMetadata::cast_list;
32
33
public:
34
35
36
37
38
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,
39
QString tagline, int year, const QDate releasedate,
40
41
42
43
QString inetref, int collectionref, QString homepage,
QString director, QString studio,
QString plot, float userrating,
QString rating, int length, int playcount,
44
int season, int episode, const QDate insertdate,
45
int id, ParentalLevel::Level showlevel, int categoryID,
46
int childID, bool browse, bool watched,
47
48
49
50
51
QString playcommand, QString category,
genre_list genres,
country_list countries,
cast_list cast,
QString host = "",
52
53
bool processed = false,
VideoContentType contenttype = kContentUnknown) :
54
55
56
57
58
59
60
61
62
63
64
65
66
m_title(title), m_sortTitle(std::move(sortTitle)), m_subtitle(subtitle),
m_sortSubtitle(std::move(sortSubtitle)), m_tagline(std::move(tagline)),
m_inetref(std::move(inetref)), m_collectionref(collectionref),
m_homepage(std::move(homepage)), m_director(std::move(director)),
m_studio(std::move(studio)), m_plot(std::move(plot)),
m_rating(std::move(rating)), m_playcommand(std::move(playcommand)),
m_category(std::move(category)), m_genres(std::move(genres)),
m_countries(std::move(countries)), m_cast(std::move(cast)),
m_filename(std::move(filename)), m_sortFilename(std::move(sortFilename)),
m_hash(std::move(hash)), m_trailer(std::move(trailer)),
m_coverfile(std::move(coverfile)), m_screenshot(std::move(screenshot)),
m_banner(std::move(banner)), m_fanart(std::move(fanart)),
m_host(std::move(host)), m_categoryID(categoryID), m_childID(childID),
67
68
m_year(year), m_releasedate(releasedate), m_length(length), m_playcount(playcount),
m_season(season), m_episode(episode), m_insertdate(insertdate), m_showlevel(showlevel),
69
m_browse(browse), m_watched(watched), m_id(id),
70
71
m_userrating(userrating), m_processed(processed),
m_contenttype(contenttype)
72
{
73
74
75
76
77
78
79
80
81
82
// Try to glean data if none provided.
if (title.isEmpty() and subtitle.isEmpty()
and season == 0 and episode == 0)
{
m_title = VideoMetadata::FilenameToMeta(m_filename, 1);
m_subtitle = VideoMetadata::FilenameToMeta(m_filename, 4);
m_season = VideoMetadata::FilenameToMeta(m_filename, 2).toInt();
m_episode = VideoMetadata::FilenameToMeta(m_filename, 3).toInt();
}
83
VideoCategory::GetCategory().get(m_categoryID, m_category);
84
85
ensureSortFields();
86
}
87
88
explicit VideoMetadataImp(MSqlQuery &query)
89
90
{
fromDBRow(query);
91
ensureSortFields();
92
93
}
94
VideoMetadataImp(const VideoMetadataImp &other)
95
{
96
*this = other;
97
98
}
99
VideoMetadataImp &operator=(const VideoMetadataImp &rhs)
100
{
101
102
103
if (this != &rhs)
{
m_title = rhs.m_title;
104
m_sortTitle = rhs.m_sortTitle;
105
m_subtitle = rhs.m_subtitle;
106
m_sortSubtitle = rhs.m_sortSubtitle;
107
m_tagline = rhs.m_tagline;
108
m_inetref = rhs.m_inetref;
109
m_collectionref = rhs.m_collectionref;
110
m_homepage = rhs.m_homepage;
111
m_director = rhs.m_director;
112
m_studio = rhs.m_studio;
113
114
115
116
117
118
119
120
m_plot = rhs.m_plot;
m_rating = rhs.m_rating;
m_playcommand = rhs.m_playcommand;
m_category = rhs.m_category;
m_genres = rhs.m_genres;
m_countries = rhs.m_countries;
m_cast = rhs.m_cast;
m_filename = rhs.m_filename;
121
m_sortFilename = rhs.m_sortFilename;
122
m_hash = rhs.m_hash;
123
m_trailer = rhs.m_trailer;
124
m_coverfile = rhs.m_coverfile;
125
126
127
m_screenshot = rhs.m_screenshot;
m_banner = rhs.m_banner;
m_fanart = rhs.m_fanart;
128
129
130
131
m_categoryID = rhs.m_categoryID;
m_childID = rhs.m_childID;
m_year = rhs.m_year;
132
m_releasedate = rhs.m_releasedate;
133
m_length = rhs.m_length;
134
m_playcount = rhs.m_playcount;
135
136
m_season = rhs.m_season;
m_episode = rhs.m_episode;
137
m_insertdate = rhs.m_insertdate;
138
139
m_showlevel = rhs.m_showlevel;
m_browse = rhs.m_browse;
140
m_watched = rhs.m_watched;
141
142
m_id = rhs.m_id;
m_userrating = rhs.m_userrating;
143
m_host = rhs.m_host;
144
m_processed = rhs.m_processed;
145
m_contenttype = rhs.m_contenttype;
146
147
148
// No DB vars
m_prefix = rhs.m_prefix;
149
150
ensureSortFields();
151
}
152
153
154
155
return *this;
}
156
void ensureSortFields(void)
157
{
158
159
160
161
162
163
164
std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
if (m_sortTitle.isEmpty() and not m_title.isEmpty())
m_sortTitle = sh->doTitle(m_title);
if (m_sortSubtitle.isEmpty() and not m_subtitle.isEmpty())
m_sortSubtitle = sh->doTitle(m_subtitle);
if (m_sortFilename.isEmpty() and not m_filename.isEmpty())
m_sortFilename = sh->doPathname(m_filename);
165
166
}
167
public:
168
169
const QString &GetPrefix() const { return m_prefix; }
void SetPrefix(const QString &prefix) { m_prefix = prefix; }
170
171
const QString &getTitle() const { return m_title; }
172
173
const QString &getSortTitle() const { return m_sortTitle; }
void SetTitle(const QString& title, const QString& sortTitle = "")
174
175
{
m_title = title;
176
177
m_sortTitle = sortTitle;
ensureSortFields();
178
179
}
180
const QString &getSubtitle() const { return m_subtitle; }
181
182
183
184
185
186
const QString &getSortSubtitle() const { return m_sortSubtitle; }
void SetSubtitle(const QString &subtitle, const QString &sortSubtitle = "") {
m_subtitle = subtitle;
m_sortSubtitle = sortSubtitle;
ensureSortFields();
}
187
188
189
190
const QString &GetTagline() const { return m_tagline; }
void SetTagline(const QString &tagline) { m_tagline = tagline; }
191
192
const QString &GetInetRef() const { return m_inetref; }
void SetInetRef(const QString &inetRef) { m_inetref = inetRef; }
193
194
195
196
int GetCollectionRef() const { return m_collectionref; }
void SetCollectionRef(int collectionref) { m_collectionref = collectionref; }
197
198
199
const QString &GetHomepage() const { return m_homepage; }
void SetHomepage(const QString &homepage) { m_homepage = homepage; }
200
const QString &getDirector() const { return m_director; }
201
void SetDirector(const QString &director) { m_director = director; }
202
203
204
205
const QString &getStudio() const { return m_studio; }
void SetStudio(const QString &studio) { m_studio = studio; }
206
const QString &getPlot() const { return m_plot; }
207
void SetPlot(const QString &plot) { m_plot = plot; }
208
209
210
const QString &GetRating() const { return m_rating; }
void SetRating(const QString &rating) { m_rating = rating; }
211
212
const QString &getPlayCommand() const { return m_playcommand; }
213
void SetPlayCommand(const QString &playCommand)
214
215
216
217
{
m_playcommand = playCommand;
}
218
219
const QString &GetCategory() const { return m_category; }
// void SetCategory(const QString &category) { m_category = category; }
220
221
const genre_list &getGenres() const { return m_genres; }
222
void SetGenres(const genre_list &genres) { m_genres = genres; }
223
224
225
const country_list &GetCountries() const { return m_countries; }
void SetCountries(const country_list &countries)
226
227
228
229
{
m_countries = countries;
}
230
231
232
const cast_list &GetCast() const { return m_cast; }
void SetCast(const cast_list &cast) { m_cast = cast; }
233
234
const QString &GetHost() const { return m_host; }
void SetHost(const QString &host) { m_host = host; }
235
236
const QString &getFilename() const { return m_filename; }
237
238
239
240
241
242
243
244
245
const QString &getSortFilename() const { return m_sortFilename; }
void SetFilename(const QString &filename, const QString &sortFilename = "")
{
m_filename = filename;
m_sortFilename = sortFilename;
ensureSortFields();
}
bool sortBefore(const VideoMetadataImp *rhs) const;
246
247
248
249
const QString &GetHash() const { return m_hash; }
void SetHash(const QString &hash) { m_hash = hash; }
250
251
252
const QString &GetTrailer() const { return m_trailer; }
void SetTrailer(const QString &trailer) { m_trailer = trailer; }
253
254
const QString &GetCoverFile() const { return m_coverfile; }
void SetCoverFile(const QString &coverFile) { m_coverfile = coverFile; }
255
256
257
258
259
260
261
262
263
264
265
const QString &GetScreenshot() const { return m_screenshot; }
void SetScreenshot(const QString &screenshot) { m_screenshot = screenshot; }
const QString &GetBanner() const { return m_banner; }
void SetBanner(const QString &banner) { m_banner = banner; }
const QString &GetFanart() const { return m_fanart; }
void SetFanart(const QString &fanart) { m_fanart = fanart; }
int GetCategoryID() const
266
267
268
{
return m_categoryID;
}
269
void SetCategoryID(int id);
270
271
272
int GetChildID() const { return m_childID; }
void SetChildID(int childID) { m_childID = childID; }
273
274
int getYear() const { return m_year; }
275
void SetYear(int year) { m_year = year; }
276
277
QDate getReleaseDate() const { return m_releasedate; }
278
void SetReleaseDate(QDate releasedate) { m_releasedate = releasedate; }
279
280
281
std::chrono::minutes GetLength() const { return m_length; }
void SetLength(std::chrono::minutes length) { m_length = length; }
282
283
284
285
unsigned int GetPlayCount() const { return m_playcount; }
void SetPlayCount(int playcount) { m_playcount = playcount; }
286
287
288
289
290
291
int GetSeason() const { return m_season; }
void SetSeason(int season) { m_season = season; }
int GetEpisode() const { return m_episode; }
void SetEpisode(int episode) { m_episode = episode; }
292
293
294
QDate GetInsertdate() const { return m_insertdate;}
void SetInsertdate(QDate date) { m_insertdate = date;}
295
296
ParentalLevel::Level GetShowLevel() const { return m_showlevel; }
void SetShowLevel(ParentalLevel::Level showLevel)
297
298
299
{
m_showlevel = ParentalLevel(showLevel).GetLevel();
}
300
301
302
bool GetBrowse() const { return m_browse; }
void SetBrowse(bool browse) { m_browse = browse; }
303
304
305
306
bool GetWatched() const { return m_watched; }
void SetWatched(bool watched) { m_watched = watched; }
307
308
unsigned int GetID() const { return m_id; }
void SetID(int id) { m_id = id; }
309
310
311
float GetUserRating() const { return m_userrating; }
void SetUserRating(float userRating) { m_userrating = userRating; }
312
313
314
315
bool GetProcessed() const { return m_processed; }
void SetProcessed(bool processed) { m_processed = processed; }
316
317
318
VideoContentType GetContentType() const { return m_contenttype; }
void SetContentType(VideoContentType contenttype) { m_contenttype = contenttype; }
319
320
////////////////////////////////
321
322
323
void SaveToDatabase();
void UpdateDatabase();
bool DeleteFromDatabase();
324
325
bool DeleteFile();
326
327
328
void Reset();
329
330
bool IsHostSet() const;
331
void GetImageMap(InfoMap &imageMap) const;
332
QString GetImage(const QString &name) const;
333
334
335
336
337
private:
void fillCountries();
void updateCountries();
void fillGenres();
338
void fillCast();
339
void updateGenres();
340
void updateCast();
341
342
343
344
345
bool removeDir(const QString &dirName);
void fromDBRow(MSqlQuery &query);
void saveToDatabase();
private:
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
QString m_title;
QString m_sortTitle;
QString m_subtitle;
QString m_sortSubtitle;
QString m_tagline;
QString m_inetref;
int m_collectionref {0};
QString m_homepage;
QString m_director;
QString m_studio;
QString m_plot;
QString m_rating;
QString m_playcommand;
QString m_category;
genre_list m_genres;
country_list m_countries;
cast_list m_cast;
QString m_filename;
QString m_sortFilename;
QString m_hash;
QString m_trailer;
QString m_coverfile;
QString m_screenshot;
QString m_banner;
QString m_fanart;
QString m_host;
int m_categoryID {0};
int m_childID {-1};
int m_year {VIDEO_YEAR_DEFAULT};
QDate m_releasedate;
377
std::chrono::minutes m_length {0min};
378
379
380
381
382
383
384
385
386
387
388
int m_playcount {0};
int m_season {0};
int m_episode {0};
QDate m_insertdate;
ParentalLevel::Level m_showlevel {ParentalLevel::plNone};
bool m_browse {true};
bool m_watched {false};
unsigned int m_id {0}; // videometadata.intid
float m_userrating {0.0};
bool m_processed {false};
VideoContentType m_contenttype {kContentUnknown};
389
390
// not in DB
391
QString m_prefix;
392
393
394
395
396
};
/////////////////////////////
/////////
/////////////////////////////
397
398
399
400
401
/** \fn VideoMetadataImp::sortBefore(const VideoMetadataImp *)
* \brief Returns true if the object should appear before the argument.
*/
bool VideoMetadataImp::sortBefore(const VideoMetadataImp *rhs) const
{
402
403
404
405
406
407
int cmp = StringUtil::naturalCompare(m_sortTitle, rhs->m_sortTitle);
if (cmp == 0)
cmp = StringUtil::naturalCompare(m_sortFilename, rhs->m_sortFilename);
if (cmp == 0)
cmp = ternary_compare(m_id, rhs->m_id);
return cmp < 0;
408
409
}
410
bool VideoMetadataImp::removeDir(const QString &dirName)
411
{
412
QDir d(dirName);
413
414
d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
415
QFileInfoList contents = d.entryInfoList();
416
if (contents.empty())
417
{
418
return d.rmdir(dirName);
419
}
420
421
for (const auto& entry : std::as_const(contents))
422
{
423
if (entry.isDir())
424
{
425
QString fileName = entry.fileName();
426
427
if (!removeDir(fileName))
return false;
428
429
430
}
else
{
431
if (!QFile(entry.fileName()).remove())
432
return false;
433
434
}
}
435
return d.rmdir(dirName);
436
437
}
438
/// Deletes the file associated with a metadata entry
439
bool VideoMetadataImp::DeleteFile()
440
{
441
bool isremoved = false;
442
443
if (!m_host.isEmpty())
444
{
445
QString url = generate_file_url("Videos", m_host, m_filename);
446
isremoved = RemoteFile::DeleteFile(url);
447
448
449
}
else
{
450
451
452
453
454
455
456
457
458
QFileInfo fi(m_filename);
if (fi.isDir())
{
isremoved = removeDir(m_filename);
}
else
{
isremoved = QFile::remove(m_filename);
}
459
}
460
461
if (!isremoved)
462
{
463
464
LOG(VB_GENERAL, LOG_DEBUG, QString("Could not delete file: %1")
.arg(m_filename));
465
}
466
467
return isremoved;
468
469
}
470
void VideoMetadataImp::Reset()
471
{
472
473
VideoMetadataImp tmp(m_filename, QString(),
VideoMetadata::VideoFileHash(m_filename, m_host), VIDEO_TRAILER_DEFAULT,
474
VIDEO_COVERFILE_DEFAULT, VIDEO_SCREENSHOT_DEFAULT, VIDEO_BANNER_DEFAULT,
475
476
VIDEO_FANART_DEFAULT, QString(), QString(), QString(), QString(),
QString(), VIDEO_YEAR_DEFAULT,
477
QDate(), VIDEO_INETREF_DEFAULT, -1, QString(), VIDEO_DIRECTOR_DEFAULT,
478
QString(), VIDEO_PLOT_DEFAULT, 0.0,
479
VIDEO_RATING_DEFAULT, 0, 0,
480
0, 0, QDate(), m_id,
481
ParentalLevel::plLowest, 0, -1, true, false, "", "",
482
483
VideoMetadata::genre_list(), VideoMetadata::country_list(),
VideoMetadata::cast_list(), m_host, false);
484
485
486
487
488
tmp.m_prefix = m_prefix;
*this = tmp;
}
489
bool VideoMetadataImp::IsHostSet() const
490
{
491
return !m_host.isEmpty();
492
493
}
494
void VideoMetadataImp::fillGenres()
495
{
496
497
498
499
500
501
m_genres.clear();
VideoGenreMap &vgm = VideoGenreMap::getGenreMap();
VideoGenreMap::entry genres;
if (vgm.get(m_id, genres))
{
VideoGenre &vg = VideoGenre::getGenre();
502
for (long value : genres.values)
503
{
504
505
// Just add empty string for no-name genres
QString name;
506
vg.get(value, name);
507
m_genres.emplace_back(value, name);
508
509
}
}
510
511
}
512
void VideoMetadataImp::fillCountries()
513
{
514
515
516
517
518
519
m_countries.clear();
VideoCountryMap &vcm = VideoCountryMap::getCountryMap();
VideoCountryMap::entry countries;
if (vcm.get(m_id, countries))
{
VideoCountry &vc = VideoCountry::getCountry();
520
for (long value : countries.values)
521
{
522
523
// Just add empty string for no-name countries
QString name;
524
vc.get(value, name);
525
m_countries.emplace_back(value, name);
526
527
}
}
528
}
529
530
void VideoMetadataImp::fillCast()
531
532
533
534
535
536
{
m_cast.clear();
VideoCastMap &vcm = VideoCastMap::getCastMap();
VideoCastMap::entry cast;
if (vcm.get(m_id, cast))
{
537
VideoCast &vc = VideoCast::GetCast();
538
for (long value : cast.values)
539
540
541
{
// Just add empty string for no-name cast
QString name;
542
vc.get(value, name);
543
m_cast.emplace_back(value, name);
544
545
546
547
}
}
}
548
/// Sets metadata from a DB row
549
550
551
///
/// Query string in VideoMetadataListManager::loadAllFromDatabase
///
552
void VideoMetadataImp::fromDBRow(MSqlQuery &query)
553
{
554
555
m_title = query.value(0).toString();
m_director = query.value(1).toString();
556
557
558
559
560
561
m_studio = query.value(2).toString();
m_plot = query.value(3).toString();
m_rating = query.value(4).toString();
m_year = query.value(5).toInt();
m_releasedate = query.value(6).toDate();
m_userrating = (float)query.value(7).toDouble();
562
if (std::isnan(m_userrating) || m_userrating < 0)
563
m_userrating = 0.0;
564
565
if (m_userrating > 10.0F)
m_userrating = 10.0F;
566
m_length = std::chrono::minutes(query.value(8).toInt());
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
m_playcount = query.value(9).toInt();
m_filename = query.value(10).toString();
m_hash = query.value(11).toString();
m_showlevel = ParentalLevel(query.value(12).toInt()).GetLevel();
m_coverfile = query.value(13).toString();
m_inetref = query.value(14).toString();
m_collectionref = query.value(15).toUInt();
m_homepage = query.value(16).toString();
m_childID = query.value(17).toUInt();
m_browse = query.value(18).toBool();
m_watched = query.value(19).toBool();
m_playcommand = query.value(20).toString();
m_categoryID = query.value(21).toInt();
m_id = query.value(22).toInt();
m_trailer = query.value(23).toString();
m_screenshot = query.value(24).toString();
m_banner = query.value(25).toString();
m_fanart = query.value(26).toString();
m_subtitle = query.value(27).toString();
m_tagline = query.value(28).toString();
m_season = query.value(29).toInt();
m_episode = query.value(30).toInt();
m_host = query.value(31).toString();
m_insertdate = query.value(32).toDate();
m_processed = query.value(33).toBool();
m_contenttype = ContentTypeFromString(query.value(34).toString());
594
595
596
ensureSortFields();
597
VideoCategory::GetCategory().get(m_categoryID, m_category);
598
599
600
601
602
603
// Genres
fillGenres();
//Countries
fillCountries();
604
605
606
// Cast
fillCast();
607
608
}
609
void VideoMetadataImp::saveToDatabase()
610
{
611
if (m_title.isEmpty())
612
m_title = VideoMetadata::FilenameToMeta(m_filename, 1);
613
if (m_hash.isEmpty())
614
m_hash = VideoMetadata::VideoFileHash(m_filename, m_host);
615
if (m_subtitle.isEmpty())
616
m_subtitle = VideoMetadata::FilenameToMeta(m_filename, 4);
617
if (m_director.isEmpty())
618
m_director = VIDEO_DIRECTOR_UNKNOWN;
619
if (m_plot.isEmpty())
620
m_plot = VIDEO_PLOT_DEFAULT;
621
if (m_rating.isEmpty())
622
m_rating = VIDEO_RATING_DEFAULT;
623
ensureSortFields();
624
625
626
627
628
629
630
631
632
InfoMap metadataMap;
GetImageMap(metadataMap);
QString coverfile = metadataMap["coverfile"];
QString screenshot = metadataMap["screenshotfile"];
QString bannerfile = metadataMap["bannerfile"];
QString fanartfile = metadataMap["fanartfile"];
if (coverfile.isEmpty() || !RemoteFile::Exists(coverfile))
633
m_coverfile = VIDEO_COVERFILE_DEFAULT;
634
if (screenshot.isEmpty() || !RemoteFile::Exists(screenshot))
635
m_screenshot = VIDEO_SCREENSHOT_DEFAULT;
636
if (bannerfile.isEmpty() || !RemoteFile::Exists(bannerfile))
637
m_banner = VIDEO_BANNER_DEFAULT;
638
if (fanartfile.isEmpty() || !RemoteFile::Exists(fanartfile))
639
m_fanart = VIDEO_FANART_DEFAULT;
640
641
if (m_trailer.isEmpty())
m_trailer = VIDEO_TRAILER_DEFAULT;
642
if (m_inetref.isEmpty())
643
m_inetref = VIDEO_INETREF_DEFAULT;
644
if (std::isnan(m_userrating))
645
m_userrating = 0.0;
646
if (m_userrating < -10.0F || m_userrating > 10.0F)
647
m_userrating = 0.0;
648
649
if (m_releasedate.toString().isEmpty())
m_releasedate = QDate::fromString("0000-00-00", "YYYY-MM-DD");
650
651
652
653
654
655
656
if (m_contenttype == kContentUnknown)
{
if (m_season > 0 || m_episode > 0)
m_contenttype = kContentTelevision;
else
m_contenttype = kContentMovie;
}
657
658
bool inserting = m_id == 0;
659
660
MSqlQuery query(MSqlQuery::InitCon());
661
662
if (inserting)
663
{
664
m_browse = true;
665
666
m_watched = false;
667
668
query.prepare("INSERT INTO videometadata (title,subtitle,tagline,director,studio,plot,"
669
"rating,year,userrating,length,season,episode,filename,hash,"
670
"showlevel,coverfile,inetref,homepage,browse,watched,trailer,"
671
"screenshot,banner,fanart,host,processed,contenttype) VALUES (:TITLE, :SUBTITLE, "
672
":TAGLINE, :DIRECTOR, :STUDIO, :PLOT, :RATING, :YEAR, :USERRATING, "
673
674
":LENGTH, :SEASON, :EPISODE, :FILENAME, :HASH, :SHOWLEVEL, "
":COVERFILE, :INETREF, :HOMEPAGE, :BROWSE, :WATCHED, "
675
":TRAILER, :SCREENSHOT, :BANNER, :FANART, :HOST, :PROCESSED, :CONTENTTYPE)");
676
}
677
else
678
{
679
query.prepare("UPDATE videometadata SET title = :TITLE, subtitle = :SUBTITLE, "
680
681
682
"tagline = :TAGLINE, director = :DIRECTOR, studio = :STUDIO, "
"plot = :PLOT, rating= :RATING, year = :YEAR, "
"releasedate = :RELEASEDATE, userrating = :USERRATING, "
683
684
"length = :LENGTH, playcount = :PLAYCOUNT, season = :SEASON, "
"episode = :EPISODE, filename = :FILENAME, hash = :HASH, trailer = :TRAILER, "
685
"showlevel = :SHOWLEVEL, coverfile = :COVERFILE, "
686
"screenshot = :SCREENSHOT, banner = :BANNER, fanart = :FANART, "
687
688
689
690
"inetref = :INETREF, collectionref = :COLLECTION, homepage = :HOMEPAGE, "
"browse = :BROWSE, watched = :WATCHED, host = :HOST, playcommand = :PLAYCOMMAND, "
"childid = :CHILDID, category = :CATEGORY, processed = :PROCESSED, "
"contenttype = :CONTENTTYPE WHERE intid = :INTID");
691
692
query.bindValue(":PLAYCOMMAND", m_playcommand);
693
694
695
query.bindValue(":CHILDID", m_childID);
query.bindValue(":CATEGORY", m_categoryID);
query.bindValue(":INTID", m_id);
696
697
}
698
699
query.bindValueNoNull(":TITLE", m_title);
query.bindValueNoNull(":SUBTITLE", m_subtitle);
700
query.bindValue(":TAGLINE", m_tagline);
701
query.bindValueNoNull(":DIRECTOR", m_director);
702
query.bindValue(":STUDIO", m_studio);
703
query.bindValue(":PLOT", m_plot);
704
query.bindValueNoNull(":RATING", m_rating);
705
query.bindValue(":YEAR", m_year);
706
query.bindValue(":RELEASEDATE", m_releasedate);
707
query.bindValue(":USERRATING", m_userrating);
708
query.bindValue(":LENGTH", static_cast<qint64>(m_length.count()));
709
query.bindValue(":PLAYCOUNT", m_playcount);
710
711
query.bindValue(":SEASON", m_season);
query.bindValue(":EPISODE", m_episode);
712
query.bindValue(":FILENAME", m_filename);
713
query.bindValue(":HASH", m_hash);
714
query.bindValueNoNull(":TRAILER", m_trailer);
715
query.bindValue(":SHOWLEVEL", m_showlevel);
716
717
718
719
720
query.bindValueNoNull(":COVERFILE", m_coverfile);
query.bindValueNoNull(":SCREENSHOT", m_screenshot);
query.bindValueNoNull(":BANNER", m_banner);
query.bindValueNoNull(":FANART", m_fanart);
query.bindValueNoNull(":INETREF", m_inetref);
721
query.bindValue(":COLLECTION", m_collectionref);
722
query.bindValueNoNull(":HOMEPAGE", m_homepage);
723
query.bindValue(":BROWSE", m_browse);
724
query.bindValue(":WATCHED", m_watched);
725
query.bindValue(":HOST", m_host);
726
query.bindValue(":PROCESSED", m_processed);
727
query.bindValue(":CONTENTTYPE", ContentTypeToString(m_contenttype));
728
729
if (!query.exec() || !query.isActive())
730
{
731
MythDB::DBError("video metadata update", query);
732
733
734
return;
}
735
if (inserting)
736
{
737
738
// Must make sure we have 'id' filled before we call updateGenres or
// updateCountries
739
740
if (!query.exec("SELECT LAST_INSERT_ID()") || !query.next())
741
{
742
MythDB::DBError("metadata id get", query);
743
744
return;
}
745
746
747
748
749
m_id = query.value(0).toUInt();
if (0 == m_id)
{
750
751
752
LOG(VB_GENERAL, LOG_ERR,
QString("%1: The id of the last inserted row to "
"videometadata seems to be 0. This is odd.")
753
754
755
.arg(__FILE__));
return;
}
756
}
757
758
759
updateGenres();
updateCountries();
760
updateCast();
761
762
}
763
void VideoMetadataImp::SaveToDatabase()
764
{
765
saveToDatabase();
766
767
}
768
void VideoMetadataImp::UpdateDatabase()
769
{
770
771
saveToDatabase();
}
772
773
bool VideoMetadataImp::DeleteFromDatabase()
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
{
VideoGenreMap::getGenreMap().remove(m_id);
VideoCountryMap::getCountryMap().remove(m_id);
VideoCastMap::getCastMap().remove(m_id);
MSqlQuery query(MSqlQuery::InitCon());
query.prepare("DELETE FROM videometadata WHERE intid = :ID");
query.bindValue(":ID", m_id);
if (!query.exec())
{
MythDB::DBError("delete from videometadata", query);
}
query.prepare("DELETE FROM filemarkup WHERE filename = :FILENAME");
query.bindValue(":FILENAME", m_filename);
if (!query.exec())
{
MythDB::DBError("delete from filemarkup", query);
}
return true;
}
797
void VideoMetadataImp::SetCategoryID(int id)
798
799
800
801
802
803
804
805
806
{
if (id == 0)
{
m_category = "";
m_categoryID = id;
}
else
{
if (m_categoryID != id)
807
{
808
QString cat;
809
if (VideoCategory::GetCategory().get(id, cat))
810
{
811
812
m_category = cat;
m_categoryID = id;
813
}
814
else
815
{
816
LOG(VB_GENERAL, LOG_ERR, "Unknown category id");
817
818
819
}
}
}
820
821
}
822
void VideoMetadataImp::updateGenres()
823
{
824
VideoGenreMap::getGenreMap().remove(m_id);
825
826
// ensure that all genres we have are in the DB
827
auto genre = m_genres.begin();
828
while (genre != m_genres.end())
829
{
830
if (!genre->second.trimmed().isEmpty())
831
832
833
834
835
836
837
838
839
{
genre->first = VideoGenre::getGenre().add(genre->second);
VideoGenreMap::getGenreMap().add(m_id, genre->first);
++genre;
}
else
{
genre = m_genres.erase(genre);
}
840
}
841
842
}
843
void VideoMetadataImp::updateCountries()
844
845
846
{
// remove countries for this video
VideoCountryMap::getCountryMap().remove(m_id);
847
848
auto country = m_countries.begin();
849
while (country != m_countries.end())
850
{
851
if (!country->second.trimmed().isEmpty())
852
853
854
855
856
857
858
859
860
{
country->first = VideoCountry::getCountry().add(country->second);
VideoCountryMap::getCountryMap().add(m_id, country->first);
++country;
}
else
{
country = m_countries.erase(country);
}
861
862
}
}
863
864
void VideoMetadataImp::updateCast()
865
866
867
868
{
VideoCastMap::getCastMap().remove(m_id);
// ensure that all cast we have are in the DB
869
auto cast = m_cast.begin();
870
871
while (cast != m_cast.end())
{
872
if (!cast->second.trimmed().isEmpty())
873
{
874
cast->first = VideoCast::GetCast().add(cast->second);
875
876
877
878
879
880
881
882
883
884
VideoCastMap::getCastMap().add(m_id, cast->first);
++cast;
}
else
{
cast = m_cast.erase(cast);
}
}
}
885
886
887
888
void VideoMetadataImp::GetImageMap(InfoMap &imageMap) const
{
QString coverfile;
if (IsHostSet()
889
&& !GetCoverFile().startsWith(u'/')
890
891
892
&& !GetCoverFile().isEmpty()
&& !IsDefaultCoverFile(GetCoverFile()))
{
893
coverfile = generate_file_url(QStringLiteral(u"Coverart"), GetHost(),
894
895
896
897
898
899
900
GetCoverFile());
}
else
{
coverfile = GetCoverFile();
}
901
902
imageMap[QStringLiteral(u"coverfile")] = coverfile;
imageMap[QStringLiteral(u"coverart")] = coverfile;
903
904
QString screenshotfile;
905
if (IsHostSet() && !GetScreenshot().startsWith(u'/')
906
907
&& !GetScreenshot().isEmpty())
{
908
screenshotfile = generate_file_url(QStringLiteral(u"Screenshots"),
909
910
911
912
913
914
915
GetHost(), GetScreenshot());
}
else
{
screenshotfile = GetScreenshot();
}
916
917
imageMap[QStringLiteral(u"screenshotfile")] = screenshotfile;
imageMap[QStringLiteral(u"screenshot")] = screenshotfile;
918
919
QString bannerfile;
920
if (IsHostSet() && !GetBanner().startsWith(u'/')
921
922
&& !GetBanner().isEmpty())
{
923
bannerfile = generate_file_url(QStringLiteral(u"Banners"), GetHost(),
924
925
926
927
928
929
930
GetBanner());
}
else
{
bannerfile = GetBanner();
}
931
932
imageMap[QStringLiteral(u"bannerfile")] = bannerfile;
imageMap[QStringLiteral(u"banner")] = bannerfile;
933
934
QString fanartfile;
935
if (IsHostSet() && !GetFanart().startsWith('/')
936
937
&& !GetFanart().isEmpty())
{
938
fanartfile = generate_file_url(QStringLiteral(u"Fanart"), GetHost(),
939
940
941
942
943
944
945
GetFanart());
}
else
{
fanartfile = GetFanart();
}
946
947
imageMap[QStringLiteral(u"fanartfile")] = fanartfile;
imageMap[QStringLiteral(u"fanart")] = fanartfile;
948
949
950
951
QString smartimage = coverfile;
if (!screenshotfile.isEmpty () && (GetSeason() > 0 || GetEpisode() > 0))
smartimage = screenshotfile;
952
imageMap[QStringLiteral(u"smartimage")] = smartimage;
953
954
}
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// This should be the equivalent of GetImageMap, only the image names
// are computed one at a time as needed.
QString VideoMetadataImp::GetImage(const QString& name) const
{
if ((name == QStringLiteral(u"coverfile")) ||
(name == QStringLiteral(u"coverart")))
{
QString coverfile = GetCoverFile();
if (IsHostSet()
&& !coverfile.startsWith(u'/')
&& !coverfile.isEmpty()
&& !IsDefaultCoverFile(coverfile))
return generate_file_url(QStringLiteral(u"Coverart"), GetHost(),
coverfile);
return coverfile;
}
if ((name == QStringLiteral(u"screenshotfile")) ||
(name == QStringLiteral(u"screenshot")))
{
QString screenshot = GetScreenshot();
if (IsHostSet() && !screenshot.startsWith(u'/')
&& !screenshot.isEmpty())
return generate_file_url(QStringLiteral(u"Screenshots"),
GetHost(), screenshot);
return screenshot;
}
if ((name == QStringLiteral(u"bannerfile")) ||
(name == QStringLiteral(u"banner")))
{
QString bannerfile = GetBanner();
if (IsHostSet() && !bannerfile.startsWith(u'/')
&& !bannerfile.isEmpty())
return generate_file_url(QStringLiteral(u"Banners"), GetHost(),
bannerfile);
return bannerfile;
}
if ((name == QStringLiteral(u"fanartfile")) ||
(name == QStringLiteral(u"fanart")))
{
QString fanartfile = GetFanart();
if (IsHostSet() && !fanartfile.startsWith('/')
&& !fanartfile.isEmpty())
return generate_file_url(QStringLiteral(u"Fanart"), GetHost(),