34#define LOC QString("ProgramInfo(%1): ").arg(GetBasename())
47#define DEFINE_FLAGS_NAMES
49#undef DEFINE_FLAGS_NAMES
52 "SELECT r.title, r.subtitle, r.description, "
53 " r.season, r.episode, r.category, "
54 " r.chanid, c.channum, c.callsign, "
55 " c.name, c.outputfilters,r.recgroup, "
56 " r.playgroup, r.storagegroup, r.basename, "
57 " r.hostname, r.recpriority, r.seriesid, "
58 " r.programid, r.inetref, r.filesize, "
59 " r.progstart, r.progend, r.stars, "
60 " r.starttime, r.endtime, p.airdate+0, "
61 " r.originalairdate, r.lastmodified, r.recordid, "
62 " c.commmethod, r.commflagged, r.previouslyshown, "
63 " r.transcoder, r.transcoded, r.deletepending, "
64 " r.preserve, r.cutlist, r.autoexpire, "
65 " r.editing, r.bookmark, r.watched, "
66 " p.audioprop+0, p.videoprop+0, p.subtitletypes+0, "
67 " r.findid, rec.dupin, rec.dupmethod, "
68 " p.syndicatedepisodenumber, p.partnumber, p.parttotal, "
69 " p.season, p.episode, p.totalepisodes, "
70 " p.category_type, r.recordedid, r.inputname, "
71 " r.bookmarkupdate, r.lastplay "
73 "LEFT JOIN channel AS c "
74 "ON (r.chanid = c.chanid) "
75 "LEFT JOIN recordedprogram AS p "
76 "ON (r.chanid = p.chanid AND "
77 " r.progstart = p.starttime) "
78 "LEFT JOIN record AS rec "
79 "ON (r.recordid = rec.recordid) ";
81static void set_flag(uint32_t &flags,
int flag_to_set,
bool is_set)
83 flags &= ~flag_to_set;
92 if (!url.startsWith(
"dvd:") && !url.startsWith(
"bd:"))
94 if(url.endsWith(
".img", Qt::CaseInsensitive) ||
95 url.endsWith(
".iso", Qt::CaseInsensitive))
100 result =
"bd:" + url;
104 result =
"dvd:" + url;
114 if (QDir(url +
"/BDMV").
exists())
115 result =
"bd:" + url;
116 else if (QDir(url +
"/VIDEO_TS").
exists())
117 result =
"dvd:" + url;
124static const std::array<const QString,ProgramInfo::kNumCatTypes>
kCatName
125{
"",
"movie",
"series",
"sports",
"tvshow" };
138 for (
size_t i = 1; i <
kCatName.size(); i++)
148 m_title(other.m_title),
149 m_sortTitle(other.m_sortTitle),
150 m_subtitle(other.m_subtitle),
151 m_sortSubtitle(other.m_sortSubtitle),
152 m_description(other.m_description),
153 m_season(other.m_season),
154 m_episode(other.m_episode),
155 m_totalEpisodes(other.m_totalEpisodes),
156 m_syndicatedEpisode(other.m_syndicatedEpisode),
157 m_category(other.m_category),
158 m_director(other.m_director),
160 m_recPriority(other.m_recPriority),
162 m_chanId(other.m_chanId),
163 m_chanStr(other.m_chanStr),
164 m_chanSign(other.m_chanSign),
165 m_chanName(other.m_chanName),
166 m_chanPlaybackFilters(other.m_chanPlaybackFilters),
168 m_recGroup(other.m_recGroup),
169 m_playGroup(other.m_playGroup),
171 m_pathname(other.m_pathname),
173 m_hostname(other.m_hostname),
174 m_storageGroup(other.m_storageGroup),
176 m_seriesId(other.m_seriesId),
177 m_programId(other.m_programId),
178 m_inetRef(other.m_inetRef),
179 m_catType(other.m_catType),
181 m_fileSize(other.m_fileSize),
183 m_startTs(other.m_startTs),
184 m_endTs(other.m_endTs),
185 m_recStartTs(other.m_recStartTs),
186 m_recEndTs(other.m_recEndTs),
188 m_stars(other.m_stars),
190 m_originalAirDate(other.m_originalAirDate),
191 m_lastModified(other.m_lastModified),
194 m_recPriority2(other.m_recPriority2),
195 m_recordId(other.m_recordId),
196 m_parentId(other.m_parentId),
198 m_sourceId(other.m_sourceId),
199 m_inputId(other.m_inputId),
201 m_findId(other.m_findId),
202 m_programFlags(other.m_programFlags),
203 m_videoProperties(other.m_videoProperties),
204 m_audioProperties(other.m_audioProperties),
205 m_subtitleProperties(other.m_subtitleProperties),
206 m_year(other.m_year),
207 m_partNumber(other.m_partNumber),
208 m_partTotal(other.m_partTotal),
210 m_recStatus(other.m_recStatus),
211 m_recType(other.m_recType),
212 m_dupIn(other.m_dupIn),
213 m_dupMethod(other.m_dupMethod),
215 m_recordedId(other.m_recordedId),
216 m_inputName(other.m_inputName),
217 m_bookmarkUpdate(other.m_bookmarkUpdate),
220 m_availableStatus(other.m_availableStatus),
221 m_spread(other.m_spread),
222 m_startCol(other.m_startCol),
225 m_positionMapDBReplacement(other.m_positionMapDBReplacement)
239 "SELECT chanid, starttime "
241 "WHERE recordedid = :RECORDEDID");
242 query.
bindValue(
":RECORDEDID", _recordedid);
252 LOG(VB_GENERAL, LOG_CRIT,
LOC +
253 QString(
"Failed to find recorded entry for %1.")
280 QString _sortSubtitle,
281 QString _description,
285 QString _syndicatedepisode,
292 QString _chanplaybackfilters,
297 const QString &_pathname,
300 QString _storagegroup,
313 QDateTime _recstartts,
321 QDate _originalAirDate,
322 QDateTime _lastmodified,
334 uint _audioproperties,
335 uint _videoproperties,
338 QDateTime _bookmarkupdate) :
339 m_title(std::move(_title)),
340 m_sortTitle(std::move(_sortTitle)),
341 m_subtitle(std::move(_subtitle)),
342 m_sortSubtitle(std::move(_sortSubtitle)),
343 m_description(std::move(_description)),
346 m_totalEpisodes(_totalepisodes),
347 m_syndicatedEpisode(std::move(_syndicatedepisode)),
348 m_category(std::move(_category)),
350 m_recPriority(_recpriority),
353 m_chanStr(std::move(_channum)),
354 m_chanSign(std::move(_chansign)),
355 m_chanName(std::move(_channame)),
356 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
358 m_recGroup(std::move(_recgroup)),
359 m_playGroup(std::move(_playgroup)),
361 m_pathname(_pathname),
363 m_hostname(std::move(_hostname)),
364 m_storageGroup(std::move(_storagegroup)),
366 m_seriesId(std::move(_seriesid)),
367 m_programId(std::move(_programid)),
368 m_inetRef(std::move(_inetref)),
371 m_fileSize(_filesize),
373 m_startTs(std::move(_startts)),
374 m_endTs(std::move(_endts)),
375 m_recStartTs(std::move(_recstartts)),
376 m_recEndTs(std::move(_recendts)),
378 m_stars(std::
clamp(_stars, 0.0F, 1.0F)),
380 m_originalAirDate(_originalAirDate),
381 m_lastModified(std::move(_lastmodified)),
384 m_recordId(_recordid),
387 m_programFlags(_programflags),
388 m_videoProperties(_videoproperties),
389 m_audioProperties(_audioproperties),
390 m_subtitleProperties(_subtitleType),
392 m_partNumber(_partnumber),
393 m_partTotal(_parttotal),
395 m_recStatus(_recstatus),
397 m_dupMethod(_dupmethod),
399 m_recordedId(_recordedid),
400 m_inputName(std::move(_inputname)),
401 m_bookmarkUpdate(std::move(_bookmarkupdate))
417 QString _sortSubtitle,
418 QString _description,
434 QDateTime _recstartts,
446 m_title(std::move(_title)),
447 m_sortTitle(std::move(_sortTitle)),
448 m_subtitle(std::move(_subtitle)),
449 m_sortSubtitle(std::move(_sortSubtitle)),
450 m_description(std::move(_description)),
453 m_category(std::move(_category)),
456 m_chanStr(std::move(_channum)),
457 m_chanSign(std::move(_chansign)),
458 m_chanName(std::move(_channame)),
460 m_seriesId(std::move(_seriesid)),
461 m_programId(std::move(_programid)),
462 m_inetRef(std::move(_inetref)),
464 m_startTs(std::move(_startts)),
465 m_endTs(std::move(_endts)),
466 m_recStartTs(std::move(_recstartts)),
467 m_recEndTs(std::move(_recendts)),
469 m_lastModified(m_startTs),
472 m_recordId(_recordid),
475 m_programFlags(duplicate ? FL_DUPLICATE : FL_NONE),
477 m_recStatus(_recstatus),
492 QString _sortSubtitle,
493 QString _description,
494 QString _syndicatedepisode,
501 QString _chanplaybackfilters,
505 QDateTime _recstartts,
517 QDate _originalAirDate,
526 uint _videoproperties,
527 uint _audioproperties,
535 m_title(std::move(_title)),
536 m_sortTitle(std::move(_sortTitle)),
537 m_subtitle(std::move(_subtitle)),
538 m_sortSubtitle(std::move(_sortSubtitle)),
539 m_description(std::move(_description)),
542 m_totalEpisodes(_totalepisodes),
543 m_syndicatedEpisode(std::move(_syndicatedepisode)),
544 m_category(std::move(_category)),
547 m_chanStr(std::move(_channum)),
548 m_chanSign(std::move(_chansign)),
549 m_chanName(std::move(_channame)),
550 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
552 m_seriesId(std::move(_seriesid)),
553 m_programId(std::move(_programid)),
556 m_startTs(std::move(_startts)),
557 m_endTs(std::move(_endts)),
558 m_recStartTs(std::move(_recstartts)),
559 m_recEndTs(std::move(_recendts)),
561 m_stars(std::
clamp(_stars, 0.0F, 1.0F)),
563 m_originalAirDate(_originalAirDate),
564 m_lastModified(m_startTs),
565 m_lastInUseTime(m_startTs.addSecs(-kLastInUseOffset)),
567 m_recordId(_recordid),
570 m_videoProperties(_videoproperties),
571 m_audioProperties(_audioproperties),
572 m_subtitleProperties(_subtitleType),
574 m_partNumber(_partnumber),
575 m_partTotal(_parttotal),
577 m_recStatus(_recstatus),
586 for (
auto *it : schedList)
636 QString _sortSubtitle,
637 QString _description,
647 QString _chanplaybackfilters,
654 QDateTime _recstartts,
660 QString _inputname) :
661 m_title(std::move(_title)),
662 m_sortTitle(std::move(_sortTitle)),
663 m_subtitle(std::move(_subtitle)),
664 m_sortSubtitle(std::move(_sortSubtitle)),
665 m_description(std::move(_description)),
668 m_totalEpisodes(_totalepisodes),
669 m_category(std::move(_category)),
672 m_chanStr(std::move(_channum)),
673 m_chanSign(std::move(_chansign)),
674 m_chanName(std::move(_channame)),
675 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
677 m_recGroup(std::move(_recgroup)),
678 m_playGroup(std::move(_playgroup)),
680 m_seriesId(std::move(_seriesid)),
681 m_programId(std::move(_programid)),
682 m_inetRef(std::move(_inetref)),
684 m_startTs(std::move(_startts)),
685 m_endTs(std::move(_endts)),
686 m_recStartTs(std::move(_recstartts)),
687 m_recEndTs(std::move(_recendts)),
690 m_lastInUseTime(m_lastModified.addSecs(-kLastInUseOffset)),
692 m_inputName(std::move(_inputname))
703 if (_pathname.isEmpty())
709 QDateTime _recstartts;
723 QString basename = _pathname.section(
'/', -1);
724 if (_pathname == basename)
725 SetPathname(QDir::currentPath() +
'/' + _pathname);
726 else if (_pathname.contains(
"./") && !_pathname.contains(
":"))
727 SetPathname(QFileInfo(_pathname).absoluteFilePath());
737 const QString &_plot,
738 const QString &_title,
739 const QString &_sortTitle,
740 const QString &_subtitle,
741 const QString &_sortSubtitle,
742 const QString &_director,
743 int _season,
int _episode,
744 const QString &_inetref,
745 std::chrono::minutes length_in_minutes,
747 const QString &_programid)
767 int64_t minutes = length_in_minutes.count();
770#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
774 QTimeZone(QTimeZone::UTC));
778 QString pn = _pathname;
779 if (!_pathname.startsWith(
"myth://"))
790 const QDateTime &_startts,
791 const QDateTime &_endts)
797 "SELECT chanid, channum, callsign, name, outputfilters, commmethod "
799 "WHERE chanid=:CHANID");
818 QString channelFormat =
826 QString(
"%1 (%2)").arg(
m_title, QObject::tr(
"Manual Record"));
844 bool ignore_non_serialized_data)
872 if (!ignore_non_serialized_data || !is_same ||
928 if (!ignore_non_serialized_data)
1034 if (a.isEmpty() and (b ==
"Default"))
1036 if ((a ==
"Default") and b.isEmpty())
1176 uint chanid,
const QDateTime &recstartts)
1178 return QString(
"%1_%2").arg(chanid).arg(recstartts.toString(
Qt::ISODate));
1185 uint &chanid, QDateTime &recstartts)
1187 QStringList keyParts = uniquekey.split(
'_');
1188 if (keyParts.size() != 2)
1190 chanid = keyParts[0].toUInt();
1192 return (chanid != 0U) && recstartts.isValid();
1196 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1198 QString basename = pathname.section(
'/', -1);
1199 if (basename.isEmpty())
1202 QStringList lr = basename.split(
"_");
1205 chanid = lr[0].toUInt();
1206 QStringList ts = lr[1].split(
".");
1207 if (chanid && !ts.empty())
1210 return recstartts.isValid();
1218 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1220 QString basename = pathname.section(
'/', -1);
1221 if (basename.isEmpty())
1226 "SELECT chanid, starttime "
1228 "WHERE basename = :BASENAME");
1232 chanid = query.
value(0).toUInt();
1243 QString basename = pathname.section(
'/', -1);
1244 if (basename.isEmpty())
1249 "SELECT recordedid "
1251 "WHERE basename = :BASENAME");
1255 recordedid = query.
value(0).toUInt();
1264 return QString::number(x.toSecsSinceEpoch());
1279 list << QString::number(
m_season );
1303 list << QString::number(
m_dupIn);
1315 list << QString(
"%1").arg(
m_stars);
1325 list << QString::number(
m_year);
1339#define NEXT_STR() do { if (it == listend) \
1341 LOG(VB_GENERAL, LOG_ERR, listerror); \
1345 ts = *it++; } while (false)
1356 if (str.isEmpty() || (str ==
"0000-00-00"))
1374 const QStringList::const_iterator& listend)
1376 QString listerror =
LOC +
"FromStringList, not enough items in list.";
1440 if (!origChanid || !origRecstartts.isValid() ||
1455template <
typename T>
1460 return propNames[0];
1463 for (
uint i = 0; i < (
sizeof(T)*8) - 1; ++i)
1466 if ((props & bit) == 0)
1468 if (propNames.contains(bit))
1470 result += propNames[bit];
1474 if (bit & FL_TYPEMASK)
1476 QString tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1477 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1481 return result.join(
'|');
1484template <
typename T>
1486 const QString& props)
1488 if (props.isEmpty())
1493 QStringList names = props.split(
'|');
1494 for (
const auto& n : std::as_const(names) )
1496 uint bit = propNames.key(n, 0);
1499 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1537 tmp_rec += QObject::tr(
"Re-Record");
1592 uint date_format)
const
1597 QString channelFormat =
1599 QString longChannelFormat =
1609 QString tempSubTitle =
m_title;
1613 tempSubTitle = QString(
"%1 - \"%2\"")
1615 tempSortSubtitle = QString(
"%1 - \"%2\"")
1619 progMap[
"titlesubtitle"] = tempSubTitle;
1620 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1622 progMap[
"description"] = progMap[
"description0"]
1626 progMap[
"season"] = progMap[
"episode"] =
"";
1627 progMap[
"totalepisodes"] =
"";
1628 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1631 progMap[
"seasonepisode"] =
"";
1640 progMap[
"s00e00"] = QString(
"s%1e%2")
1643 progMap[
"00x00"] = QString(
"%1x%2")
1647 if (progMap[
"seasonepisode"].isEmpty())
1649 progMap[
"seasonepisode"] = QString(
"s%1e%2")
1658 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1662 progMap[
"starttime"] =
"";
1663 progMap[
"startdate"] =
"";
1664 progMap[
"endtime"] =
"";
1665 progMap[
"enddate"] =
"";
1666 progMap[
"recstarttime"] =
"";
1667 progMap[
"recstartdate"] =
"";
1668 progMap[
"recendtime"] =
"";
1669 progMap[
"recenddate"] =
"";
1673 progMap[
"startdate"] =
"";
1674 progMap[
"recstartdate"] =
"";
1678 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1679 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1686 progMap[
"startdate"] =
1696 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1697 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1698 if (timeNow.toLocalTime().date().year() !=
1700 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1701 if (timeNow.toLocalTime().date().year() !=
1702 m_endTs.toLocalTime().date().year())
1703 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1707 progMap[
"timedate"] =
1711 progMap[
"shorttimedate"] =
1715 progMap[
"starttimedate"] =
1718 progMap[
"shortstarttimedate"] =
1722 progMap[
"lastmodifieddate"] =
1724 progMap[
"lastmodified"] =
1731 progMap[
"chanid"] = QString::number(
m_chanId);
1734 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1736 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1737 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1739 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1742 int minutes = seconds / 60;
1744 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1746 progMap[
"lenmins"] = min_str;
1747 int hours = minutes / 60;
1748 minutes = minutes % 60;
1750 progMap[
"lentime"] = min_str;
1751 if (hours > 0 && minutes > 0)
1753 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1754 progMap[
"lentime"] = QString(
"%1 %2")
1755 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1759 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1762 progMap[
"recordedpercent"] =
1765 progMap[
"watchedpercent"] =
1783 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1789 progMap[
"storagegroup"] = QObject::tr(
"Default");
1796 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1820 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1821 progMap[
"longrepeat"] = progMap[
"repeat"];
1824 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1825 .arg(QObject::tr(
"Repeat"),
1833 progMap[
"repeat"] =
"";
1834 progMap[
"longrepeat"] =
"";
1842 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1847 QString star_str = (
m_stars != 0.0F) ?
1848 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1849 progMap[
"stars"] = star_str;
1850 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1853 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1855 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1857 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1859 progMap[
"yearstars"] =
"";
1864 progMap[
"originalairdate"] =
"";
1865 progMap[
"shortoriginalairdate"] =
"";
1879 QString mediaTypeString;
1883 mediaType =
"video";
1884 mediaTypeString = QObject::tr(
"Video");
1888 mediaTypeString = QObject::tr(
"DVD");
1891 mediaType =
"httpstream";
1892 mediaTypeString = QObject::tr(
"HTTP Streaming");
1895 mediaType =
"rtspstream";
1896 mediaTypeString = QObject::tr(
"RTSP Streaming");
1899 mediaType =
"bluraydisc";
1900 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1904 mediaType =
"recording";
1905 mediaTypeString = QObject::tr(
"Recording",
1906 "Recorded file, object not action");
1908 progMap[
"mediatype"] = mediaType;
1909 progMap[
"mediatypestring"] = mediaTypeString;
1917 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1929 uint64_t last_frame = 0;
1938 if (!posMap.empty())
1940 frm_pos_map_t::const_iterator it = posMap.constEnd();
1942 last_frame = it.key();
1949 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1976 str +=
" startts(" +
1979 ") recendts(" +
m_recEndTs.toString() +
")\n";
1980 str +=
" title(" +
m_title +
")";
1988 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1993 str = QString(
"%1 at %2")
1997 str = QString(
"%1 @ %2")
2020 const uint _chanid,
const QDateTime &_recstartts)
2022 if (!_chanid || !_recstartts.isValid())
2031 "WHERE r.chanid = :CHANID AND "
2032 " r.starttime = :RECSTARTTS");
2034 query.
bindValue(
":RECSTARTTS", _recstartts);
2087 if (!query.
value(7).toString().isEmpty())
2101 QString new_basename = query.
value(14).toString();
2102 if ((
GetBasename() != new_basename) || !is_reload)
2106 LOG(VB_FILE, LOG_INFO,
LOC +
2107 QString(
"Updated pathname '%1':'%2' -> '%3'")
2243 if (index == oindex && (index < 0 ||
2302 if (index == oindex && (index < 0 ||
2397 QMap<QString, int> authMap;
2398 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2401 for (
const QString& table : tables)
2404 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2405 "FROM %1 WHERE programid <> ''").arg(table));
2412 while (query.
next())
2413 authMap[query.
value(0).toString()] = 1;
2417 int numAuths = authMap.count();
2418 LOG(VB_GENERAL, LOG_INFO,
2419 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2432 QString retval = QString(
"%1_%2.%3")
2433 .arg(QString::number(
m_chanId), starts, ext);
2439 uint chanid,
const QString &pathname,
bool use_remote)
2441 QString fn_lower = pathname.toLower();
2447 else if (fn_lower.startsWith(
"http:"))
2451 else if (fn_lower.startsWith(
"rtsp:"))
2459 if (fn_lower.startsWith(
"dvd:"))
2463 else if (fn_lower.startsWith(
"bd:"))
2467 else if (use_remote && fn_lower.startsWith(
"myth://"))
2469 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2470 QString tmpFileBD = pathname +
"/BDMV";
2498 LOG(VB_GUI, LOG_INFO,
2513 query.
prepare(
"UPDATE recorded "
2514 "SET basename = :BASENAME "
2515 "WHERE recordedid = :RECORDEDID;");
2525 query.
prepare(
"UPDATE recordedfile "
2526 "SET basename = :BASENAME "
2527 "WHERE recordedid = :RECORDEDID;");
2559 "FROM recordedfile "
2560 "WHERE recordedid = :RECORDEDID;");
2567 else if (query.
next())
2569 return query.
value(0).toString();
2573 LOG(VB_GENERAL, LOG_INFO,
2574 QString(
"QueryBasename found no entry for recording ID %1")
2589 bool checkMaster,
bool forceCheckLocal)
2596 if (basename.isEmpty())
2605 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2608 QUrl url = QUrl(fullpath);
2609 QString path = url.path();
2610 QString host = url.toString(QUrl::RemovePath).mid(7);
2611 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2615 list = host.split(
"@", Qt::SkipEmptyParts);
2617 if (!list.empty() && list.size() < 3)
2619 host = list.size() == 1 ? list[0] : list[1];
2620 group = list.size() == 1 ? QString() : list[0];
2623 if (!local.isEmpty() && sg.
FileExists(local))
2636 LOG(VB_FILE, LOG_DEBUG,
LOC +
2637 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2639 tmpURL = sgroup.
FindFile(basename);
2641 if (!tmpURL.isEmpty())
2643 LOG(VB_FILE, LOG_INFO,
LOC +
2644 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2649 LOG(VB_GENERAL, LOG_ERR,
LOC +
2650 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2651 "not be found.").arg(basename));
2654 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2668 LOG(VB_FILE, LOG_INFO,
LOC +
2669 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2678 LOG(VB_FILE, LOG_INFO,
LOC +
2679 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2693 query.
prepare(
"SELECT mplexid FROM channel "
2694 "WHERE chanid = :CHANID");
2699 else if (query.
next())
2700 ret = query.
value(0).toUInt();
2703 ret = (32767 == ret) ? 0 : ret;
2715 bool is_valid = (frame > 0);
2736 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2737 " bookmark = :BOOKMARKFLAG "
2738 "WHERE recordedid = :RECORDEDID");
2740 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2752 bool isValid = frame > 0;
2777 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2778 " lastplay = :LASTPLAYFLAG "
2779 "WHERE recordedid = :RECORDEDID");
2781 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2812 "SELECT bookmarkupdate "
2814 "WHERE chanid = :CHANID AND"
2815 " starttime = :STARTTIME");
2823 else if (query.
next())
2843 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2853 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2870 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2887 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2895 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2902 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2909 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2916 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2920 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2930 const QString &serialid)
const
2932 QStringList fields = QStringList();
2937 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2938 " FROM dvdbookmark "
2939 " WHERE serialid = :SERIALID ");
2944 QString dvdstate = query.
value(0).toString();
2946 if (!dvdstate.isEmpty())
2948 fields.append(dvdstate);
2954 for(
int i = 1; i < 5; i++)
2955 fields.append(query.
value(i).toString());
2965 QStringList::const_iterator it = fields.begin();
2968 QString serialid = *it;
2969 QString name = *(++it);
2971 if( fields.count() == 3 )
2974 QString state = *(++it);
2976 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2978 " VALUES ( :SERIALID, :NAME );");
2985 query.
prepare(
" UPDATE dvdbookmark "
2986 " SET dvdstate = :STATE , "
2987 " timestamp = NOW() "
2988 " WHERE serialid = :SERIALID");
2995 query.
prepare(
"DELETE FROM dvdbookmark "
2996 "WHERE serialid = :SERIALID");
3009 QStringList fields = QStringList();
3014 query.
prepare(
" SELECT bdstate FROM bdbookmark "
3015 " WHERE serialid = :SERIALID ");
3019 fields.append(query.
value(0).toString());
3027 QStringList::const_iterator it = fields.begin();
3030 QString serialid = *it;
3031 QString name = *(++it);
3033 if( fields.count() == 3 )
3036 QString state = *(++it);
3038 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
3040 " VALUES ( :SERIALID, :NAME );");
3047 query.
prepare(
" UPDATE bdbookmark "
3048 " SET bdstate = :STATE , "
3049 " timestamp = NOW() "
3050 " WHERE serialid = :SERIALID");
3057 query.
prepare(
"DELETE FROM bdbookmark "
3058 "WHERE serialid = :SERIALID");
3077 query.
prepare(
" SELECT category_type "
3078 " FROM recordedprogram "
3079 " WHERE chanid = :CHANID "
3080 " AND starttime = :STARTTIME;");
3100 query.
prepare(
"UPDATE recorded"
3101 " SET watched = :WATCHEDFLAG"
3102 " WHERE chanid = :CHANID"
3103 " AND starttime = :STARTTIME ;");
3106 query.
bindValue(
":WATCHEDFLAG", watched);
3118 if (url.startsWith(
"myth://"))
3120 url = QUrl(url).path();
3125 query.
prepare(
"UPDATE videometadata"
3126 " SET watched = :WATCHEDFLAG"
3127 " WHERE title = :TITLE"
3128 " AND subtitle = :SUBTITLE"
3129 " AND filename = :FILENAME ;");
3133 query.
bindValue(
":WATCHEDFLAG", watched);
3152 query.
prepare(
"SELECT editing FROM recorded"
3153 " WHERE chanid = :CHANID"
3154 " AND starttime = :STARTTIME ;");
3159 editing = query.
value(0).toBool();
3176 query.
prepare(
"UPDATE recorded"
3177 " SET editing = :EDIT"
3178 " WHERE chanid = :CHANID"
3179 " AND starttime = :STARTTIME ;");
3201 query.
prepare(
"UPDATE recorded"
3202 " SET deletepending = :DELETEFLAG, "
3204 " WHERE chanid = :CHANID"
3205 " AND starttime = :STARTTIME ;");
3208 query.
bindValue(
":DELETEFLAG", deleteFlag);
3233 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3234 " WHERE chanid = :CHANID"
3235 " AND starttime = :STARTTIME "
3236 " AND lastupdatetime > :ONEHOURAGO ;");
3239 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3242 if (query.
exec() && query.
size() > 0)
3246 while (query.
next())
3248 usageStr = QObject::tr(
"Unknown");
3249 recusage = query.
value(1).toString();
3252 usageStr = QObject::tr(
"Playing");
3254 usageStr = QObject::tr(
"PIP");
3256 usageStr = QObject::tr(
"PBP");
3259 usageStr = QObject::tr(
"Recording");
3261 usageStr = QObject::tr(
"File transfer");
3263 usageStr = QObject::tr(
"Delete");
3265 usageStr = QObject::tr(
"Commercial Detection");
3267 usageStr = QObject::tr(
"Transcoding");
3269 usageStr = QObject::tr(
"Preview Generation");
3271 usageStr = QObject::tr(
"User Job");
3273 byWho.push_back(recusage);
3274 byWho.push_back(query.
value(0).toString());
3275 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3293 for (
int i = 0; i+2 < users.size(); i+=3)
3294 byWho += users[i+2] +
"\n";
3321 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3331 (one_playback_allowed && (play_cnt <= 1)));
3333 ok = ok && (ft_cnt == jq_cnt);
3344 query.
prepare(
"SELECT transcoded FROM recorded"
3345 " WHERE chanid = :CHANID"
3346 " AND starttime = :STARTTIME ;");
3366 "SET transcoded = :VALUE "
3367 "WHERE chanid = :CHANID AND"
3368 " starttime = :STARTTIME");
3387 query.
prepare(
"UPDATE recorded"
3388 " SET commflagged = :FLAG"
3389 " WHERE chanid = :CHANID"
3390 " AND starttime = :STARTTIME ;");
3413 query.
prepare(
"UPDATE recorded"
3414 " SET preserve = :PRESERVE"
3415 " WHERE chanid = :CHANID"
3416 " AND starttime = :STARTTIME ;");
3417 query.
bindValue(
":PRESERVE", preserveEpisode);
3440 query.
prepare(
"UPDATE recorded"
3441 " SET autoexpire = :AUTOEXPIRE"
3442 " WHERE chanid = :CHANID"
3443 " AND starttime = :STARTTIME ;");
3450 else if (updateDelete)
3469 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3470 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3473 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3474 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3475 "WHERE recordid = :RECORDID");
3477 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3481 query.
prepare(
"UPDATE record SET last_delete = NULL "
3482 "WHERE recordid = :RECORDID");
3495 query.
prepare(
"SELECT autoexpire FROM recorded"
3496 " WHERE chanid = :CHANID"
3497 " AND starttime = :STARTTIME ;");
3518 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3520 uint64_t frame = i.key();
3526 delMap[frame] = mark;
3536 return !delMap.isEmpty();
3552 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3554 uint64_t frame = i.key();
3563 tmpDelMap[frame] = mark;
3572 query.
prepare(
"UPDATE recorded"
3573 " SET cutlist = :CUTLIST"
3574 " WHERE chanid = :CHANID"
3575 " AND starttime = :STARTTIME ;");
3577 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3606 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3609 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3612 comp += QString(
" AND type = :TYPE ");
3616 query.
prepare(
"DELETE FROM filemarkup"
3617 " WHERE filename = :PATH "
3623 query.
prepare(
"DELETE FROM recordedmarkup"
3624 " WHERE chanid = :CHANID"
3625 " AND STARTTIME = :STARTTIME"
3642 int64_t min_frame, int64_t max_frame)
const
3654 query.
prepare(
"SELECT starttime FROM recorded"
3655 " WHERE chanid = :CHANID"
3656 " AND starttime = :STARTTIME ;");
3671 frm_dir_map_t::const_iterator it;
3672 for (it = marks.begin(); it != marks.end(); ++it)
3674 uint64_t frame = it.key();
3676 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3679 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3686 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3687 " VALUES ( :PATH , :MARK , :TYPE );");
3692 query.
prepare(
"INSERT INTO recordedmarkup"
3693 " (chanid, starttime, mark, type)"
3694 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3698 query.
bindValue(
":MARK", (quint64)frame);
3715 marks,
type, merge);
3724 const QString &video_pathname,
3733 query.
prepare(
"SELECT mark, type, `offset` "
3735 "WHERE filename = :PATH AND "
3738 query.
bindValue(
":PATH", video_pathname);
3747 while (query.
next())
3751 int entryType = query.
value(1).toInt();
3761 uint chanid,
const QDateTime &recstartts,
3769 query.
prepare(
"SELECT mark, type, data "
3770 "FROM recordedmarkup "
3771 "WHERE chanid = :CHANID AND "
3772 " starttime = :STARTTIME AND"
3776 query.
bindValue(
":STARTTIME", recstartts);
3785 while (query.
next())
3789 int entryType = query.
value(1).toInt();
3804 return flagMap.contains(0);
3832 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3833 " WHERE filename = :PATH"
3834 " AND type = :TYPE ;");
3839 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3840 " WHERE chanid = :CHANID"
3841 " AND starttime = :STARTTIME"
3842 " AND type = :TYPE ;");
3858 while (query.
next())
3859 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3875 query.
prepare(
"DELETE FROM filemarkup"
3876 " WHERE filename = :PATH"
3877 " AND type = :TYPE ;");
3882 query.
prepare(
"DELETE FROM recordedseek"
3883 " WHERE chanid = :CHANID"
3884 " AND starttime = :STARTTIME"
3885 " AND type = :TYPE ;");
3902 int64_t min_frame, int64_t max_frame)
const
3908 if ((min_frame >= 0) || (max_frame >= 0))
3916 uint64_t frame = it.key();
3917 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3919 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3921 new_map.insert(it.key(), *it);
3931 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3933 uint64_t frame = it.key();
3934 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3936 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3940 .insert(frame, *it);
3950 comp +=
" AND mark >= :MIN_FRAME ";
3952 comp +=
" AND mark <= :MAX_FRAME ";
3959 query.
prepare(
"DELETE FROM filemarkup"
3960 " WHERE filename = :PATH"
3967 query.
prepare(
"DELETE FROM recordedseek"
3968 " WHERE chanid = :CHANID"
3969 " AND starttime = :STARTTIME"
3982 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3984 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3989 if (posMap.isEmpty())
3993 QStringList q(
"INSERT INTO ");
3997 q <<
"filemarkup (filename, type, mark, `offset`)";
3998 qfields = QString(
"('%1',%2,") .
4005 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4006 qfields = QString(
"(%1,'%2',%3,") .
4013 bool add_comma =
false;
4014 frm_pos_map_t::iterator it;
4015 for (it = posMap.begin(); it != posMap.end(); ++it)
4017 uint64_t frame = it.key();
4019 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
4022 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
4025 uint64_t offset = *it;
4035 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4047 if (posMap.isEmpty())
4054 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4061 QStringList q(
"INSERT INTO ");
4065 q <<
"filemarkup (filename, type, mark, `offset`)";
4066 qfields = QString(
"('%1',%2,") .
4073 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4074 qfields = QString(
"(%1,'%2',%3,") .
4085 bool add_comma =
false;
4086 frm_pos_map_t::iterator it;
4087 for (it = posMap.begin(); it != posMap.end(); ++it)
4089 uint64_t frame = it.key();
4090 uint64_t offset = *it;
4100 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4112 "SELECT mark, `offset` FROM filemarkup"
4113 " WHERE filename = :PATH"
4115 " AND mark >= :QUERY_ARG"
4116 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4118 "SELECT mark, `offset` FROM filemarkup"
4119 " WHERE filename = :PATH"
4121 " AND mark <= :QUERY_ARG"
4122 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4124 "SELECT mark, `offset` FROM recordedseek"
4125 " WHERE chanid = :CHANID"
4126 " AND starttime = :STARTTIME"
4128 " AND mark >= :QUERY_ARG"
4129 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4131 "SELECT mark, `offset` FROM recordedseek"
4132 " WHERE chanid = :CHANID"
4133 " AND starttime = :STARTTIME"
4135 " AND mark <= :QUERY_ARG"
4136 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4138 "SELECT `offset`,mark FROM filemarkup"
4139 " WHERE filename = :PATH"
4141 " AND `offset` >= :QUERY_ARG"
4142 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4144 "SELECT `offset`,mark FROM filemarkup"
4145 " WHERE filename = :PATH"
4147 " AND `offset` <= :QUERY_ARG"
4148 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4150 "SELECT `offset`,mark FROM recordedseek"
4151 " WHERE chanid = :CHANID"
4152 " AND starttime = :STARTTIME"
4154 " AND `offset` >= :QUERY_ARG"
4155 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4157 "SELECT `offset`,mark FROM recordedseek"
4158 " WHERE chanid = :CHANID"
4159 " AND starttime = :STARTTIME"
4161 " AND `offset` <= :QUERY_ARG"
4162 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4165 uint64_t position_or_keyframe,
4168 const char *from_filemarkup_asc,
4169 const char *from_filemarkup_desc,
4170 const char *from_recordedseek_asc,
4171 const char *from_recordedseek_desc)
const
4178 query.
prepare(from_filemarkup_desc);
4180 query.
prepare(from_filemarkup_asc);
4186 query.
prepare(from_recordedseek_desc);
4188 query.
prepare(from_recordedseek_asc);
4193 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4203 *result = query.
value(1).toULongLong();
4210 query.
prepare(from_filemarkup_asc);
4212 query.
prepare(from_filemarkup_desc);
4218 query.
prepare(from_recordedseek_asc);
4220 query.
prepare(from_recordedseek_desc);
4225 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4235 *result = query.
value(1).toULongLong();
4244 bool backwards)
const
4253 bool backwards)
const
4262 bool backwards)
const
4271 bool backwards)
const
4291 query.
prepare(
"INSERT INTO recordedmarkup"
4292 " (chanid, starttime, mark, type, data)"
4294 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4298 query.
bindValue(
":MARK", (quint64)frame);
4308#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4309 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4311 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4329 query.
prepare(
"INSERT INTO recordedmarkup"
4330 " (chanid, starttime, mark, type, data)"
4332 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4335 query.
bindValue(
":MARK", (quint64)frame);
4354 query.
prepare(
"INSERT INTO recordedmarkup"
4355 " (chanid, starttime, mark, type, data)"
4357 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4360 query.
bindValue(
":MARK", (quint64)frame);
4374 query.
prepare(
"DELETE FROM recordedmarkup "
4375 " WHERE chanid=:CHANID "
4376 " AND starttime=:STARTTIME "
4379 query.
bindValue(
":STARTTIME", recstartts);
4392 query.
prepare(
"DELETE FROM filemarkup"
4393 " WHERE filename = :PATH "
4394 " AND type = :TYPE ;");
4408 query.
prepare(
"DELETE FROM filemarkup"
4409 " WHERE filename = :PATH "
4410 " AND mark = :MARK "
4411 " AND type = :TYPE ;");
4425 query.
prepare(
"INSERT INTO filemarkup"
4426 " (filename, mark, type, `offset`)"
4428 " ( :PATH , :MARK , :TYPE, :OFFSET );");
4443 query.
prepare(
"INSERT INTO recordedmarkup"
4444 " (chanid, starttime, mark, type, data)"
4446 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4448 query.
bindValue(
":STARTTIME", recstartts);
4505 query.
prepare(
"INSERT INTO recordedmarkup"
4506 " (chanid, starttime, mark, type, data)"
4508 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4511 query.
bindValue(
":MARK", (quint64)frame);
4518 query.
prepare(
"INSERT INTO recordedmarkup"
4519 " (chanid, starttime, mark, type, data)"
4521 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4524 query.
bindValue(
":MARK", (quint64)frame);
4535 QString qstr = QString(
4536 "SELECT recordedmarkup.data "
4537 "FROM recordedmarkup "
4538 "WHERE recordedmarkup.chanid = :CHANID AND "
4539 " recordedmarkup.starttime = :STARTTIME AND "
4540 " recordedmarkup.type = :TYPE "
4541 "GROUP BY recordedmarkup.data "
4542 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4543 " FROM recordedmarkup AS rm "
4544 " WHERE rm.chanid = recordedmarkup.chanid AND "
4545 " rm.starttime = recordedmarkup.starttime AND "
4546 " rm.type = recordedmarkup.type AND "
4547 " rm.mark > recordedmarkup.mark "
4548 " ORDER BY rm.mark ASC LIMIT 1 "
4549 " ) - recordedmarkup.mark "
4557 query.
bindValue(
":STARTTIME", recstartts);
4565 return (query.
next()) ? query.
value(0).toUInt() : 0;
4571 QString qstr = QString(
4572 "SELECT filemarkup.`offset` "
4574 "WHERE filemarkup.filename = :PATH AND "
4575 " filemarkup.type = :TYPE "
4576 "GROUP BY filemarkup.`offset` "
4577 "ORDER BY SUM( ( SELECT IFNULL(fm.mark, filemarkup.mark)"
4578 " FROM filemarkup AS fm "
4579 " WHERE fm.filename = filemarkup.filename AND "
4580 " fm.type = filemarkup.type AND "
4581 " fm.mark > filemarkup.mark "
4582 " ORDER BY fm.mark ASC LIMIT 1 "
4583 " ) - filemarkup.mark "
4598 return (query.
next()) ? query.
value(0).toUInt() : 0;
4632 query.
prepare(
"SELECT recordedmarkup.type "
4633 "FROM recordedmarkup "
4634 "WHERE recordedmarkup.chanid = :CHANID AND "
4635 " recordedmarkup.starttime = :STARTTIME AND "
4636 " recordedmarkup.type >= :ASPECTSTART AND "
4637 " recordedmarkup.type <= :ASPECTEND "
4638 "GROUP BY recordedmarkup.type "
4639 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4640 " SELECT MAX(rmmax.mark) "
4641 " FROM recordedmarkup AS rmmax "
4642 " WHERE rmmax.chanid = recordedmarkup.chanid "
4643 " AND rmmax.starttime = recordedmarkup.starttime "
4645 " FROM recordedmarkup AS rm "
4646 " WHERE rm.chanid = recordedmarkup.chanid AND "
4647 " rm.starttime = recordedmarkup.starttime AND "
4648 " rm.type >= :ASPECTSTART2 AND "
4649 " rm.type <= :ASPECTEND2 AND "
4650 " rm.mark > recordedmarkup.mark "
4651 " ORDER BY rm.mark ASC LIMIT 1 "
4652 " ) - recordedmarkup.mark "
4723 QVector<MarkupEntry> &mapSeek)
const
4729 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4730 " WHERE filename = :PATH"
4731 " AND type NOT IN (:KEYFRAME,:DURATION)"
4732 " ORDER BY mark, type;");
4739 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4740 " WHERE chanid = :CHANID"
4741 " AND STARTTIME = :STARTTIME"
4742 " ORDER BY mark, type");
4755 while (query.
next())
4758 uint64_t frame = query.
value(1).toLongLong();
4760 bool isDataNull = query.
value(2).isNull();
4762 data = query.
value(2).toLongLong();
4769 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4770 " WHERE filename = :PATH"
4771 " AND type IN (:KEYFRAME,:DURATION)"
4772 " ORDER BY mark, type;");
4779 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4780 " WHERE chanid = :CHANID"
4781 " AND STARTTIME = :STARTTIME"
4782 " ORDER BY mark, type");
4791 while (query.
next())
4794 uint64_t frame = query.
value(1).toLongLong();
4796 bool isDataNull = query.
value(2).isNull();
4798 data = query.
value(2).toLongLong();
4804 const QVector<MarkupEntry> &mapSeek)
const
4810 if (mapMark.isEmpty())
4812 LOG(VB_GENERAL, LOG_INFO,
4813 QString(
"No mark entries in input, "
4814 "not removing marks from DB"));
4818 query.
prepare(
"DELETE FROM filemarkup"
4819 " WHERE filename = :PATH"
4820 " AND type NOT IN (:KEYFRAME,:DURATION)");
4829 for (
const auto& entry : std::as_const(mapMark))
4833 if (entry.isDataNull)
4835 query.
prepare(
"INSERT INTO filemarkup"
4836 " (filename,type,mark)"
4837 " VALUES (:PATH,:TYPE,:MARK)");
4841 query.
prepare(
"INSERT INTO filemarkup"
4842 " (filename,type,mark,`offset`)"
4843 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4844 query.
bindValue(
":OFFSET", (quint64)entry.data);
4848 query.
bindValue(
":MARK", (quint64)entry.frame);
4856 if (mapSeek.isEmpty())
4858 LOG(VB_GENERAL, LOG_INFO,
4859 QString(
"No seek entries in input, "
4860 "not removing marks from DB"));
4864 query.
prepare(
"DELETE FROM filemarkup"
4865 " WHERE filename = :PATH"
4866 " AND type IN (:KEYFRAME,:DURATION)");
4875 for (
int i = 0; i < mapSeek.size(); ++i)
4877 if (i > 0 && (i % 1000 == 0))
4879 LOG(VB_GENERAL, LOG_INFO,
4880 QString(
"Inserted %1 of %2 records")
4881 .arg(i).arg(mapSeek.size()));
4884 query.
prepare(
"INSERT INTO filemarkup"
4885 " (filename,type,mark,`offset`)"
4886 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4901 if (mapMark.isEmpty())
4903 LOG(VB_GENERAL, LOG_INFO,
4904 QString(
"No mark entries in input, "
4905 "not removing marks from DB"));
4909 query.
prepare(
"DELETE FROM recordedmarkup"
4910 " WHERE chanid = :CHANID"
4911 " AND starttime = :STARTTIME");
4919 for (
const auto& entry : std::as_const(mapMark))
4921 if (entry.isDataNull)
4923 query.
prepare(
"INSERT INTO recordedmarkup"
4924 " (chanid,starttime,type,mark)"
4925 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4929 query.
prepare(
"INSERT INTO recordedmarkup"
4930 " (chanid,starttime,type,mark,data)"
4931 " VALUES (:CHANID,:STARTTIME,"
4932 " :TYPE,:MARK,:OFFSET)");
4933 query.
bindValue(
":OFFSET", (quint64)entry.data);
4938 query.
bindValue(
":MARK", (quint64)entry.frame);
4946 if (mapSeek.isEmpty())
4948 LOG(VB_GENERAL, LOG_INFO,
4949 QString(
"No seek entries in input, "
4950 "not removing marks from DB"));
4954 query.
prepare(
"DELETE FROM recordedseek"
4955 " WHERE chanid = :CHANID"
4956 " AND starttime = :STARTTIME");
4964 for (
int i = 0; i < mapSeek.size(); ++i)
4966 if (i > 0 && (i % 1000 == 0))
4968 LOG(VB_GENERAL, LOG_INFO,
4969 QString(
"Inserted %1 of %2 records")
4970 .arg(i).arg(mapSeek.size()));
4973 query.
prepare(
"INSERT INTO recordedseek"
4974 " (chanid,starttime,type,mark,`offset`)"
4975 " VALUES (:CHANID,:STARTTIME,"
4976 " :TYPE,:MARK,:OFFSET)");
4996 LOG(VB_RECORD, LOG_INFO,
4997 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4998 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
5001 "UPDATE recordedprogram "
5002 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
5003 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
5006 query.
bindValue(
":FLAGS", video_property_flags);
5016 videoproperties &= ~mask;
5017 videoproperties |= video_property_flags;
5035 QString chan(format);
5045 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
5065 "SET season = :SEASON, episode = :EPISODE "
5066 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5067 "AND recordid = :RECORDID");
5089 "SET inetref = :INETREF "
5090 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5091 "AND recordid = :RECORDID");
5130 query.
prepare(
"SELECT password FROM recgroups "
5131 "WHERE recgroup = :GROUP");
5135 result = query.
value(0).toString();
5145 query.
prepare(
"SELECT recgroup FROM recorded "
5146 "WHERE chanid = :CHANID AND "
5147 " starttime = :START");
5153 grp = query.
value(0).toString();
5161 query.
prepare(
"SELECT transcoder FROM recorded "
5162 "WHERE chanid = :CHANID AND "
5163 " starttime = :START");
5168 return query.
value(0).toUInt();
5186 if (path.startsWith(
"/"))
5188 QFileInfo testFile(path);
5189 return testFile.path();
5200 if (testFile.exists())
5202 if (testFile.isSymLink())
5205 if (testFile.isFile())
5206 return testFile.path();
5207 if (testFile.isDir())
5208 return testFile.filePath();
5212 testFile.setFile(testFile.absolutePath());
5213 if (testFile.exists())
5215 if (testFile.isSymLink())
5218 if (testFile.isDir())
5219 return testFile.filePath();
5238 bool notifyOfChange =
false;
5244 if (!usedFor.isEmpty())
5250 LOG(VB_GENERAL, LOG_INFO,
LOC +
5251 QString(
"MarkAsInUse(true, '%1'->'%2')")
5253 " -- use has changed");
5257 LOG(VB_GENERAL, LOG_INFO,
LOC +
5258 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5267 .arg(QObject::tr(
"Unknown")).arg(getpid());
5268 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5270 " -- use was not explicitly set");
5273 notifyOfChange =
true;
5278 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5279 QString(
"MarkAsInUse(false, '%1'->'%2')")
5281 " -- use has changed since first setting as in use.");
5286 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5296 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5297 "MarkAsInUse requires a key to delete in use mark");
5305 "DELETE FROM inuseprograms "
5306 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5307 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5332 "FROM inuseprograms "
5333 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5334 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5344 else if (!query.
next())
5346 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5348 else if (query.
value(0).toBool())
5351 "UPDATE inuseprograms "
5352 "SET lastupdatetime = :UPDATETIME "
5353 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5354 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5359 query.
bindValue(
":UPDATETIME", inUseTime);
5369 "INSERT INTO inuseprograms "
5370 " (chanid, starttime, recusage, hostname, "
5371 " lastupdatetime, rechost, recdir) "
5373 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5374 " :UPDATETIME, :RECHOST, :RECDIR)");
5379 query.
bindValue(
":UPDATETIME", inUseTime);
5391 if (!notifyOfChange)
5396 query.
prepare(
"SELECT DISTINCT recusage "
5397 "FROM inuseprograms "
5398 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5399 " chanid = :CHANID AND "
5400 " starttime = :STARTTIME");
5403 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5407 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5408 while (query.
next())
5410 QString inUseForWhat = query.
value(0).toString();
5432 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5433 "FROM channel, capturecard "
5434 "WHERE channel.chanid = :CHANID AND "
5435 " capturecard.sourceid = :SOURCEID AND "
5436 " capturecard.cardid = :INPUTID");
5443 channum = query.
value(0).toString();
5444 input = query.
value(1).toString();
5458 QString rec_profile_names =
5459 QObject::tr(
"Default",
"Recording Profile Default") +
5460 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5461 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5462 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5463 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5464 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5465 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5468 QString rec_profile_groups =
5469 QObject::tr(
"CRC IP Recorders",
5470 "Recording Profile Group Name") +
5471 QObject::tr(
"FireWire Input",
5472 "Recording Profile Group Name") +
5473 QObject::tr(
"Freebox Input",
5474 "Recording Profile Group Name") +
5475 QObject::tr(
"Hardware DVB Encoders",
5476 "Recording Profile Group Name") +
5477 QObject::tr(
"Hardware HDTV",
5478 "Recording Profile Group Name") +
5479 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5480 "Recording Profile Group Name") +
5481 QObject::tr(
"HD-PVR Recorders",
5482 "Recording Profile Group Name") +
5483 QObject::tr(
"HDHomeRun Recorders",
5484 "Recording Profile Group Name") +
5485 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5486 "Recording Profile Group Name") +
5487 QObject::tr(
"Software Encoders (V4L based)",
5488 "Recording Profile Group Name") +
5489 QObject::tr(
"Transcoders",
5490 "Recording Profile Group Name") +
5491 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5492 "Recording Profile Group Name") +
5493 QObject::tr(
"V4L2 Encoders",
5494 "Recording Profile Group Name");
5496 QString display_rec_groups =
5497 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5498 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5499 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5500 QObject::tr(
"Default",
"Recording Group Default") +
5501 QObject::tr(
"Deleted",
"Recording Group Deleted");
5503 QString special_program_groups =
5504 QObject::tr(
"All Programs - %1",
5505 "Show all programs from a specific recording group");
5507 QString storage_groups =
5508 QObject::tr(
"Default",
"Storage Group Name") +
5509 QObject::tr(
"Live TV",
"Storage Group Name") +
5510 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5511 QObject::tr(
"DB Backups",
"Storage Group Name");
5513 QString play_groups =
5514 QObject::tr(
"Default",
"Playback Group Name");
5517 rec_profile_groups.length() +
5518 display_rec_groups.length() +
5519 special_program_groups.length() +
5520 storage_groups.length() +
5521 play_groups.length();
5535 static std::once_flag init_done;
5536 std::call_once(init_done,
init_tr);
5538 QByteArray msg_arr = msg.toLatin1();
5542 QString msg_i18n = QObject::tr(msg_arr.constData());
5543 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5544 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5556 if (pburl.startsWith(
"myth://"))
5558 str.replace(QString(
"%DIR%"), pburl);
5562 QFileInfo dirInfo(pburl);
5563 str.replace(QString(
"%DIR%"), dirInfo.path());
5571 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5572 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5573 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5574 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5575 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5577 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5578 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5579 str.replace(QString(
"%CATEGORY%"),
m_category);
5580 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5582 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5583 str.replace(QString(
"%INETREF%"),
m_inetRef);
5584 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5585 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5586 str.replace(QString(
"%ORIGINALAIRDATE%"),
5588 static const std::array<const QString,4> s_timeStr
5589 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5590 const std::array<const QDateTime *,4> time_dtr
5592 for (
size_t i = 0; i < s_timeStr.size(); i++)
5594 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5595 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5596 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5598 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5599 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5600 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5603 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5608 QMap<QString, uint32_t> inUseMap;
5613 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5614 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5615 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5620 while (query.
next())
5623 query.
value(0).toUInt(),
5626 QString inUseForWhat = query.
value(2).toString();
5628 if (!inUseMap.contains(inUseKey))
5629 inUseMap[inUseKey] = 0;
5632 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5634 inUseMap[inUseKey] |= FL_INUSERECORDING;
5636 inUseMap[inUseKey] |= FL_INUSEOTHER;
5644 QMap<QString,bool> is_job_running;
5647 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5648 "WHERE type = :TYPE");
5651 return is_job_running;
5653 while (query.
next())
5657 int tmpStatus = query.
value(2).toInt();
5658 if ((tmpStatus != 0x0000) &&
5659 (tmpStatus != 0x0001) &&
5660 (!(tmpStatus & 0x0100)))
5667 return is_job_running;
5671 const QString &tmptable,
int recordid)
5676 if (
sched && tmptable.isEmpty())
5684 LOG(VB_GENERAL, LOG_ERR,
5685 "Called from master backend\n\t\t\t"
5686 "with recordid or tmptable, this is not currently supported");
5691 (tmptable.isEmpty()) ?
5692 QString(
"QUERY_GETALLPENDING") :
5693 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5697 LOG(VB_GENERAL, LOG_ALERT,
5698 "LoadFromScheduler(): Error querying master.");
5717 QString columns = QString(
5718 "program.chanid, program.starttime, program.endtime, "
5719 "program.title, program.subtitle, program.description, "
5720 "program.category, channel.channum, channel.callsign, "
5721 "channel.name, program.previouslyshown, channel.commmethod, "
5722 "channel.outputfilters, program.seriesid, program.programid, "
5723 "program.airdate, program.stars, program.originalairdate, "
5724 "program.category_type, oldrecstatus.recordid, "
5725 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5726 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5727 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5728 "program.partnumber, program.parttotal, "
5729 "program.season, program.episode, program.totalepisodes ");
5731 QString querystr = QString(
5735 " LEFT JOIN channel ON program.chanid = channel.chanid "
5736 " LEFT JOIN oldrecorded AS oldrecstatus ON "
5737 " oldrecstatus.future = 0 AND "
5738 " program.title = oldrecstatus.title AND "
5739 " channel.callsign = oldrecstatus.station AND "
5740 " program.starttime = oldrecstatus.starttime "
5751 ", row_number() over ( "
5754 columns +=
"channel.channum, "
5755 " channel.callsign, ";
5757 columns +=
"channel.callsign, ";
5759 columns +=
"program.programid, ";
5762 " program.starttime "
5763 " order by channel.recpriority desc, "
5764 " channel.sourceid, "
5765 " channel.channum+0 "
5767 querystr +=
"WHERE grouprn = 1 ";
5773 querystr += QString(
"LIMIT %1 ").arg(limit);
5774 else if (!querystr.contains(
" LIMIT "))
5775 querystr +=
" LIMIT 20000 ";
5777 MSqlBindings::const_iterator it;
5794 if (start > 0 || limit > 0)
5796 QString countStr = querystr
5797 .arg(
"SQL_CALC_FOUND_ROWS chanid", columns);
5799 for (it = bindings.begin(); it != bindings.end(); ++it)
5801 if (countStr.contains(it.key()))
5811 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5812 count = query.
value(0).toUInt();
5816 querystr += QString(
"OFFSET %1 ").arg(start);
5818 querystr = querystr.arg(
"*", columns);
5820 for (it = bindings.begin(); it != bindings.end(); ++it)
5822 if (querystr.contains(it.key()))
5836 const QString &groupBy,
const QString &orderBy,
5841 QString queryStr =
"";
5843 if (!where.isEmpty())
5844 queryStr.append(QString(
"WHERE %1 ").arg(where));
5846 if (!groupBy.isEmpty())
5847 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5849 if (!orderBy.isEmpty())
5850 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5854 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5864 QString queryStr = sql;
5878 if (!queryStr.contains(
"WHERE"))
5879 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5881 if (!queryStr.contains(
"ORDER BY"))
5883 queryStr +=
" ORDER BY program.starttime, ";
5886 if (chanorder !=
"channum")
5887 queryStr += chanorder +
" ";
5889 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5894 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5904 destination.
clear();
5906 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5908 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5909 "clause, caller should be updated to use "
5910 "start parameter instead");
5913 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5915 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5916 "clause, caller should be updated to use "
5917 "limit parameter instead");
5926 count = query.
size();
5928 while (query.
next())
5932 query.
value(3).toString(),
5934 query.
value(4).toString(),
5936 query.
value(5).toString(),
5937 query.
value(26).toString(),
5938 query.
value(6).toString(),
5940 query.
value(0).toUInt(),
5941 query.
value(7).toString(),
5942 query.
value(8).toString(),
5943 query.
value(9).toString(),
5944 query.
value(12).toString(),
5951 query.
value(13).toString(),
5952 query.
value(14).toString(),
5955 query.
value(16).toFloat(),
5956 query.
value(15).toUInt(),
5957 query.
value(27).toUInt(),
5958 query.
value(28).toUInt(),
5959 query.
value(17).toDate(),
5961 query.
value(19).toUInt(),
5963 query.
value(22).toUInt(),
5966 query.
value(10).toBool(),
5967 query.
value(23).toInt(),
5968 query.
value(24).toInt(),
5969 query.
value(25).toInt(),
5970 query.
value(29).toUInt(),
5971 query.
value(30).toUInt(),
5972 query.
value(31).toUInt(),
5981 const QDateTime& starttime)
5988 QString sSQL =
"WHERE program.chanid = :ChanId "
5989 "AND program.starttime = :StartTime ";
5991 bindings[
":ChanId" ] = chanid;
5992 bindings[
":StartTime"] = starttime;
5997 bool hasConflicts =
false;
6006 if (progList.
empty())
6027 destination.
clear();
6033 "oldrecorded.chanid, starttime, endtime, "
6034 "title, subtitle, description, season, episode, category, seriesid, "
6035 "programid, inetref, channel.channum, channel.callsign, "
6036 "channel.name, findid, rectype, recstatus, recordid, duplicate ";
6041 "LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
6042 "WHERE oldrecorded.future = 0 "
6045 bool hasLimit = querystr.contains(
" LIMIT ",Qt::CaseInsensitive);
6049 if (!hasLimit && !querystr.contains(
" ORDER ",Qt::CaseInsensitive))
6050 querystr +=
" ORDER BY starttime DESC ";
6056 querystr += QString(
"LIMIT %1 ").arg(limit);
6063 nLimit = std::max(nLimit, 100);
6064 querystr += QString(
"LIMIT %1 ").arg(nLimit);
6067 MSqlBindings::const_iterator it;
6084 if (count > 0 && (start > 0 || limit > 0))
6086 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS oldrecorded.chanid");
6088 for (it = bindings.begin(); it != bindings.end(); ++it)
6090 if (countStr.contains(it.key()))
6100 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
6101 count = query.
value(0).toUInt();
6105 querystr += QString(
"OFFSET %1 ").arg(start);
6107 querystr = querystr.arg(columns);
6109 for (it = bindings.begin(); it != bindings.end(); ++it)
6111 if (querystr.contains(it.key()))
6121 while (query.
next())
6124 QString channum = QString(
"#%1").arg(chanid);
6125 QString chansign = channum;
6126 QString channame = channum;
6127 if (!query.
value(12).toString().isEmpty())
6129 channum = query.
value(12).toString();
6130 chansign = query.
value(13).toString();
6131 channame = query.
value(14).toString();
6135 query.
value(3).toString(),
6137 query.
value(4).toString(),
6139 query.
value(5).toString(),
6140 query.
value(6).toUInt(),
6141 query.
value(7).toUInt(),
6142 query.
value(8).toString(),
6144 chanid, channum, chansign, channame,
6146 query.
value(9).toString(), query.
value(10).toString(),
6147 query.
value(11).toString(),
6155 query.
value(18).toUInt(),
6157 query.
value(15).toUInt(),
6159 query.
value(19).toBool()));
6185 bool possiblyInProgressRecordingsOnly,
6186 const QMap<QString,uint32_t> &inUseMap,
6187 const QMap<QString,bool> &isJobRunning,
6188 const QMap<QString, ProgramInfo*> &recMap,
6190 const QString &sortBy,
6194 destination.
clear();
6202 if (possiblyInProgressRecordingsOnly || ignoreLiveTV || ignoreDeleted)
6204 thequery +=
"WHERE ";
6205 if (possiblyInProgressRecordingsOnly)
6207 thequery +=
"(r.endtime >= NOW() AND r.starttime <= NOW()) ";
6211 thequery += QString(
"%1 r.recgroup != 'LiveTV' ")
6212 .arg(possiblyInProgressRecordingsOnly ?
"AND" :
"");
6216 thequery += QString(
"%1 r.recgroup != 'Deleted' ")
6217 .arg((possiblyInProgressRecordingsOnly || ignoreLiveTV)
6222 if (sortBy.isEmpty())
6225 thequery +=
"ORDER BY r.starttime ";
6227 thequery +=
"DESC ";
6231 QStringList sortByFields;
6232 sortByFields <<
"starttime" <<
"title" <<
"subtitle" <<
"season" <<
"episode" <<
"category"
6233 <<
"watched" <<
"stars" <<
"originalairdate" <<
"recgroup" <<
"storagegroup"
6234 <<
"channum" <<
"callsign" <<
"name" <<
"filesize" <<
"duration";
6237 QStringList fields = sortBy.split(
",");
6238 for (
const QString& oneField : std::as_const(fields))
6240 bool ascending =
true;
6241 QString field = oneField.simplified().toLower();
6243 if (field.endsWith(
"desc"))
6246 field = field.remove(
"desc");
6249 if (field.endsWith(
"asc"))
6252 field = field.remove(
"asc");
6255 field = field.simplified();
6257 if (field ==
"channelname")
6260 if (sortByFields.contains(field))
6263 if (field ==
"channum" || field ==
"callsign" || field ==
"name")
6268 if (field ==
"channum")
6271 field =
"channum*1000-ifnull(regexp_substr(c.channum,'-.*'),0)";
6274 else if (field ==
"duration")
6276 field =
"timestampdiff(second,r.starttime,r.endtime)";
6280 else if (field ==
"season")
6282 field =
"if(r.season,r.season,p.season)";
6286 else if (field ==
"episode")
6288 field =
"if(r.episode,r.episode,p.episode)";
6292 else if (field ==
"title")
6295 QString prefixes = sh->getPrefixes();
6296 field =
"REGEXP_REPLACE(r.title,'" + prefixes +
"','')";
6300 else if (field ==
"subtitle")
6303 QString prefixes = sh->getPrefixes();
6304 field =
"REGEXP_REPLACE(r.subtitle,'" + prefixes +
"','')";
6308 else if (field ==
"originalairdate")
6310 field =
"IF(r.originalairdate != '0000-00-00', r.originalairdate, STR_TO_DATE(CONCAT(p.airdate,',01,01'),'%Y,%m,%d'))";
6314 if (sSortBy.isEmpty())
6315 sSortBy = QString(
"%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6317 sSortBy += QString(
",%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6321 LOG(VB_GENERAL, LOG_WARNING, QString(
"ProgramInfo::LoadFromRecorded() got an unknown sort field '%1' - ignoring").arg(oneField));
6325 thequery +=
"ORDER BY " + sSortBy;
6337 while (query.
next())
6339 const uint chanid = query.
value(6).toUInt();
6340 QString channum = QString(
"#%1").arg(chanid);
6341 QString chansign = channum;
6342 QString channame = channum;
6344 if (!query.
value(7).toString().isEmpty())
6346 channum = query.
value(7).toString();
6347 chansign = query.
value(8).toString();
6348 channame = query.
value(9).toString();
6349 chanfilt = query.
value(10).toString();
6361 recMap.contains(key))
6366 bool save_not_commflagged =
false;
6373 set_flag(flags, FL_COMMPROCESSING ,
6378 set_flag(flags, FL_DELETEPENDING, query.
value(35).toBool());
6382 set_flag(flags, FL_REALLYEDITING, query.
value(39).toBool());
6387 if (inUseMap.contains(key))
6388 flags |= inUseMap[key];
6390 if (((flags & FL_COMMPROCESSING) != 0U) &&
6391 (!isJobRunning.contains(key)))
6393 flags &= ~FL_COMMPROCESSING;
6394 save_not_commflagged =
true;
6398 ((flags & FL_REALLYEDITING) != 0U) ||
6404 season = query.
value(51).toUInt();
6409 episode = query.
value(52).toUInt();
6412 uint totalepisodes = query.
value(53).toUInt();
6416 query.
value(55).toUInt(),
6417 query.
value(0).toString(),
6419 query.
value(1).toString(),
6421 query.
value(2).toString(),
6425 query.
value(48).toString(),
6426 query.
value(5).toString(),
6428 chanid, channum, chansign, channame, chanfilt,
6430 query.
value(11).toString(), query.
value(12).toString(),
6432 query.
value(14).toString(),
6436 query.
value(17).toString(), query.
value(18).toString(),
6437 query.
value(19).toString(),
6440 query.
value(16).toInt(),
6442 query.
value(20).toULongLong(),
6449 query.
value(23).toFloat(),
6451 query.
value(26).toUInt(),
6452 query.
value(49).toUInt(),
6453 query.
value(50).toUInt(),
6454 query.
value(27).toDate(),
6459 query.
value(29).toUInt(),
6464 query.
value(45).toUInt(),
6467 query.
value(42).toUInt(),
6468 query.
value(43).toUInt(),
6469 query.
value(44).toUInt(),
6470 query.
value(56).toString(),
6474 if (save_not_commflagged)
6483 std::vector<ProgramInfo> *list)
6485 nextRecordingStart = QDateTime();
6488 bool *conflicts = hasConflicts ? hasConflicts : &dummy;
6495 for (
auto *prog : progList)
6499 (nextRecordingStart.isNull() ||
6500 nextRecordingStart > prog->GetRecordingStartTime()))
6502 nextRecordingStart = prog->GetRecordingStartTime();
6510 for (
auto & prog : progList)
6514 (prog->GetRecordingStartTime() == nextRecordingStart))
6554 "SET filesize = :FILESIZE "
6555 "WHERE chanid = :CHANID AND "
6556 " starttime = :STARTTIME");
6557 query.
bindValue(
":FILESIZE", (quint64)fsize);
6588 uint64_t db_filesize = 0;
6595 "WHERE chanid = :CHANID AND "
6596 " starttime = :STARTTIME");
6600 db_filesize = query.
value(0).toULongLong();
6603 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"RI Filesize=0, DB Filesize=%1")
6617 if (now < startTime)
6621 int current = startTime.secsTo(now);
6622 int duration = startTime.secsTo(endTime);
6627 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 recorded percent %2/%3 = %4%")
6656 total = rate1000 * duration / 1000;
6668 LOG(VB_GUI, LOG_DEBUG,
6669 QString(
"%1 %2 no frame count. Please rebuild seek table for this video.")
6674 LOG(VB_GUI, LOG_DEBUG,
6675 QString(
"%1 %2 no frame count. Please rebuild seek table for this recording.")
6683 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 %2 watched percent %3/%4 = %5%")
6701 return tr(
"Channel Number");
6703 return tr(
"CallSign");
6705 return tr(
"ProgramId");
6707 return tr(
"Unknown");
6713 QStringList strlist(
"QUERY_CHECKFILE");
6714 strlist << QString::number((
int)checkSlaves);
6718 (strlist.size() < 2) || !strlist[0].toInt())
6723 QString localpath = strlist[1];
6724 QFile checkFile(localpath);
6725 if (checkFile.exists())
6731#include "moc_programinfo.cpp"
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)
bool operator==(const ProgramInfo &rhs) const
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
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)
static void init_tr(void)
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.