33#define LOC QString("ProgramInfo(%1): ").arg(GetBasename())
48#define DEFINE_FLAGS_NAMES
50#undef DEFINE_FLAGS_NAMES
53 "SELECT r.title, r.subtitle, r.description, "
54 " r.season, r.episode, r.category, "
55 " r.chanid, c.channum, c.callsign, "
56 " c.name, c.outputfilters,r.recgroup, "
57 " r.playgroup, r.storagegroup, r.basename, "
58 " r.hostname, r.recpriority, r.seriesid, "
59 " r.programid, r.inetref, r.filesize, "
60 " r.progstart, r.progend, r.stars, "
61 " r.starttime, r.endtime, p.airdate+0, "
62 " r.originalairdate, r.lastmodified, r.recordid, "
63 " c.commmethod, r.commflagged, r.previouslyshown, "
64 " r.transcoder, r.transcoded, r.deletepending, "
65 " r.preserve, r.cutlist, r.autoexpire, "
66 " r.editing, r.bookmark, r.watched, "
67 " p.audioprop+0, p.videoprop+0, p.subtitletypes+0, "
68 " r.findid, rec.dupin, rec.dupmethod, "
69 " p.syndicatedepisodenumber, p.partnumber, p.parttotal, "
70 " p.season, p.episode, p.totalepisodes, "
71 " p.category_type, r.recordedid, r.inputname, "
72 " r.bookmarkupdate, r.lastplay "
74 "LEFT JOIN channel AS c "
75 "ON (r.chanid = c.chanid) "
76 "LEFT JOIN recordedprogram AS p "
77 "ON (r.chanid = p.chanid AND "
78 " r.progstart = p.starttime) "
79 "LEFT JOIN record AS rec "
80 "ON (r.recordid = rec.recordid) ";
82static void set_flag(uint32_t &flags,
int flag_to_set,
bool is_set)
84 flags &= ~flag_to_set;
93 if (!url.startsWith(
"dvd:") && !url.startsWith(
"bd:"))
95 if(url.endsWith(
".img", Qt::CaseInsensitive) ||
96 url.endsWith(
".iso", Qt::CaseInsensitive))
101 result =
"bd:" + url;
105 result =
"dvd:" + url;
115 if (QDir(url +
"/BDMV").
exists())
116 result =
"bd:" + url;
117 else if (QDir(url +
"/VIDEO_TS").
exists())
118 result =
"dvd:" + url;
125static const std::array<const QString,ProgramInfo::kNumCatTypes>
kCatName
126{
"",
"movie",
"series",
"sports",
"tvshow" };
139 for (
size_t i = 1; i <
kCatName.size(); i++)
149 m_title(other.m_title),
150 m_sortTitle(other.m_sortTitle),
151 m_subtitle(other.m_subtitle),
152 m_sortSubtitle(other.m_sortSubtitle),
153 m_description(other.m_description),
154 m_season(other.m_season),
155 m_episode(other.m_episode),
156 m_totalEpisodes(other.m_totalEpisodes),
157 m_syndicatedEpisode(other.m_syndicatedEpisode),
158 m_category(other.m_category),
159 m_director(other.m_director),
161 m_recPriority(other.m_recPriority),
163 m_chanId(other.m_chanId),
164 m_chanStr(other.m_chanStr),
165 m_chanSign(other.m_chanSign),
166 m_chanName(other.m_chanName),
167 m_chanPlaybackFilters(other.m_chanPlaybackFilters),
169 m_recGroup(other.m_recGroup),
170 m_playGroup(other.m_playGroup),
172 m_pathname(other.m_pathname),
174 m_hostname(other.m_hostname),
175 m_storageGroup(other.m_storageGroup),
177 m_seriesId(other.m_seriesId),
178 m_programId(other.m_programId),
179 m_inetRef(other.m_inetRef),
180 m_catType(other.m_catType),
182 m_fileSize(other.m_fileSize),
184 m_startTs(other.m_startTs),
185 m_endTs(other.m_endTs),
186 m_recStartTs(other.m_recStartTs),
187 m_recEndTs(other.m_recEndTs),
189 m_stars(other.m_stars),
191 m_originalAirDate(other.m_originalAirDate),
192 m_lastModified(other.m_lastModified),
195 m_recPriority2(other.m_recPriority2),
196 m_recordId(other.m_recordId),
197 m_parentId(other.m_parentId),
199 m_sourceId(other.m_sourceId),
200 m_inputId(other.m_inputId),
202 m_findId(other.m_findId),
203 m_programFlags(other.m_programFlags),
204 m_videoProperties(other.m_videoProperties),
205 m_audioProperties(other.m_audioProperties),
206 m_subtitleProperties(other.m_subtitleProperties),
207 m_year(other.m_year),
208 m_partNumber(other.m_partNumber),
209 m_partTotal(other.m_partTotal),
211 m_recStatus(other.m_recStatus),
212 m_recType(other.m_recType),
213 m_dupIn(other.m_dupIn),
214 m_dupMethod(other.m_dupMethod),
216 m_recordedId(other.m_recordedId),
217 m_inputName(other.m_inputName),
218 m_bookmarkUpdate(other.m_bookmarkUpdate),
221 m_availableStatus(other.m_availableStatus),
222 m_spread(other.m_spread),
223 m_startCol(other.m_startCol),
226 m_positionMapDBReplacement(other.m_positionMapDBReplacement)
240 "SELECT chanid, starttime "
242 "WHERE recordedid = :RECORDEDID");
243 query.
bindValue(
":RECORDEDID", _recordedid);
253 LOG(VB_GENERAL, LOG_CRIT,
LOC +
254 QString(
"Failed to find recorded entry for %1.")
281 QString _sortSubtitle,
282 QString _description,
286 QString _syndicatedepisode,
293 QString _chanplaybackfilters,
298 const QString &_pathname,
301 QString _storagegroup,
314 QDateTime _recstartts,
322 QDate _originalAirDate,
323 QDateTime _lastmodified,
335 uint _audioproperties,
336 uint _videoproperties,
339 QDateTime _bookmarkupdate) :
340 m_title(
std::move(_title)),
341 m_sortTitle(
std::move(_sortTitle)),
342 m_subtitle(
std::move(_subtitle)),
343 m_sortSubtitle(
std::move(_sortSubtitle)),
344 m_description(
std::move(_description)),
347 m_totalEpisodes(_totalepisodes),
348 m_syndicatedEpisode(
std::move(_syndicatedepisode)),
349 m_category(
std::move(_category)),
351 m_recPriority(_recpriority),
354 m_chanStr(
std::move(_channum)),
355 m_chanSign(
std::move(_chansign)),
356 m_chanName(
std::move(_channame)),
357 m_chanPlaybackFilters(
std::move(_chanplaybackfilters)),
359 m_recGroup(
std::move(_recgroup)),
360 m_playGroup(
std::move(_playgroup)),
362 m_pathname(_pathname),
364 m_hostname(
std::move(_hostname)),
365 m_storageGroup(
std::move(_storagegroup)),
367 m_seriesId(
std::move(_seriesid)),
368 m_programId(
std::move(_programid)),
369 m_inetRef(
std::move(_inetref)),
372 m_fileSize(_filesize),
374 m_startTs(
std::move(_startts)),
375 m_endTs(
std::move(_endts)),
376 m_recStartTs(
std::move(_recstartts)),
377 m_recEndTs(
std::move(_recendts)),
379 m_stars(
std::
clamp(_stars, 0.0F, 1.0F)),
381 m_originalAirDate(_originalAirDate),
382 m_lastModified(
std::move(_lastmodified)),
385 m_recordId(_recordid),
388 m_programFlags(_programflags),
389 m_videoProperties(_videoproperties),
390 m_audioProperties(_audioproperties),
391 m_subtitleProperties(_subtitleType),
393 m_partNumber(_partnumber),
394 m_partTotal(_parttotal),
396 m_recStatus(_recstatus),
398 m_dupMethod(_dupmethod),
400 m_recordedId(_recordedid),
401 m_inputName(
std::move(_inputname)),
402 m_bookmarkUpdate(
std::move(_bookmarkupdate))
418 QString _sortSubtitle,
419 QString _description,
435 QDateTime _recstartts,
447 m_title(
std::move(_title)),
448 m_sortTitle(
std::move(_sortTitle)),
449 m_subtitle(
std::move(_subtitle)),
450 m_sortSubtitle(
std::move(_sortSubtitle)),
451 m_description(
std::move(_description)),
454 m_category(
std::move(_category)),
457 m_chanStr(
std::move(_channum)),
458 m_chanSign(
std::move(_chansign)),
459 m_chanName(
std::move(_channame)),
461 m_seriesId(
std::move(_seriesid)),
462 m_programId(
std::move(_programid)),
463 m_inetRef(
std::move(_inetref)),
465 m_startTs(
std::move(_startts)),
466 m_endTs(
std::move(_endts)),
467 m_recStartTs(
std::move(_recstartts)),
468 m_recEndTs(
std::move(_recendts)),
470 m_lastModified(m_startTs),
473 m_recordId(_recordid),
476 m_programFlags((duplicate) ? FL_DUPLICATE : FL_NONE),
478 m_recStatus(_recstatus),
493 QString _sortSubtitle,
494 QString _description,
495 QString _syndicatedepisode,
502 QString _chanplaybackfilters,
506 QDateTime _recstartts,
518 QDate _originalAirDate,
527 uint _videoproperties,
528 uint _audioproperties,
536 m_title(
std::move(_title)),
537 m_sortTitle(
std::move(_sortTitle)),
538 m_subtitle(
std::move(_subtitle)),
539 m_sortSubtitle(
std::move(_sortSubtitle)),
540 m_description(
std::move(_description)),
543 m_totalEpisodes(_totalepisodes),
544 m_syndicatedEpisode(
std::move(_syndicatedepisode)),
545 m_category(
std::move(_category)),
548 m_chanStr(
std::move(_channum)),
549 m_chanSign(
std::move(_chansign)),
550 m_chanName(
std::move(_channame)),
551 m_chanPlaybackFilters(
std::move(_chanplaybackfilters)),
553 m_seriesId(
std::move(_seriesid)),
554 m_programId(
std::move(_programid)),
557 m_startTs(
std::move(_startts)),
558 m_endTs(
std::move(_endts)),
559 m_recStartTs(
std::move(_recstartts)),
560 m_recEndTs(
std::move(_recendts)),
562 m_stars(
std::
clamp(_stars, 0.0F, 1.0F)),
564 m_originalAirDate(_originalAirDate),
565 m_lastModified(m_startTs),
566 m_lastInUseTime(m_startTs.addSecs(-kLastInUseOffset)),
568 m_recordId(_recordid),
571 m_videoProperties(_videoproperties),
572 m_audioProperties(_audioproperties),
573 m_subtitleProperties(_subtitleType),
575 m_partNumber(_partnumber),
576 m_partTotal(_parttotal),
578 m_recStatus(_recstatus),
587 for (
auto *it : schedList)
637 QString _sortSubtitle,
638 QString _description,
648 QString _chanplaybackfilters,
655 QDateTime _recstartts,
661 QString _inputname) :
662 m_title(
std::move(_title)),
663 m_sortTitle(
std::move(_sortTitle)),
664 m_subtitle(
std::move(_subtitle)),
665 m_sortSubtitle(
std::move(_sortSubtitle)),
666 m_description(
std::move(_description)),
669 m_totalEpisodes(_totalepisodes),
670 m_category(
std::move(_category)),
673 m_chanStr(
std::move(_channum)),
674 m_chanSign(
std::move(_chansign)),
675 m_chanName(
std::move(_channame)),
676 m_chanPlaybackFilters(
std::move(_chanplaybackfilters)),
678 m_recGroup(
std::move(_recgroup)),
679 m_playGroup(
std::move(_playgroup)),
681 m_seriesId(
std::move(_seriesid)),
682 m_programId(
std::move(_programid)),
683 m_inetRef(
std::move(_inetref)),
685 m_startTs(
std::move(_startts)),
686 m_endTs(
std::move(_endts)),
687 m_recStartTs(
std::move(_recstartts)),
688 m_recEndTs(
std::move(_recendts)),
691 m_lastInUseTime(m_lastModified.addSecs(-kLastInUseOffset)),
693 m_inputName(
std::move(_inputname))
704 if (_pathname.isEmpty())
710 QDateTime _recstartts;
724 QString basename = _pathname.section(
'/', -1);
725 if (_pathname == basename)
726 SetPathname(QDir::currentPath() +
'/' + _pathname);
727 else if (_pathname.contains(
"./") && !_pathname.contains(
":"))
728 SetPathname(QFileInfo(_pathname).absoluteFilePath());
738 const QString &_plot,
739 const QString &_title,
740 const QString &_sortTitle,
741 const QString &_subtitle,
742 const QString &_sortSubtitle,
743 const QString &_director,
744 int _season,
int _episode,
745 const QString &_inetref,
746 std::chrono::minutes length_in_minutes,
748 const QString &_programid)
768 int64_t minutes = length_in_minutes.count();
771#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
775 QTimeZone(QTimeZone::UTC));
779 QString pn = _pathname;
780 if (!_pathname.startsWith(
"myth://"))
791 const QDateTime &_startts,
792 const QDateTime &_endts)
798 "SELECT chanid, channum, callsign, name, outputfilters, commmethod "
800 "WHERE chanid=:CHANID");
819 QString channelFormat =
827 QString(
"%1 (%2)").arg(
m_title, QObject::tr(
"Manual Record"));
845 bool ignore_non_serialized_data)
873 if (!ignore_non_serialized_data || !is_same ||
929 if (!ignore_non_serialized_data)
1035 if (a.isEmpty() and (b ==
"Default"))
1037 if ((a ==
"Default") and b.isEmpty())
1177 uint chanid,
const QDateTime &recstartts)
1179 return QString(
"%1_%2").arg(chanid).arg(recstartts.toString(
Qt::ISODate));
1186 uint &chanid, QDateTime &recstartts)
1188 QStringList keyParts = uniquekey.split(
'_');
1189 if (keyParts.size() != 2)
1191 chanid = keyParts[0].toUInt();
1193 return (chanid != 0U) && recstartts.isValid();
1197 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1199 QString basename = pathname.section(
'/', -1);
1200 if (basename.isEmpty())
1203 QStringList lr = basename.split(
"_");
1206 chanid = lr[0].toUInt();
1207 QStringList ts = lr[1].split(
".");
1208 if (chanid && !ts.empty())
1211 return recstartts.isValid();
1219 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1221 QString basename = pathname.section(
'/', -1);
1222 if (basename.isEmpty())
1227 "SELECT chanid, starttime "
1229 "WHERE basename = :BASENAME");
1233 chanid = query.
value(0).toUInt();
1244 QString basename = pathname.section(
'/', -1);
1245 if (basename.isEmpty())
1250 "SELECT recordedid "
1252 "WHERE basename = :BASENAME");
1256 recordedid = query.
value(0).toUInt();
1265 return QString::number(x.toSecsSinceEpoch());
1280 list << QString::number(
m_season );
1304 list << QString::number(
m_dupIn);
1316 list << QString(
"%1").arg(
m_stars);
1326 list << QString::number(
m_year);
1340#define NEXT_STR() do { if (it == listend) \
1342 LOG(VB_GENERAL, LOG_ERR, listerror); \
1346 ts = *it++; } while (false)
1357 if (str.isEmpty() || (str ==
"0000-00-00"))
1375 const QStringList::const_iterator& listend)
1377 QString listerror =
LOC +
"FromStringList, not enough items in list.";
1441 if (!origChanid || !origRecstartts.isValid() ||
1456template <
typename T>
1461 return propNames[0];
1464 for (
uint i = 0; i < (
sizeof(T)*8) - 1; ++i)
1467 if ((props & bit) == 0)
1469 if (propNames.contains(bit))
1471 result += propNames[bit];
1475 if (bit & FL_TYPEMASK)
1477 QString
tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1478 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1482 return result.join(
'|');
1485template <
typename T>
1487 const QString& props)
1489 if (props.isEmpty())
1494 QStringList names = props.split(
'|');
1495 for (
const auto& n : std::as_const(names) )
1497 uint bit = propNames.key(n, 0);
1500 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1538 tmp_rec += QObject::tr(
"Re-Record");
1593 uint date_format)
const
1598 QString channelFormat =
1600 QString longChannelFormat =
1610 QString tempSubTitle =
m_title;
1614 tempSubTitle = QString(
"%1 - \"%2\"")
1616 tempSortSubtitle = QString(
"%1 - \"%2\"")
1620 progMap[
"titlesubtitle"] = tempSubTitle;
1621 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1623 progMap[
"description"] = progMap[
"description0"] =
m_description;
1630 progMap[
"s00e00"] = QString(
"s%1e%2")
1633 progMap[
"00x00"] = QString(
"%1x%2")
1639 progMap[
"season"] = progMap[
"episode"] =
"";
1640 progMap[
"totalepisodes"] =
"";
1641 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1649 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1653 progMap[
"starttime"] =
"";
1654 progMap[
"startdate"] =
"";
1655 progMap[
"endtime"] =
"";
1656 progMap[
"enddate"] =
"";
1657 progMap[
"recstarttime"] =
"";
1658 progMap[
"recstartdate"] =
"";
1659 progMap[
"recendtime"] =
"";
1660 progMap[
"recenddate"] =
"";
1664 progMap[
"startdate"] =
"";
1665 progMap[
"recstartdate"] =
"";
1669 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1670 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1677 progMap[
"startdate"] =
1687 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1688 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1689 if (timeNow.toLocalTime().date().year() !=
1691 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1692 if (timeNow.toLocalTime().date().year() !=
1693 m_endTs.toLocalTime().date().year())
1694 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1698 progMap[
"timedate"] =
1702 progMap[
"shorttimedate"] =
1706 progMap[
"starttimedate"] =
1709 progMap[
"shortstarttimedate"] =
1713 progMap[
"lastmodifieddate"] =
1715 progMap[
"lastmodified"] =
1722 progMap[
"chanid"] = QString::number(
m_chanId);
1725 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1727 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1728 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1730 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1733 int minutes = seconds / 60;
1735 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1737 progMap[
"lenmins"] = min_str;
1738 int hours = minutes / 60;
1739 minutes = minutes % 60;
1741 progMap[
"lentime"] = min_str;
1742 if (hours > 0 && minutes > 0)
1744 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1745 progMap[
"lentime"] = QString(
"%1 %2")
1746 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1750 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1753 progMap[
"recordedpercent"] =
1756 progMap[
"watchedpercent"] =
1774 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1779 progMap[
"storagegroup"] = QObject::tr(
"Default");
1785 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1809 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1810 progMap[
"longrepeat"] = progMap[
"repeat"];
1813 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1814 .arg(QObject::tr(
"Repeat"),
1822 progMap[
"repeat"] =
"";
1823 progMap[
"longrepeat"] =
"";
1831 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1836 QString star_str = (
m_stars != 0.0F) ?
1837 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1838 progMap[
"stars"] = star_str;
1839 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1842 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1844 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1846 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1848 progMap[
"yearstars"] =
"";
1853 progMap[
"originalairdate"] =
"";
1854 progMap[
"shortoriginalairdate"] =
"";
1868 QString mediaTypeString;
1872 mediaType =
"video";
1873 mediaTypeString = QObject::tr(
"Video");
1877 mediaTypeString = QObject::tr(
"DVD");
1880 mediaType =
"httpstream";
1881 mediaTypeString = QObject::tr(
"HTTP Streaming");
1884 mediaType =
"rtspstream";
1885 mediaTypeString = QObject::tr(
"RTSP Streaming");
1888 mediaType =
"bluraydisc";
1889 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1893 mediaType =
"recording";
1894 mediaTypeString = QObject::tr(
"Recording",
1895 "Recorded file, object not action");
1897 progMap[
"mediatype"] = mediaType;
1898 progMap[
"mediatypestring"] = mediaTypeString;
1906 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1918 uint64_t last_frame = 0;
1927 if (!posMap.empty())
1929 frm_pos_map_t::const_iterator it = posMap.constEnd();
1931 last_frame = it.key();
1938 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1965 str +=
" startts(" +
1968 ") recendts(" +
m_recEndTs.toString() +
")\n";
1969 str +=
" title(" +
m_title +
")";
1977 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1982 str = QString(
"%1 at %2")
1986 str = QString(
"%1 @ %2")
2009 const uint _chanid,
const QDateTime &_recstartts)
2011 if (!_chanid || !_recstartts.isValid())
2020 "WHERE r.chanid = :CHANID AND "
2021 " r.starttime = :RECSTARTTS");
2023 query.
bindValue(
":RECSTARTTS", _recstartts);
2076 if (!query.
value(7).toString().isEmpty())
2090 QString new_basename = query.
value(14).toString();
2091 if ((
GetBasename() != new_basename) || !is_reload)
2095 LOG(VB_FILE, LOG_INFO,
LOC +
2096 QString(
"Updated pathname '%1':'%2' -> '%3'")
2232 if (index == oindex && (index < 0 ||
2291 if (index == oindex && (index < 0 ||
2386 QMap<QString, int> authMap;
2387 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2390 for (
const QString& table : tables)
2393 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2394 "FROM %1 WHERE programid <> ''").arg(table));
2399 while (query.
next())
2400 authMap[query.
value(0).toString()] = 1;
2404 int numAuths = authMap.count();
2405 LOG(VB_GENERAL, LOG_INFO,
2406 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2419 QString retval = QString(
"%1_%2.%3")
2420 .arg(QString::number(
m_chanId), starts, ext);
2426 uint chanid,
const QString &pathname,
bool use_remote)
2428 QString fn_lower = pathname.toLower();
2432 else if (fn_lower.startsWith(
"http:"))
2434 else if (fn_lower.startsWith(
"rtsp:"))
2440 if (fn_lower.startsWith(
"dvd:"))
2444 else if (fn_lower.startsWith(
"bd:"))
2448 else if (use_remote && fn_lower.startsWith(
"myth://"))
2450 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2451 QString tmpFileBD = pathname +
"/BDMV";
2479 LOG(VB_GUI, LOG_INFO,
2494 query.
prepare(
"UPDATE recorded "
2495 "SET basename = :BASENAME "
2496 "WHERE recordedid = :RECORDEDID;");
2506 query.
prepare(
"UPDATE recordedfile "
2507 "SET basename = :BASENAME "
2508 "WHERE recordedid = :RECORDEDID;");
2540 "FROM recordedfile "
2541 "WHERE recordedid = :RECORDEDID;");
2548 else if (query.
next())
2550 return query.
value(0).toString();
2554 LOG(VB_GENERAL, LOG_INFO,
2555 QString(
"QueryBasename found no entry for recording ID %1")
2570 bool checkMaster,
bool forceCheckLocal)
2577 if (basename.isEmpty())
2586 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2589 QUrl url = QUrl(fullpath);
2590 QString path = url.path();
2591 QString host = url.toString(QUrl::RemovePath).mid(7);
2592 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2596 list = host.split(
"@", Qt::SkipEmptyParts);
2598 if (!list.empty() && list.size() < 3)
2600 host = list.size() == 1 ? list[0] : list[1];
2601 group = list.size() == 1 ? QString() : list[0];
2604 if (!local.isEmpty() && sg.
FileExists(local))
2617 LOG(VB_FILE, LOG_DEBUG,
LOC +
2618 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2620 tmpURL = sgroup.
FindFile(basename);
2622 if (!tmpURL.isEmpty())
2624 LOG(VB_FILE, LOG_INFO,
LOC +
2625 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2630 LOG(VB_GENERAL, LOG_ERR,
LOC +
2631 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2632 "not be found.").arg(basename));
2635 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2641 if ((checkMaster) &&
2649 LOG(VB_FILE, LOG_INFO,
LOC +
2650 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2659 LOG(VB_FILE, LOG_INFO,
LOC +
2660 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2674 query.
prepare(
"SELECT mplexid FROM channel "
2675 "WHERE chanid = :CHANID");
2680 else if (query.
next())
2681 ret = query.
value(0).toUInt();
2684 ret = (32767 == ret) ? 0 : ret;
2696 bool is_valid = (frame > 0);
2717 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2718 " bookmark = :BOOKMARKFLAG "
2719 "WHERE recordedid = :RECORDEDID");
2721 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2733 bool isValid = frame > 0;
2758 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2759 " lastplay = :LASTPLAYFLAG "
2760 "WHERE recordedid = :RECORDEDID");
2762 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2793 "SELECT bookmarkupdate "
2795 "WHERE chanid = :CHANID AND"
2796 " starttime = :STARTTIME");
2804 else if (query.
next())
2824 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2834 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2851 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2868 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2876 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2883 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2890 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2897 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2901 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2911 const QString &serialid)
const
2913 QStringList fields = QStringList();
2918 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2919 " FROM dvdbookmark "
2920 " WHERE serialid = :SERIALID ");
2925 QString dvdstate = query.
value(0).toString();
2927 if (!dvdstate.isEmpty())
2929 fields.append(dvdstate);
2934 for(
int i = 1; i < 5; i++)
2935 fields.append(query.
value(i).toString());
2945 QStringList::const_iterator it = fields.begin();
2948 QString serialid = *(it);
2949 QString name = *(++it);
2951 if( fields.count() == 3 )
2954 QString state = *(++it);
2956 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2958 " VALUES ( :SERIALID, :NAME );");
2965 query.
prepare(
" UPDATE dvdbookmark "
2966 " SET dvdstate = :STATE , "
2967 " timestamp = NOW() "
2968 " WHERE serialid = :SERIALID");
2975 query.
prepare(
"DELETE FROM dvdbookmark "
2976 "WHERE serialid = :SERIALID");
2989 QStringList fields = QStringList();
2994 query.
prepare(
" SELECT bdstate FROM bdbookmark "
2995 " WHERE serialid = :SERIALID ");
2999 fields.append(query.
value(0).toString());
3007 QStringList::const_iterator it = fields.begin();
3010 QString serialid = *(it);
3011 QString name = *(++it);
3013 if( fields.count() == 3 )
3016 QString state = *(++it);
3018 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
3020 " VALUES ( :SERIALID, :NAME );");
3027 query.
prepare(
" UPDATE bdbookmark "
3028 " SET bdstate = :STATE , "
3029 " timestamp = NOW() "
3030 " WHERE serialid = :SERIALID");
3037 query.
prepare(
"DELETE FROM bdbookmark "
3038 "WHERE serialid = :SERIALID");
3057 query.
prepare(
" SELECT category_type "
3058 " FROM recordedprogram "
3059 " WHERE chanid = :CHANID "
3060 " AND starttime = :STARTTIME;");
3080 query.
prepare(
"UPDATE recorded"
3081 " SET watched = :WATCHEDFLAG"
3082 " WHERE chanid = :CHANID"
3083 " AND starttime = :STARTTIME ;");
3086 query.
bindValue(
":WATCHEDFLAG", watched);
3098 if (url.startsWith(
"myth://"))
3100 url = QUrl(url).path();
3105 query.
prepare(
"UPDATE videometadata"
3106 " SET watched = :WATCHEDFLAG"
3107 " WHERE title = :TITLE"
3108 " AND subtitle = :SUBTITLE"
3109 " AND filename = :FILENAME ;");
3113 query.
bindValue(
":WATCHEDFLAG", watched);
3132 query.
prepare(
"SELECT editing FROM recorded"
3133 " WHERE chanid = :CHANID"
3134 " AND starttime = :STARTTIME ;");
3139 editing = query.
value(0).toBool();
3156 query.
prepare(
"UPDATE recorded"
3157 " SET editing = :EDIT"
3158 " WHERE chanid = :CHANID"
3159 " AND starttime = :STARTTIME ;");
3181 query.
prepare(
"UPDATE recorded"
3182 " SET deletepending = :DELETEFLAG, "
3184 " WHERE chanid = :CHANID"
3185 " AND starttime = :STARTTIME ;");
3188 query.
bindValue(
":DELETEFLAG", deleteFlag);
3213 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3214 " WHERE chanid = :CHANID"
3215 " AND starttime = :STARTTIME "
3216 " AND lastupdatetime > :ONEHOURAGO ;");
3219 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3222 if (query.
exec() && query.
size() > 0)
3226 while (query.
next())
3228 usageStr = QObject::tr(
"Unknown");
3229 recusage = query.
value(1).toString();
3232 usageStr = QObject::tr(
"Playing");
3234 usageStr = QObject::tr(
"PIP");
3236 usageStr = QObject::tr(
"PBP");
3239 usageStr = QObject::tr(
"Recording");
3241 usageStr = QObject::tr(
"File transfer");
3243 usageStr = QObject::tr(
"Delete");
3245 usageStr = QObject::tr(
"Commercial Detection");
3247 usageStr = QObject::tr(
"Transcoding");
3249 usageStr = QObject::tr(
"Preview Generation");
3251 usageStr = QObject::tr(
"User Job");
3253 byWho.push_back(recusage);
3254 byWho.push_back(query.
value(0).toString());
3255 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3273 for (
int i = 0; i+2 < users.size(); i+=3)
3274 byWho += users[i+2] +
"\n";
3301 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3311 (one_playback_allowed && (play_cnt <= 1)));
3313 ok = ok && (ft_cnt == jq_cnt);
3324 query.
prepare(
"SELECT transcoded FROM recorded"
3325 " WHERE chanid = :CHANID"
3326 " AND starttime = :STARTTIME ;");
3346 "SET transcoded = :VALUE "
3347 "WHERE chanid = :CHANID AND"
3348 " starttime = :STARTTIME");
3367 query.
prepare(
"UPDATE recorded"
3368 " SET commflagged = :FLAG"
3369 " WHERE chanid = :CHANID"
3370 " AND starttime = :STARTTIME ;");
3393 query.
prepare(
"UPDATE recorded"
3394 " SET preserve = :PRESERVE"
3395 " WHERE chanid = :CHANID"
3396 " AND starttime = :STARTTIME ;");
3397 query.
bindValue(
":PRESERVE", preserveEpisode);
3420 query.
prepare(
"UPDATE recorded"
3421 " SET autoexpire = :AUTOEXPIRE"
3422 " WHERE chanid = :CHANID"
3423 " AND starttime = :STARTTIME ;");
3430 else if (updateDelete)
3449 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3450 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3453 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3454 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3455 "WHERE recordid = :RECORDID");
3457 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3461 query.
prepare(
"UPDATE record SET last_delete = NULL "
3462 "WHERE recordid = :RECORDID");
3475 query.
prepare(
"SELECT autoexpire FROM recorded"
3476 " WHERE chanid = :CHANID"
3477 " AND starttime = :STARTTIME ;");
3498 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3500 uint64_t frame = i.key();
3506 delMap[frame] = mark;
3516 return !delMap.isEmpty();
3532 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3534 uint64_t frame = i.key();
3543 tmpDelMap[frame] = mark;
3552 query.
prepare(
"UPDATE recorded"
3553 " SET cutlist = :CUTLIST"
3554 " WHERE chanid = :CHANID"
3555 " AND starttime = :STARTTIME ;");
3557 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3586 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3589 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3592 comp += QString(
" AND type = :TYPE ");
3596 query.
prepare(
"DELETE FROM filemarkup"
3597 " WHERE filename = :PATH "
3603 query.
prepare(
"DELETE FROM recordedmarkup"
3604 " WHERE chanid = :CHANID"
3605 " AND STARTTIME = :STARTTIME"
3622 int64_t min_frame, int64_t max_frame)
const
3634 query.
prepare(
"SELECT starttime FROM recorded"
3635 " WHERE chanid = :CHANID"
3636 " AND starttime = :STARTTIME ;");
3651 frm_dir_map_t::const_iterator it;
3652 for (it = marks.begin(); it != marks.end(); ++it)
3654 uint64_t frame = it.key();
3656 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3659 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3666 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3667 " VALUES ( :PATH , :MARK , :TYPE );");
3672 query.
prepare(
"INSERT INTO recordedmarkup"
3673 " (chanid, starttime, mark, type)"
3674 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3678 query.
bindValue(
":MARK", (quint64)frame);
3695 marks,
type, merge);
3704 const QString &video_pathname,
3713 query.
prepare(
"SELECT mark, type, `offset` "
3715 "WHERE filename = :PATH AND "
3718 query.
bindValue(
":PATH", video_pathname);
3727 while (query.
next())
3731 int entryType = query.
value(1).toInt();
3741 uint chanid,
const QDateTime &recstartts,
3749 query.
prepare(
"SELECT mark, type, data "
3750 "FROM recordedmarkup "
3751 "WHERE chanid = :CHANID AND "
3752 " starttime = :STARTTIME AND"
3756 query.
bindValue(
":STARTTIME", recstartts);
3765 while (query.
next())
3769 int entryType = query.
value(1).toInt();
3784 return flagMap.contains(0);
3812 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3813 " WHERE filename = :PATH"
3814 " AND type = :TYPE ;");
3819 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3820 " WHERE chanid = :CHANID"
3821 " AND starttime = :STARTTIME"
3822 " AND type = :TYPE ;");
3838 while (query.
next())
3839 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3855 query.
prepare(
"DELETE FROM filemarkup"
3856 " WHERE filename = :PATH"
3857 " AND type = :TYPE ;");
3862 query.
prepare(
"DELETE FROM recordedseek"
3863 " WHERE chanid = :CHANID"
3864 " AND starttime = :STARTTIME"
3865 " AND type = :TYPE ;");
3882 int64_t min_frame, int64_t max_frame)
const
3888 if ((min_frame >= 0) || (max_frame >= 0))
3896 uint64_t frame = it.key();
3897 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3899 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3901 new_map.insert(it.key(), *it);
3911 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3913 uint64_t frame = it.key();
3914 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3916 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3920 .insert(frame, *it);
3930 comp +=
" AND mark >= :MIN_FRAME ";
3932 comp +=
" AND mark <= :MAX_FRAME ";
3939 query.
prepare(
"DELETE FROM filemarkup"
3940 " WHERE filename = :PATH"
3947 query.
prepare(
"DELETE FROM recordedseek"
3948 " WHERE chanid = :CHANID"
3949 " AND starttime = :STARTTIME"
3962 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3964 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3969 if (posMap.isEmpty())
3973 QStringList q(
"INSERT INTO ");
3977 q <<
"filemarkup (filename, type, mark, `offset`)";
3978 qfields = QString(
"('%1',%2,") .
3985 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
3986 qfields = QString(
"(%1,'%2',%3,") .
3993 bool add_comma =
false;
3994 frm_pos_map_t::iterator it;
3995 for (it = posMap.begin(); it != posMap.end(); ++it)
3997 uint64_t frame = it.key();
3999 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
4002 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
4005 uint64_t offset = *it;
4015 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4027 if (posMap.isEmpty())
4034 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4041 QStringList q(
"INSERT INTO ");
4045 q <<
"filemarkup (filename, type, mark, `offset`)";
4046 qfields = QString(
"('%1',%2,") .
4053 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4054 qfields = QString(
"(%1,'%2',%3,") .
4065 bool add_comma =
false;
4066 frm_pos_map_t::iterator it;
4067 for (it = posMap.begin(); it != posMap.end(); ++it)
4069 uint64_t frame = it.key();
4070 uint64_t offset = *it;
4080 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4092 "SELECT mark, `offset` FROM filemarkup"
4093 " WHERE filename = :PATH"
4095 " AND mark >= :QUERY_ARG"
4096 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4098 "SELECT mark, `offset` FROM filemarkup"
4099 " WHERE filename = :PATH"
4101 " AND mark <= :QUERY_ARG"
4102 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4104 "SELECT mark, `offset` FROM recordedseek"
4105 " WHERE chanid = :CHANID"
4106 " AND starttime = :STARTTIME"
4108 " AND mark >= :QUERY_ARG"
4109 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4111 "SELECT mark, `offset` FROM recordedseek"
4112 " WHERE chanid = :CHANID"
4113 " AND starttime = :STARTTIME"
4115 " AND mark <= :QUERY_ARG"
4116 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4118 "SELECT `offset`,mark FROM filemarkup"
4119 " WHERE filename = :PATH"
4121 " AND `offset` >= :QUERY_ARG"
4122 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4124 "SELECT `offset`,mark FROM filemarkup"
4125 " WHERE filename = :PATH"
4127 " AND `offset` <= :QUERY_ARG"
4128 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4130 "SELECT `offset`,mark FROM recordedseek"
4131 " WHERE chanid = :CHANID"
4132 " AND starttime = :STARTTIME"
4134 " AND `offset` >= :QUERY_ARG"
4135 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4137 "SELECT `offset`,mark FROM recordedseek"
4138 " WHERE chanid = :CHANID"
4139 " AND starttime = :STARTTIME"
4141 " AND `offset` <= :QUERY_ARG"
4142 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4145 uint64_t position_or_keyframe,
4148 const char *from_filemarkup_asc,
4149 const char *from_filemarkup_desc,
4150 const char *from_recordedseek_asc,
4151 const char *from_recordedseek_desc)
const
4158 query.
prepare(from_filemarkup_desc);
4160 query.
prepare(from_filemarkup_asc);
4166 query.
prepare(from_recordedseek_desc);
4168 query.
prepare(from_recordedseek_asc);
4173 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4183 *result = query.
value(1).toULongLong();
4190 query.
prepare(from_filemarkup_asc);
4192 query.
prepare(from_filemarkup_desc);
4198 query.
prepare(from_recordedseek_asc);
4200 query.
prepare(from_recordedseek_desc);
4205 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4215 *result = query.
value(1).toULongLong();
4224 bool backwards)
const
4233 bool backwards)
const
4242 bool backwards)
const
4251 bool backwards)
const
4271 query.
prepare(
"INSERT INTO recordedmarkup"
4272 " (chanid, starttime, mark, type, data)"
4274 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4278 query.
bindValue(
":MARK", (quint64)frame);
4286#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4287 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4289 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4307 query.
prepare(
"INSERT INTO recordedmarkup"
4308 " (chanid, starttime, mark, type, data)"
4310 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4313 query.
bindValue(
":MARK", (quint64)frame);
4332 query.
prepare(
"INSERT INTO recordedmarkup"
4333 " (chanid, starttime, mark, type, data)"
4335 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4338 query.
bindValue(
":MARK", (quint64)frame);
4352 query.
prepare(
"DELETE FROM recordedmarkup "
4353 " WHERE chanid=:CHANID "
4354 " AND starttime=:STARTTIME "
4357 query.
bindValue(
":STARTTIME", recstartts);
4370 query.
prepare(
"DELETE FROM filemarkup"
4371 " WHERE filename = :PATH "
4372 " AND type = :TYPE ;");
4386 query.
prepare(
"DELETE FROM filemarkup"
4387 " WHERE filename = :PATH "
4388 " AND mark = :MARK "
4389 " AND type = :TYPE ;");
4403 query.
prepare(
"INSERT INTO filemarkup"
4404 " (filename, mark, type, `offset`)"
4406 " ( :PATH , :MARK , :TYPE, :OFFSET );");
4421 query.
prepare(
"INSERT INTO recordedmarkup"
4422 " (chanid, starttime, mark, type, data)"
4424 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4426 query.
bindValue(
":STARTTIME", recstartts);
4483 query.
prepare(
"INSERT INTO recordedmarkup"
4484 " (chanid, starttime, mark, type, data)"
4486 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4489 query.
bindValue(
":MARK", (quint64)frame);
4496 query.
prepare(
"INSERT INTO recordedmarkup"
4497 " (chanid, starttime, mark, type, data)"
4499 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4502 query.
bindValue(
":MARK", (quint64)frame);
4513 QString qstr = QString(
4514 "SELECT recordedmarkup.data "
4515 "FROM recordedmarkup "
4516 "WHERE recordedmarkup.chanid = :CHANID AND "
4517 " recordedmarkup.starttime = :STARTTIME AND "
4518 " recordedmarkup.type = :TYPE "
4519 "GROUP BY recordedmarkup.data "
4520 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4521 " FROM recordedmarkup AS rm "
4522 " WHERE rm.chanid = recordedmarkup.chanid AND "
4523 " rm.starttime = recordedmarkup.starttime AND "
4524 " rm.type = recordedmarkup.type AND "
4525 " rm.mark > recordedmarkup.mark "
4526 " ORDER BY rm.mark ASC LIMIT 1 "
4527 " ) - recordedmarkup.mark "
4535 query.
bindValue(
":STARTTIME", recstartts);
4543 return (query.
next()) ? query.
value(0).toUInt() : 0;
4549 QString qstr = QString(
4550 "SELECT filemarkup.`offset` "
4552 "WHERE filemarkup.filename = :PATH AND "
4553 " filemarkup.type = :TYPE "
4554 "GROUP BY filemarkup.`offset` "
4555 "ORDER BY SUM( ( SELECT IFNULL(fm.mark, filemarkup.mark)"
4556 " FROM filemarkup AS fm "
4557 " WHERE fm.filename = filemarkup.filename AND "
4558 " fm.type = filemarkup.type AND "
4559 " fm.mark > filemarkup.mark "
4560 " ORDER BY fm.mark ASC LIMIT 1 "
4561 " ) - filemarkup.mark "
4576 return (query.
next()) ? query.
value(0).toUInt() : 0;
4610 query.
prepare(
"SELECT recordedmarkup.type "
4611 "FROM recordedmarkup "
4612 "WHERE recordedmarkup.chanid = :CHANID AND "
4613 " recordedmarkup.starttime = :STARTTIME AND "
4614 " recordedmarkup.type >= :ASPECTSTART AND "
4615 " recordedmarkup.type <= :ASPECTEND "
4616 "GROUP BY recordedmarkup.type "
4617 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4618 " SELECT MAX(rmmax.mark) "
4619 " FROM recordedmarkup AS rmmax "
4620 " WHERE rmmax.chanid = recordedmarkup.chanid "
4621 " AND rmmax.starttime = recordedmarkup.starttime "
4623 " FROM recordedmarkup AS rm "
4624 " WHERE rm.chanid = recordedmarkup.chanid AND "
4625 " rm.starttime = recordedmarkup.starttime AND "
4626 " rm.type >= :ASPECTSTART2 AND "
4627 " rm.type <= :ASPECTEND2 AND "
4628 " rm.mark > recordedmarkup.mark "
4629 " ORDER BY rm.mark ASC LIMIT 1 "
4630 " ) - recordedmarkup.mark "
4701 QVector<MarkupEntry> &mapSeek)
const
4707 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4708 " WHERE filename = :PATH"
4709 " AND type NOT IN (:KEYFRAME,:DURATION)"
4710 " ORDER BY mark, type;");
4717 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4718 " WHERE chanid = :CHANID"
4719 " AND STARTTIME = :STARTTIME"
4720 " ORDER BY mark, type");
4733 while (query.
next())
4736 uint64_t frame = query.
value(1).toLongLong();
4738 bool isDataNull = query.
value(2).isNull();
4740 data = query.
value(2).toLongLong();
4747 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4748 " WHERE filename = :PATH"
4749 " AND type IN (:KEYFRAME,:DURATION)"
4750 " ORDER BY mark, type;");
4757 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4758 " WHERE chanid = :CHANID"
4759 " AND STARTTIME = :STARTTIME"
4760 " ORDER BY mark, type");
4769 while (query.
next())
4772 uint64_t frame = query.
value(1).toLongLong();
4774 bool isDataNull = query.
value(2).isNull();
4776 data = query.
value(2).toLongLong();
4782 const QVector<MarkupEntry> &mapSeek)
const
4788 if (mapMark.isEmpty())
4790 LOG(VB_GENERAL, LOG_INFO,
4791 QString(
"No mark entries in input, "
4792 "not removing marks from DB"));
4796 query.
prepare(
"DELETE FROM filemarkup"
4797 " WHERE filename = :PATH"
4798 " AND type NOT IN (:KEYFRAME,:DURATION)");
4807 for (
const auto& entry : std::as_const(mapMark))
4811 if (entry.isDataNull)
4813 query.
prepare(
"INSERT INTO filemarkup"
4814 " (filename,type,mark)"
4815 " VALUES (:PATH,:TYPE,:MARK)");
4819 query.
prepare(
"INSERT INTO filemarkup"
4820 " (filename,type,mark,`offset`)"
4821 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4822 query.
bindValue(
":OFFSET", (quint64)entry.data);
4826 query.
bindValue(
":MARK", (quint64)entry.frame);
4834 if (mapSeek.isEmpty())
4836 LOG(VB_GENERAL, LOG_INFO,
4837 QString(
"No seek entries in input, "
4838 "not removing marks from DB"));
4842 query.
prepare(
"DELETE FROM filemarkup"
4843 " WHERE filename = :PATH"
4844 " AND type IN (:KEYFRAME,:DURATION)");
4853 for (
int i = 0; i < mapSeek.size(); ++i)
4855 if (i > 0 && (i % 1000 == 0))
4857 LOG(VB_GENERAL, LOG_INFO,
4858 QString(
"Inserted %1 of %2 records")
4859 .arg(i).arg(mapSeek.size()));
4862 query.
prepare(
"INSERT INTO filemarkup"
4863 " (filename,type,mark,`offset`)"
4864 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4879 if (mapMark.isEmpty())
4881 LOG(VB_GENERAL, LOG_INFO,
4882 QString(
"No mark entries in input, "
4883 "not removing marks from DB"));
4887 query.
prepare(
"DELETE FROM recordedmarkup"
4888 " WHERE chanid = :CHANID"
4889 " AND starttime = :STARTTIME");
4897 for (
const auto& entry : std::as_const(mapMark))
4899 if (entry.isDataNull)
4901 query.
prepare(
"INSERT INTO recordedmarkup"
4902 " (chanid,starttime,type,mark)"
4903 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4907 query.
prepare(
"INSERT INTO recordedmarkup"
4908 " (chanid,starttime,type,mark,data)"
4909 " VALUES (:CHANID,:STARTTIME,"
4910 " :TYPE,:MARK,:OFFSET)");
4911 query.
bindValue(
":OFFSET", (quint64)entry.data);
4916 query.
bindValue(
":MARK", (quint64)entry.frame);
4924 if (mapSeek.isEmpty())
4926 LOG(VB_GENERAL, LOG_INFO,
4927 QString(
"No seek entries in input, "
4928 "not removing marks from DB"));
4932 query.
prepare(
"DELETE FROM recordedseek"
4933 " WHERE chanid = :CHANID"
4934 " AND starttime = :STARTTIME");
4942 for (
int i = 0; i < mapSeek.size(); ++i)
4944 if (i > 0 && (i % 1000 == 0))
4946 LOG(VB_GENERAL, LOG_INFO,
4947 QString(
"Inserted %1 of %2 records")
4948 .arg(i).arg(mapSeek.size()));
4951 query.
prepare(
"INSERT INTO recordedseek"
4952 " (chanid,starttime,type,mark,`offset`)"
4953 " VALUES (:CHANID,:STARTTIME,"
4954 " :TYPE,:MARK,:OFFSET)");
4974 LOG(VB_RECORD, LOG_INFO,
4975 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4976 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
4979 "UPDATE recordedprogram "
4980 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
4981 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
4984 query.
bindValue(
":FLAGS", video_property_flags);
4994 videoproperties &= ~mask;
4995 videoproperties |= video_property_flags;
5013 QString chan(format);
5023 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
5043 "SET season = :SEASON, episode = :EPISODE "
5044 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5045 "AND recordid = :RECORDID");
5067 "SET inetref = :INETREF "
5068 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5069 "AND recordid = :RECORDID");
5108 query.
prepare(
"SELECT password FROM recgroups "
5109 "WHERE recgroup = :GROUP");
5113 result = query.
value(0).toString();
5123 query.
prepare(
"SELECT recgroup FROM recorded "
5124 "WHERE chanid = :CHANID AND "
5125 " starttime = :START");
5131 grp = query.
value(0).toString();
5139 query.
prepare(
"SELECT transcoder FROM recorded "
5140 "WHERE chanid = :CHANID AND "
5141 " starttime = :START");
5146 return query.
value(0).toUInt();
5164 if (path.startsWith(
"/"))
5166 QFileInfo testFile(path);
5167 return testFile.path();
5178 if (testFile.exists())
5180 if (testFile.isSymLink())
5183 if (testFile.isFile())
5184 return testFile.path();
5185 if (testFile.isDir())
5186 return testFile.filePath();
5190 testFile.setFile(testFile.absolutePath());
5191 if (testFile.exists())
5193 if (testFile.isSymLink())
5196 if (testFile.isDir())
5197 return testFile.filePath();
5216 bool notifyOfChange =
false;
5222 if (!usedFor.isEmpty())
5228 LOG(VB_GENERAL, LOG_INFO,
LOC +
5229 QString(
"MarkAsInUse(true, '%1'->'%2')")
5231 " -- use has changed");
5235 LOG(VB_GENERAL, LOG_INFO,
LOC +
5236 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5245 .arg(QObject::tr(
"Unknown")).arg(getpid());
5246 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5248 " -- use was not explicitly set");
5251 notifyOfChange =
true;
5256 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5257 QString(
"MarkAsInUse(false, '%1'->'%2')")
5259 " -- use has changed since first setting as in use.");
5264 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5274 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5275 "MarkAsInUse requires a key to delete in use mark");
5283 "DELETE FROM inuseprograms "
5284 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5285 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5310 "FROM inuseprograms "
5311 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5312 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5322 else if (!query.
next())
5324 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5326 else if (query.
value(0).toBool())
5329 "UPDATE inuseprograms "
5330 "SET lastupdatetime = :UPDATETIME "
5331 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5332 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5337 query.
bindValue(
":UPDATETIME", inUseTime);
5347 "INSERT INTO inuseprograms "
5348 " (chanid, starttime, recusage, hostname, "
5349 " lastupdatetime, rechost, recdir) "
5351 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5352 " :UPDATETIME, :RECHOST, :RECDIR)");
5357 query.
bindValue(
":UPDATETIME", inUseTime);
5369 if (!notifyOfChange)
5374 query.
prepare(
"SELECT DISTINCT recusage "
5375 "FROM inuseprograms "
5376 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5377 " chanid = :CHANID AND "
5378 " starttime = :STARTTIME");
5381 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5385 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5386 while (query.
next())
5388 QString inUseForWhat = query.
value(0).toString();
5410 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5411 "FROM channel, capturecard "
5412 "WHERE channel.chanid = :CHANID AND "
5413 " capturecard.sourceid = :SOURCEID AND "
5414 " capturecard.cardid = :INPUTID");
5421 channum = query.
value(0).toString();
5422 input = query.
value(1).toString();
5431 static bool s_done =
false;
5432 static QMutex s_initTrLock;
5433 QMutexLocker locker(&s_initTrLock);
5437 QString rec_profile_names =
5438 QObject::tr(
"Default",
"Recording Profile Default") +
5439 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5440 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5441 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5442 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5443 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5444 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5447 QString rec_profile_groups =
5448 QObject::tr(
"CRC IP Recorders",
5449 "Recording Profile Group Name") +
5450 QObject::tr(
"FireWire Input",
5451 "Recording Profile Group Name") +
5452 QObject::tr(
"Freebox Input",
5453 "Recording Profile Group Name") +
5454 QObject::tr(
"Hardware DVB Encoders",
5455 "Recording Profile Group Name") +
5456 QObject::tr(
"Hardware HDTV",
5457 "Recording Profile Group Name") +
5458 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5459 "Recording Profile Group Name") +
5460 QObject::tr(
"HD-PVR Recorders",
5461 "Recording Profile Group Name") +
5462 QObject::tr(
"HDHomeRun Recorders",
5463 "Recording Profile Group Name") +
5464 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5465 "Recording Profile Group Name") +
5466 QObject::tr(
"Software Encoders (V4L based)",
5467 "Recording Profile Group Name") +
5468 QObject::tr(
"Transcoders",
5469 "Recording Profile Group Name") +
5470 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5471 "Recording Profile Group Name") +
5472 QObject::tr(
"V4L2 Encoders",
5473 "Recording Profile Group Name");
5475 QString display_rec_groups =
5476 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5477 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5478 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5479 QObject::tr(
"Default",
"Recording Group Default") +
5480 QObject::tr(
"Deleted",
"Recording Group Deleted");
5482 QString special_program_groups =
5483 QObject::tr(
"All Programs - %1",
5484 "Show all programs from a specific recording group");
5486 QString storage_groups =
5487 QObject::tr(
"Default",
"Storage Group Name") +
5488 QObject::tr(
"Live TV",
"Storage Group Name") +
5489 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5490 QObject::tr(
"DB Backups",
"Storage Group Name");
5492 QString play_groups =
5493 QObject::tr(
"Default",
"Playback Group Name");
5496 return (rec_profile_names.length() +
5497 rec_profile_groups.length() +
5498 display_rec_groups.length() +
5499 special_program_groups.length() +
5500 storage_groups.length() +
5501 play_groups.length());
5516 QByteArray msg_arr = msg.toLatin1();
5517 QString msg_i18n = QObject::tr(msg_arr.constData());
5518 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5519 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5531 if (pburl.startsWith(
"myth://"))
5533 str.replace(QString(
"%DIR%"), pburl);
5537 QFileInfo dirInfo(pburl);
5538 str.replace(QString(
"%DIR%"), dirInfo.path());
5546 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5547 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5548 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5549 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5550 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5552 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5553 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5554 str.replace(QString(
"%CATEGORY%"),
m_category);
5555 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5557 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5558 str.replace(QString(
"%INETREF%"),
m_inetRef);
5559 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5560 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5561 str.replace(QString(
"%ORIGINALAIRDATE%"),
5563 static const std::array<const QString,4> s_timeStr
5564 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5565 const std::array<const QDateTime *,4> time_dtr
5567 for (
size_t i = 0; i < s_timeStr.size(); i++)
5569 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5570 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5571 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5573 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5574 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5575 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5578 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5583 QMap<QString, uint32_t> inUseMap;
5588 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5589 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5590 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5595 while (query.
next())
5598 query.
value(0).toUInt(),
5601 QString inUseForWhat = query.
value(2).toString();
5603 if (!inUseMap.contains(inUseKey))
5604 inUseMap[inUseKey] = 0;
5607 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5609 inUseMap[inUseKey] |= FL_INUSERECORDING;
5611 inUseMap[inUseKey] |= FL_INUSEOTHER;
5619 QMap<QString,bool> is_job_running;
5622 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5623 "WHERE type = :TYPE");
5626 return is_job_running;
5628 while (query.
next())
5632 int tmpStatus = query.
value(2).toInt();
5633 if ((tmpStatus != 0x0000) &&
5634 (tmpStatus != 0x0001) &&
5635 (!(tmpStatus & 0x0100)))
5642 return is_job_running;
5646 const QString &tmptable,
int recordid)
5651 if (
sched && tmptable.isEmpty())
5659 LOG(VB_GENERAL, LOG_ERR,
5660 "Called from master backend\n\t\t\t"
5661 "with recordid or tmptable, this is not currently supported");
5666 (tmptable.isEmpty()) ?
5667 QString(
"QUERY_GETALLPENDING") :
5668 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5672 LOG(VB_GENERAL, LOG_ALERT,
5673 "LoadFromScheduler(): Error querying master.");
5692 QString columns = QString(
5693 "program.chanid, program.starttime, program.endtime, "
5694 "program.title, program.subtitle, program.description, "
5695 "program.category, channel.channum, channel.callsign, "
5696 "channel.name, program.previouslyshown, channel.commmethod, "
5697 "channel.outputfilters, program.seriesid, program.programid, "
5698 "program.airdate, program.stars, program.originalairdate, "
5699 "program.category_type, oldrecstatus.recordid, "
5700 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5701 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5702 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5703 "program.partnumber, program.parttotal, "
5704 "program.season, program.episode, program.totalepisodes ");
5706 QString querystr = QString(
5710 " LEFT JOIN channel ON program.chanid = channel.chanid "
5711 " LEFT JOIN oldrecorded AS oldrecstatus ON "
5712 " oldrecstatus.future = 0 AND "
5713 " program.title = oldrecstatus.title AND "
5714 " channel.callsign = oldrecstatus.station AND "
5715 " program.starttime = oldrecstatus.starttime "
5726 ", row_number() over ( "
5729 columns +=
"channel.channum, "
5730 " channel.callsign, ";
5732 columns +=
"channel.callsign, ";
5734 columns +=
"program.programid, ";
5737 " program.starttime "
5738 " order by channel.recpriority desc, "
5739 " channel.sourceid, "
5740 " channel.channum+0 "
5742 querystr +=
"WHERE grouprn = 1 ";
5748 querystr += QString(
"LIMIT %1 ").arg(limit);
5749 else if (!querystr.contains(
" LIMIT "))
5750 querystr +=
" LIMIT 20000 ";
5752 MSqlBindings::const_iterator it;
5769 if (start > 0 || limit > 0)
5771 QString countStr = querystr
5772 .arg(
"SQL_CALC_FOUND_ROWS chanid", columns);
5774 for (it = bindings.begin(); it != bindings.end(); ++it)
5776 if (countStr.contains(it.key()))
5786 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5787 count = query.
value(0).toUInt();
5791 querystr += QString(
"OFFSET %1 ").arg(start);
5793 querystr = querystr.arg(
"*", columns);
5795 for (it = bindings.begin(); it != bindings.end(); ++it)
5797 if (querystr.contains(it.key()))
5811 const QString &groupBy,
const QString &orderBy,
5816 QString queryStr =
"";
5818 if (!where.isEmpty())
5819 queryStr.append(QString(
"WHERE %1 ").arg(where));
5821 if (!groupBy.isEmpty())
5822 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5824 if (!orderBy.isEmpty())
5825 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5829 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5839 QString queryStr = sql;
5853 if (!queryStr.contains(
"WHERE"))
5854 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5856 if (!queryStr.contains(
"ORDER BY"))
5858 queryStr +=
" ORDER BY program.starttime, ";
5861 if (chanorder !=
"channum")
5862 queryStr += chanorder +
" ";
5864 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5869 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5879 destination.
clear();
5881 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5883 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5884 "clause, caller should be updated to use "
5885 "start parameter instead");
5888 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5890 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5891 "clause, caller should be updated to use "
5892 "limit parameter instead");
5901 count = query.
size();
5903 while (query.
next())
5907 query.
value(3).toString(),
5909 query.
value(4).toString(),
5911 query.
value(5).toString(),
5912 query.
value(26).toString(),
5913 query.
value(6).toString(),
5915 query.
value(0).toUInt(),
5916 query.
value(7).toString(),
5917 query.
value(8).toString(),
5918 query.
value(9).toString(),
5919 query.
value(12).toString(),
5926 query.
value(13).toString(),
5927 query.
value(14).toString(),
5930 query.
value(16).toFloat(),
5931 query.
value(15).toUInt(),
5932 query.
value(27).toUInt(),
5933 query.
value(28).toUInt(),
5934 query.
value(17).toDate(),
5936 query.
value(19).toUInt(),
5938 query.
value(22).toUInt(),
5941 query.
value(10).toBool(),
5942 query.
value(23).toInt(),
5943 query.
value(24).toInt(),
5944 query.
value(25).toInt(),
5945 query.
value(29).toUInt(),
5946 query.
value(30).toUInt(),
5947 query.
value(31).toUInt(),
5956 const QDateTime& starttime)
5963 QString sSQL =
"WHERE program.chanid = :ChanId "
5964 "AND program.starttime = :StartTime ";
5966 bindings[
":ChanId" ] = chanid;
5967 bindings[
":StartTime"] = starttime;
5972 bool hasConflicts =
false;
5981 if (progList.
empty())
6002 destination.
clear();
6008 "oldrecorded.chanid, starttime, endtime, "
6009 "title, subtitle, description, season, episode, category, seriesid, "
6010 "programid, inetref, channel.channum, channel.callsign, "
6011 "channel.name, findid, rectype, recstatus, recordid, duplicate ";
6016 "LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
6017 "WHERE oldrecorded.future = 0 "
6020 bool hasLimit = querystr.contains(
" LIMIT ",Qt::CaseInsensitive);
6024 if (!hasLimit && !querystr.contains(
" ORDER ",Qt::CaseInsensitive))
6025 querystr +=
" ORDER BY starttime DESC ";
6030 querystr += QString(
"LIMIT %1 ").arg(limit);
6036 nLimit = std::max(nLimit, 100);
6037 querystr += QString(
"LIMIT %1 ").arg(nLimit);
6040 MSqlBindings::const_iterator it;
6057 if (count > 0 && (start > 0 || limit > 0))
6059 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS oldrecorded.chanid");
6061 for (it = bindings.begin(); it != bindings.end(); ++it)
6063 if (countStr.contains(it.key()))
6073 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
6074 count = query.
value(0).toUInt();
6078 querystr += QString(
"OFFSET %1 ").arg(start);
6080 querystr = querystr.arg(columns);
6082 for (it = bindings.begin(); it != bindings.end(); ++it)
6084 if (querystr.contains(it.key()))
6094 while (query.
next())
6097 QString channum = QString(
"#%1").arg(chanid);
6098 QString chansign = channum;
6099 QString channame = channum;
6100 if (!query.
value(12).toString().isEmpty())
6102 channum = query.
value(12).toString();
6103 chansign = query.
value(13).toString();
6104 channame = query.
value(14).toString();
6108 query.
value(3).toString(),
6110 query.
value(4).toString(),
6112 query.
value(5).toString(),
6113 query.
value(6).toUInt(),
6114 query.
value(7).toUInt(),
6115 query.
value(8).toString(),
6117 chanid, channum, chansign, channame,
6119 query.
value(9).toString(), query.
value(10).toString(),
6120 query.
value(11).toString(),
6128 query.
value(18).toUInt(),
6130 query.
value(15).toUInt(),
6132 query.
value(19).toBool()));
6158 bool possiblyInProgressRecordingsOnly,
6159 const QMap<QString,uint32_t> &inUseMap,
6160 const QMap<QString,bool> &isJobRunning,
6161 const QMap<QString, ProgramInfo*> &recMap,
6163 const QString &sortBy,
6167 destination.
clear();
6175 if (possiblyInProgressRecordingsOnly || ignoreLiveTV || ignoreDeleted)
6177 thequery +=
"WHERE ";
6178 if (possiblyInProgressRecordingsOnly)
6180 thequery +=
"(r.endtime >= NOW() AND r.starttime <= NOW()) ";
6184 thequery += QString(
"%1 r.recgroup != 'LiveTV' ")
6185 .arg(possiblyInProgressRecordingsOnly ?
"AND" :
"");
6189 thequery += QString(
"%1 r.recgroup != 'Deleted' ")
6190 .arg((possiblyInProgressRecordingsOnly || ignoreLiveTV)
6195 if (sortBy.isEmpty())
6198 thequery +=
"ORDER BY r.starttime ";
6200 thequery +=
"DESC ";
6204 QStringList sortByFields;
6205 sortByFields <<
"starttime" <<
"title" <<
"subtitle" <<
"season" <<
"episode" <<
"category"
6206 <<
"watched" <<
"stars" <<
"originalairdate" <<
"recgroup" <<
"storagegroup"
6207 <<
"channum" <<
"callsign" <<
"name" <<
"filesize" <<
"duration";
6210 QStringList fields = sortBy.split(
",");
6211 for (
const QString& oneField : std::as_const(fields))
6213 bool ascending =
true;
6214 QString field = oneField.simplified().toLower();
6216 if (field.endsWith(
"desc"))
6219 field = field.remove(
"desc");
6222 if (field.endsWith(
"asc"))
6225 field = field.remove(
"asc");
6228 field = field.simplified();
6230 if (field ==
"channelname")
6233 if (sortByFields.contains(field))
6236 if (field ==
"channum" || field ==
"callsign" || field ==
"name")
6241 if (field ==
"channum")
6244 field =
"channum*1000-ifnull(regexp_substr(c.channum,'-.*'),0)";
6247 else if (field ==
"duration")
6249 field =
"timestampdiff(second,r.starttime,r.endtime)";
6253 else if (field ==
"season")
6255 field =
"if(r.season,r.season,p.season)";
6259 else if (field ==
"episode")
6261 field =
"if(r.episode,r.episode,p.episode)";
6265 else if (field ==
"title")
6268 QString prefixes = sh->getPrefixes();
6269 field =
"REGEXP_REPLACE(r.title,'" + prefixes +
"','')";
6273 else if (field ==
"subtitle")
6276 QString prefixes = sh->getPrefixes();
6277 field =
"REGEXP_REPLACE(r.subtitle,'" + prefixes +
"','')";
6281 else if (field ==
"originalairdate")
6283 field =
"IF(r.originalairdate != '0000-00-00', r.originalairdate, STR_TO_DATE(CONCAT(p.airdate,',01,01'),'%Y,%m,%d'))";
6287 if (sSortBy.isEmpty())
6288 sSortBy = QString(
"%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6290 sSortBy += QString(
",%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6294 LOG(VB_GENERAL, LOG_WARNING, QString(
"ProgramInfo::LoadFromRecorded() got an unknown sort field '%1' - ignoring").arg(oneField));
6298 thequery +=
"ORDER BY " + sSortBy;
6310 while (query.
next())
6312 const uint chanid = query.
value(6).toUInt();
6313 QString channum = QString(
"#%1").arg(chanid);
6314 QString chansign = channum;
6315 QString channame = channum;
6317 if (!query.
value(7).toString().isEmpty())
6319 channum = query.
value(7).toString();
6320 chansign = query.
value(8).toString();
6321 channame = query.
value(9).toString();
6322 chanfilt = query.
value(10).toString();
6334 recMap.contains(key))
6339 bool save_not_commflagged =
false;
6346 set_flag(flags, FL_COMMPROCESSING ,
6351 set_flag(flags, FL_DELETEPENDING, query.
value(35).toBool());
6355 set_flag(flags, FL_REALLYEDITING, query.
value(39).toBool());
6360 if (inUseMap.contains(key))
6361 flags |= inUseMap[key];
6363 if (((flags & FL_COMMPROCESSING) != 0U) &&
6364 (!isJobRunning.contains(key)))
6366 flags &= ~FL_COMMPROCESSING;
6367 save_not_commflagged =
true;
6371 ((flags & FL_REALLYEDITING) != 0U) ||
6377 season = query.
value(51).toUInt();
6382 episode = query.
value(52).toUInt();
6385 uint totalepisodes = query.
value(53).toUInt();
6389 query.
value(55).toUInt(),
6390 query.
value(0).toString(),
6392 query.
value(1).toString(),
6394 query.
value(2).toString(),
6398 query.
value(48).toString(),
6399 query.
value(5).toString(),
6401 chanid, channum, chansign, channame, chanfilt,
6403 query.
value(11).toString(), query.
value(12).toString(),
6405 query.
value(14).toString(),
6409 query.
value(17).toString(), query.
value(18).toString(),
6410 query.
value(19).toString(),
6413 query.
value(16).toInt(),
6415 query.
value(20).toULongLong(),
6422 query.
value(23).toFloat(),
6424 query.
value(26).toUInt(),
6425 query.
value(49).toUInt(),
6426 query.
value(50).toUInt(),
6427 query.
value(27).toDate(),
6432 query.
value(29).toUInt(),
6437 query.
value(45).toUInt(),
6440 query.
value(42).toUInt(),
6441 query.
value(43).toUInt(),
6442 query.
value(44).toUInt(),
6443 query.
value(56).toString(),
6447 if (save_not_commflagged)
6456 std::vector<ProgramInfo> *list)
6458 nextRecordingStart = QDateTime();
6461 bool *conflicts = (hasConflicts) ? hasConflicts : &dummy;
6468 for (
auto *prog : progList)
6472 (nextRecordingStart.isNull() ||
6473 nextRecordingStart > prog->GetRecordingStartTime()))
6475 nextRecordingStart = prog->GetRecordingStartTime();
6483 for (
auto & prog : progList)
6487 (prog->GetRecordingStartTime() == nextRecordingStart))
6527 "SET filesize = :FILESIZE "
6528 "WHERE chanid = :CHANID AND "
6529 " starttime = :STARTTIME");
6530 query.
bindValue(
":FILESIZE", (quint64)fsize);
6561 uint64_t db_filesize = 0;
6568 "WHERE chanid = :CHANID AND "
6569 " starttime = :STARTTIME");
6573 db_filesize = query.
value(0).toULongLong();
6576 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"RI Filesize=0, DB Filesize=%1")
6590 if (now < startTime)
6594 int current = startTime.secsTo(now);
6595 int duration = startTime.secsTo(endTime);
6600 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 recorded percent %2/%3 = %4%")
6629 total = rate1000 * duration / 1000;
6641 LOG(VB_GUI, LOG_DEBUG,
6642 QString(
"%1 %2 no frame count. Please rebuild seek table for this video.")
6647 LOG(VB_GUI, LOG_DEBUG,
6648 QString(
"%1 %2 no frame count. Please rebuild seek table for this recording.")
6656 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 %2 watched percent %3/%4 = %5%")
6674 return tr(
"Channel Number");
6676 return tr(
"CallSign");
6678 return tr(
"ProgramId");
6680 return tr(
"Unknown");
6686 QStringList strlist(
"QUERY_CHECKFILE");
6687 strlist << QString::number((
int)checkSlaves);
6691 (strlist.size() < 2) || !strlist[0].toInt())
6696 QString localpath = strlist[1];
6697 QFile checkFile(localpath);
6698 if (checkFile.exists())
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
void setForwardOnly(bool f)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
static ImageType inspectImage(const QString &path)
bool IsDatabaseIgnored(void) const
/brief Returns true if database is being ignored.
QString GetHostName(void)
MythScheduler * GetScheduler(void)
QString GetSetting(const QString &key, const QString &defaultval="")
static int GetMasterServerPort(void)
Returns the Master Backend control port If no master server port has been defined in the database,...
int GetBackendServerPort(void)
Returns the locally defined backend control port.
bool IsBackend(void) const
is this process a backend process
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
int GetNumSetting(const QString &key, int defaultval=0)
QString GetMasterHostName(void)
bool GetBoolSetting(const QString &key, bool defaultval=false)
static void DBError(const QString &where, const MSqlQuery &query)
This is an generic interface to a program scheduler.
QMap< MarkTypes, frm_pos_map_t > map
static QString toString(ProgGroupBy::Type groupBy)
void insert(uint recordedid, PIAction action, uint64_t filesize=0ULL)
Holds information on recordings and videos.
float GetStars(void) const
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
void SetAvailableStatus(AvailableStatusType status, const QString &where)
ProgramInfo & operator=(const ProgramInfo &other)
Copies important fields from other ProgramInfo.
static uint SubtitleTypesFromNames(const QString &names)
bool QueryKeyFrameInfo(uint64_t *result, uint64_t position_or_keyframe, bool backwards, MarkTypes type, const char *from_filemarkup_asc, const char *from_filemarkup_desc, const char *from_recordedseek_asc, const char *from_recordedseek_desc) const
uint64_t QueryStartMark(void) const
QString GetShortInputName(void) const
void SaveTranscodeStatus(TranscodingStatus trans)
Set "transcoded" field in "recorded" table to "trans".
void QueryMarkup(QVector< MarkupEntry > &mapMark, QVector< MarkupEntry > &mapSeek) const
bool IsSameProgramWeakCheck(const ProgramInfo &other) const
Checks for duplicate using only title, chanid and startts.
QString GetBasename(void) const
bool IsSameTitleTimeslotAndChannel(const ProgramInfo &other) const
Checks title, chanid or chansign, start/end times, cardid, inputid for fully inclusive overlap.
QString GetAudioPropertyNames(void) const
static bool ExtractKey(const QString &uniquekey, uint &chanid, QDateTime &recstartts)
Extracts chanid and recstartts from a unique key generated by MakeUniqueKey().
void SavePreserve(bool preserveEpisode)
Set "preserve" field in "recorded" table to "preserveEpisode".
static bool s_usingProgIDAuth
bool QueryIsInUse(QStringList &byWho) const
Returns true if Program is in use.
PMapDBReplacement * m_positionMapDBReplacement
static ProgramInfoUpdater * s_updater
bool IsVideoFile(void) const
VideoPropsType m_videoProperties
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
bool IsVideoDVD(void) const
ProgramInfoType GetProgramInfoType(void) const
bool QueryTuningInfo(QString &channum, QString &input) const
Returns the channel and input needed to record the program.
void ensureSortFields(void)
Ensure that the sortTitle and sortSubtitle fields are set.
QString GetCategoryTypeString(void) const
Returns catType as a string.
bool IsSameTitleStartTimeAndChannel(const ProgramInfo &other) const
Checks title, chanid or callsign and start times for equality.
void SetTitle(const QString &t, const QString &st=nullptr)
static const QString kFromRecordedQuery
AutoExpireType QueryAutoExpire(void) const
Returns "autoexpire" field from "recorded" table.
static int InitStatics(void)
uint GetEpisode(void) const
uint64_t QueryProgStart(void) const
Gets any progstart position in database, unless the ignore progstart flag is set.
uint32_t m_programFlags
ProgramFlag.
void SaveWatched(bool watchedFlag)
Set "watched" field in recorded/videometadata to "watchedFlag".
virtual void SaveFilesize(uint64_t fsize)
Sets recording file size in database, and sets "filesize" field.
void CalculateWatchedProgress(uint64_t pos)
void UpdateInUseMark(bool force=false)
bool IsDuplicateProgram(const ProgramInfo &other) const
Checks for duplicates according to dupmethod.
QString m_chanPlaybackFilters
bool IsSameChannel(const ProgramInfo &other) const
Checks whether channel id or callsign are identical.
QString GetRecordingGroup(void) const
QString ChannelText(const QString &format) const
Returns channel info using "format".
void SaveAutoExpire(AutoExpireType autoExpire, bool updateDelete=false)
Set "autoexpire" field in "recorded" table to "autoExpire".
QString GetProgramFlagNames(void) const
uint8_t m_availableStatus
void ProgramFlagsFromNames(const QString &names)
ProgramInfo(void)
Null constructor.
void ClearPositionMap(MarkTypes type) const
uint QueryMplexID(void) const
Queries multiplex any recording would be made on, zero if unknown.
bool IsSameProgram(const ProgramInfo &other) const
Checks whether this is the same program as "other", which may or may not be a repeat or on another ch...
uint QueryTranscoderID(void) const
void SaveMarkup(const QVector< MarkupEntry > &mapMark, const QVector< MarkupEntry > &mapSeek) const
bool FromStringList(QStringList::const_iterator &it, const QStringList::const_iterator &end)
Uses a QStringList to initialize this ProgramInfo instance.
bool HasCutlist(void) const
void SendAddedEvent(void) const
Sends event out that the ProgramInfo should be added to lists.
QStringList QueryBDBookmark(const QString &serialid) const
Queries "bdbookmark" table for bookmarking BD serial number.
bool QueryIsDeleteCandidate(bool one_playback_allowed=false) const
Returns true iff this is a recording, it is not in use (except by the recorder), and at most one play...
bool QueryKeyFrameDuration(uint64_t *duration, uint64_t keyframe, bool backwards) const
bool LoadProgramFromRecorded(uint chanid, const QDateTime &recstartts)
Loads ProgramInfo for an existing recording.
void QueryCommBreakList(frm_dir_map_t &frames) const
int64_t QueryTotalFrames(void) const
If present in recording this loads total frames of the main video stream from database's stream marku...
void CalculateRecordedProgress()
bool IsFileReadable(void)
Attempts to ascertain if the main file for this ProgramInfo is readable.
bool IsRepeat(void) const
void SaveVideoScanType(uint64_t frame, bool progressive)
Store the Progressive/Interlaced state in the recordedmarkup table.
QDateTime QueryBookmarkTimeStamp(void) const
Queries Latest bookmark timestamp from the database.
void QueryPositionMap(frm_pos_map_t &posMap, MarkTypes type) const
void SaveTotalDuration(std::chrono::milliseconds duration)
Store the Total Duration at frame 0 in the recordedmarkup table.
QString CreateRecordBasename(const QString &ext) const
Returns a filename for a recording based on the recording channel and date.
bool IsRecording(void) const
static bool QueryKeyFromPathname(const QString &pathname, uint &chanid, QDateTime &recstartts)
static QStringList LoadFromScheduler(const QString &tmptable, int recordid)
CategoryType QueryCategoryType(void) const
Queries recordedprogram to get the category_type of the recording.
void UpdateMarkTimeStamp(bool bookmarked) const
virtual void SetFilesize(uint64_t sz)
QString DiscoverRecordingDirectory(void)
void UpdateLastDelete(bool setTime) const
Set or unset the record.last_delete field.
void SaveResolution(uint64_t frame, uint width, uint height)
Store the Resolution at frame in the recordedmarkup table.
void SaveFrameRate(uint64_t frame, uint framerate)
Store the Frame Rate at frame in the recordedmarkup table.
bool SaveBasename(const QString &basename)
Sets a recording's basename in the database.
void SaveAspect(uint64_t frame, MarkTypes type, uint customAspect)
Store aspect ratio of a frame in the recordedmark table.
void SendDeletedEvent(void) const
Sends event out that the ProgramInfo should be delete from lists.
uint QueryAverageWidth(void) const
If present in recording this loads average width of the main video stream from database's stream mark...
void SaveVideoProperties(uint mask, uint video_property_flags)
TranscodingStatus QueryTranscodeStatus(void) const
Returns the "transcoded" field in "recorded" table.
bool QueryIsEditing(void) const
Queries "recorded" table for its "editing" field and returns true if it is set to true.
static uint AudioPropertiesFromNames(const QString &names)
uint QueryAverageHeight(void) const
If present in recording this loads average height of the main video stream from database's stream mar...
AudioPropsType m_audioProperties
void MarkAsInUse(bool inuse, const QString &usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
static void CheckProgramIDAuthorities(void)
static QMap< QString, bool > QueryJobsRunning(int type)
bool IsGeneric(void) const
static QString QueryRecordingGroupPassword(const QString &group)
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
bool IsSameProgramAndStartTime(const ProgramInfo &other) const
Match same program, with same starttime (channel may be different)
bool QueryPositionKeyFrame(uint64_t *keyframe, uint64_t position, bool backwards) const
static bool ExtractKeyFromPathname(const QString &pathname, uint &chanid, QDateTime &recstartts)
bool QueryAverageScanProgressive(void) const
If present in recording this loads average video scan type of the main video stream from database's s...
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
void SavePositionMap(frm_pos_map_t &posMap, MarkTypes type, int64_t min_frame=-1, int64_t max_frame=-1) const
QString QueryBasename(void) const
Gets the basename, from the DB if necessary.
void SaveLastPlayPos(uint64_t frame)
TODO Move to RecordingInfo.
void SaveInetRef(const QString &inet)
uint64_t QueryLastFrameInPosMap(void) const
Returns last frame in position map or 0.
bool QueryCutList(frm_dir_map_t &delMap, bool loadAutosave=false) const
QString m_syndicatedEpisode
uint QueryAverageFrameRate(void) const
If present in recording this loads average frame rate of the main video stream from database's stream...
float m_stars
Rating, range [0..1].
std::chrono::milliseconds QueryTotalDuration(void) const
If present this loads the total duration in milliseconds of the main video stream from recordedmarkup...
void SaveCommBreakList(frm_dir_map_t &frames) const
QString GetSubtitleTypeNames(void) const
ProgramInfoType DiscoverProgramInfoType(void) const
bool IsDuplicate(void) const
MarkTypes QueryAverageAspectRatio(void) const
void SaveCutList(frm_dir_map_t &delMap, bool isAutoSave=false) const
void SetProgramInfoType(ProgramInfoType t)
void SaveTotalFrames(int64_t frames)
Store the Total Frames at frame 0 in the recordedmarkup table.
QStringList QueryDVDBookmark(const QString &serialid) const
Queries "dvdbookmark" table for bookmarking DVD serial number.
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
virtual void SubstituteMatches(QString &str)
Subsitute MATCH% type variable names in the given string.
static QString i18n(const QString &msg)
Translations for play,recording, & storage groups +.
bool IsVideoBD(void) const
static constexpr int64_t kLastInUseOffset
SubtitlePropsType m_subtitleProperties
void SavePositionMapDelta(frm_pos_map_t &posMap, MarkTypes type) const
void ClearMarkupMap(MarkTypes type=MARK_ALL, int64_t min_frame=-1, int64_t max_frame=-1) const
std::chrono::seconds GetSecondsInRecording(void) const
Returns length of program/recording in seconds.
void SaveMarkupFlag(MarkTypes type) const
Clears the specified flag, then if sets it.
static void SaveBDBookmark(const QStringList &fields)
virtual void ToMap(InfoMap &progMap, bool showrerecord=false, uint star_range=10, uint date_format=0) const
Converts ProgramInfo into QString QHash containing each field in ProgramInfo converted into localized...
QString GetPathname(void) const
bool QueryMarkupFlag(MarkTypes type) const
Returns true iff the speficied mark type is set on frame 0.
bool QueryKeyFramePosition(uint64_t *position, uint64_t keyframe, bool backwards) const
void SaveEditing(bool edit)
Sets "editing" field in "recorded" table to "edit".
void QueryMarkupMap(frm_dir_map_t &marks, MarkTypes type, bool merge=false) const
static uint VideoPropertiesFromNames(const QString &names)
QString GetVideoPropertyNames(void) const
virtual uint64_t GetFilesize(void) const
bool QueryDurationKeyFrame(uint64_t *keyframe, uint64_t duration, bool backwards) const
void UpdateLastPlayTimeStamp(bool lastplay) const
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
QString GetPlaybackURL(bool checkMaster=false, bool forceCheckLocal=false)
Returns filename or URL to be used to play back this recording.
void SaveSeasonEpisode(uint seas, uint ep)
bool IsWatched(void) const
virtual void clone(const ProgramInfo &other, bool ignore_non_serialized_data=false)
Copies important fields from other ProgramInfo.
static bool QueryRecordedIdFromPathname(const QString &pathname, uint &recordedid)
static QMap< QString, uint32_t > QueryInUseMap(void)
RecStatus::Type GetRecordingStatus(void) const
QString GetRecTypeStatus(bool showrerecord) const
uint64_t QueryLastPlayPos(void) const
Gets any lastplaypos position in database, unless the ignore lastplaypos flag is set.
uint64_t QueryBookmark(void) const
Gets any bookmark position in database, unless the ignore bookmark flag is set.
QDateTime m_bookmarkUpdate
void SaveMarkupMap(const frm_dir_map_t &marks, MarkTypes type=MARK_ALL, int64_t min_frame=-1, int64_t max_frame=-1) const
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
void SendUpdateEvent(void) const
Sends event out that the ProgramInfo should be reloaded.
void SaveBookmark(uint64_t frame)
Clears any existing bookmark in DB and if frame is greater than 0 sets a new bookmark.
uint GetSeason(void) const
void SetSubtitle(const QString &st, const QString &sst=nullptr)
static void SaveDVDBookmark(const QStringList &fields)
QDateTime m_lastInUseTime
void SaveDeletePendingFlag(bool deleteFlag)
Set "deletepending" field in "recorded" table to "deleteFlag".
bool IsMythStream(void) const
void SetPathname(const QString &pn)
RecordingType GetRecordingRuleType(void) const
bool operator==(const ProgramInfo &rhs)
void CalculateProgress(uint64_t pos)
static QMutex s_staticDataLock
QString QueryRecordingGroup(void) const
Query recgroup from recorded.
static QString toDescription(Type recstatus, RecordingType rectype, const QDateTime &recstartts)
Converts "recstatus" into a long human readable description.
static QString toString(RecStatus::Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
static bool Exists(const QString &url, struct stat *fileinfo)
bool GetAllPending(RecList &retList, int recRuleId=0) const
bool FileExists(const QString &filename)
QString FindFile(const QString &filename)
static const QStringList kSpecialGroups
static QString GetRelativePathname(const QString &filename)
Returns the relative pathname of a file by comparing the filename against all Storage Group directori...
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.
QHash< QString, QString > InfoMap
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
std::chrono::seconds secsInPast(const QDateTime &past)
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
@ kDateTimeFull
Default local time.
@ kFilename
Default UTC, "yyyyMMddhhmmss".
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
@ kDateFull
Default local time.
@ kDateTimeShort
Default local time.
@ kTime
Default local time.
@ kAddYear
Add year to string if not included.
@ kDateShort
Default local time.
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
QString intToPaddedString(int n, int width=2)
Creates a zero padded string representation of an integer.
static QDateTime DateTimeFromListItem(const QString &str)
static const char * from_recordedseek_offset_desc
static void insert_markup_datum(MarkTypes type, uint mark, uint offset, const QString &videoPath)
bool LoadFromRecorded(ProgramList &destination, bool possiblyInProgressRecordingsOnly, const QMap< QString, uint32_t > &inUseMap, const QMap< QString, bool > &isJobRunning, const QMap< QString, ProgramInfo * > &recMap, int sort, const QString &sortBy, bool ignoreLiveTV, bool ignoreDeleted)
static QString determineURLType(const QString &url)
QString myth_category_type_to_string(ProgramInfo::CategoryType category_type)
static const char * from_recordedseek_mark_desc
bool RemoteCheckFile(ProgramInfo *pginfo, bool checkSlaves)
ProgramInfo::CategoryType string_to_myth_category_type(const QString &category_type)
bool GetNextRecordingList(QDateTime &nextRecordingStart, bool *hasConflicts, std::vector< ProgramInfo > *list)
static void set_flag(uint32_t &flags, int flag_to_set, bool is_set)
ProgramInfo * LoadProgramFromProgram(const uint chanid, const QDateTime &starttime)
bool LoadFromOldRecorded(ProgramList &destination, const QString &sql, const MSqlBindings &bindings)
static QString DateTimeToListInt(const QDateTime &x)
static const char * from_filemarkup_mark_desc
static const char * from_filemarkup_offset_desc
bool LoadFromProgram(ProgramList &destination, const QString &where, const QString &groupBy, const QString &orderBy, const MSqlBindings &bindings, const ProgramList &schedList)
static const std::array< const QString, ProgramInfo::kNumCatTypes > kCatName
static const char * from_recordedseek_mark_asc
uint propsValueFromString(const QString &name, const QMap< T, QString > &propNames, const QString &props)
static constexpr int64_t kLastUpdateOffset
bool qstringEqualOrDefault(const QString &a, const QString &b)
static constexpr uint kInvalidDateTime
static void delete_markup_datum(MarkTypes type, uint chanid, const QDateTime &recstartts)
static QDate DateFromListItem(const QString &str)
static ProgramInfoType discover_program_info_type(uint chanid, const QString &pathname, bool use_remote)
int pginfo_init_statics()
static const char * from_filemarkup_offset_asc
static uint load_markup_datum(MarkTypes type, uint chanid, const QDateTime &recstartts)
static const char * from_recordedseek_offset_asc
QString propsValueToString(const QString &name, QMap< T, QString > propNames, T props)
static bool FromProgramQuery(const QString &sql, const MSqlBindings &bindings, MSqlQuery &query, const uint start, const uint limit, uint &count, ProgGroupBy::Type groupBy)
static const char * from_filemarkup_mark_asc
bool LoadFromScheduler(AutoDeleteDeque< TYPE * > &destination, bool &hasConflicts, const QString &altTable="", int recordid=-1)
const QString kTranscoderInUseID
const QString kPlayerInUseID
const QString kPreviewGeneratorInUseID
const QString kImportRecorderInUseID
const QString kJobQueueInUseID
const QString kPBPPlayerInUseID
const QString kFlaggerInUseID
const QString kFileTransferInUseID
const QString kRecorderInUseID
const QString kPIPPlayerInUseID
const QString kTruncatingDeleteInUseID
QMap< uint64_t, MarkTypes > frm_dir_map_t
Frame # -> Mark map.
@ kProgramInfoTypeVideoStreamingRTSP
@ kProgramInfoTypeVideoDVD
@ kProgramInfoTypeRecording
@ kProgramInfoTypeVideoStreamingHTML
@ kProgramInfoTypeVideoFile
@ kProgramInfoTypeVideoBD
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
@ TRANSCODING_NOT_TRANSCODED
static eu8 clamp(eu8 value, eu8 low, eu8 high)
QChar toQChar(RecordingType rectype)
Converts "rectype" into a human readable character.