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];
1474 QString
tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1475 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1479 return result.join(
'|');
1482template <
typename T>
1484 const QString& props)
1486 if (props.isEmpty())
1491 QStringList names = props.split(
'|');
1492 for (
const auto& n : std::as_const(names) )
1494 uint bit = propNames.key(n, 0);
1497 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1535 tmp_rec += QObject::tr(
"Re-Record");
1590 uint date_format)
const
1595 QString channelFormat =
1597 QString longChannelFormat =
1607 QString tempSubTitle =
m_title;
1611 tempSubTitle = QString(
"%1 - \"%2\"")
1613 tempSortSubtitle = QString(
"%1 - \"%2\"")
1617 progMap[
"titlesubtitle"] = tempSubTitle;
1618 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1620 progMap[
"description"] = progMap[
"description0"] =
m_description;
1627 progMap[
"s00e00"] = QString(
"s%1e%2")
1630 progMap[
"00x00"] = QString(
"%1x%2")
1636 progMap[
"season"] = progMap[
"episode"] =
"";
1637 progMap[
"totalepisodes"] =
"";
1638 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1646 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1650 progMap[
"starttime"] =
"";
1651 progMap[
"startdate"] =
"";
1652 progMap[
"endtime"] =
"";
1653 progMap[
"enddate"] =
"";
1654 progMap[
"recstarttime"] =
"";
1655 progMap[
"recstartdate"] =
"";
1656 progMap[
"recendtime"] =
"";
1657 progMap[
"recenddate"] =
"";
1661 progMap[
"startdate"] =
"";
1662 progMap[
"recstartdate"] =
"";
1666 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1667 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1674 progMap[
"startdate"] =
1684 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1685 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1686 if (timeNow.toLocalTime().date().year() !=
1688 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1689 if (timeNow.toLocalTime().date().year() !=
1690 m_endTs.toLocalTime().date().year())
1691 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1695 progMap[
"timedate"] =
1699 progMap[
"shorttimedate"] =
1703 progMap[
"starttimedate"] =
1706 progMap[
"shortstarttimedate"] =
1710 progMap[
"lastmodifieddate"] =
1712 progMap[
"lastmodified"] =
1719 progMap[
"chanid"] = QString::number(
m_chanId);
1722 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1724 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1725 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1727 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1730 int minutes = seconds / 60;
1732 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1734 progMap[
"lenmins"] = min_str;
1735 int hours = minutes / 60;
1736 minutes = minutes % 60;
1738 progMap[
"lentime"] = min_str;
1739 if (hours > 0 && minutes > 0)
1741 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1742 progMap[
"lentime"] = QString(
"%1 %2")
1743 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1747 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1750 progMap[
"recordedpercent"] =
1753 progMap[
"watchedpercent"] =
1771 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1776 progMap[
"storagegroup"] = QObject::tr(
"Default");
1782 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1806 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1807 progMap[
"longrepeat"] = progMap[
"repeat"];
1810 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1811 .arg(QObject::tr(
"Repeat"),
1819 progMap[
"repeat"] =
"";
1820 progMap[
"longrepeat"] =
"";
1828 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1833 QString star_str = (
m_stars != 0.0F) ?
1834 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1835 progMap[
"stars"] = star_str;
1836 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1839 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1841 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1843 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1845 progMap[
"yearstars"] =
"";
1850 progMap[
"originalairdate"] =
"";
1851 progMap[
"shortoriginalairdate"] =
"";
1865 QString mediaTypeString;
1869 mediaType =
"video";
1870 mediaTypeString = QObject::tr(
"Video");
1874 mediaTypeString = QObject::tr(
"DVD");
1877 mediaType =
"httpstream";
1878 mediaTypeString = QObject::tr(
"HTTP Streaming");
1881 mediaType =
"rtspstream";
1882 mediaTypeString = QObject::tr(
"RTSP Streaming");
1885 mediaType =
"bluraydisc";
1886 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1890 mediaType =
"recording";
1891 mediaTypeString = QObject::tr(
"Recording",
1892 "Recorded file, object not action");
1894 progMap[
"mediatype"] = mediaType;
1895 progMap[
"mediatypestring"] = mediaTypeString;
1903 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1915 uint64_t last_frame = 0;
1924 if (!posMap.empty())
1926 frm_pos_map_t::const_iterator it = posMap.constEnd();
1928 last_frame = it.key();
1935 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1962 str +=
" startts(" +
1965 ") recendts(" +
m_recEndTs.toString() +
")\n";
1966 str +=
" title(" +
m_title +
")";
1974 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1979 str = QString(
"%1 at %2")
1983 str = QString(
"%1 @ %2")
2006 const uint _chanid,
const QDateTime &_recstartts)
2008 if (!_chanid || !_recstartts.isValid())
2017 "WHERE r.chanid = :CHANID AND "
2018 " r.starttime = :RECSTARTTS");
2020 query.
bindValue(
":RECSTARTTS", _recstartts);
2073 if (!query.
value(7).toString().isEmpty())
2087 QString new_basename = query.
value(14).toString();
2088 if ((
GetBasename() != new_basename) || !is_reload)
2092 LOG(VB_FILE, LOG_INFO,
LOC +
2093 QString(
"Updated pathname '%1':'%2' -> '%3'")
2229 if (index == oindex && (index < 0 ||
2288 if (index == oindex && (index < 0 ||
2383 QMap<QString, int> authMap;
2384 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2387 for (
const QString& table : tables)
2390 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2391 "FROM %1 WHERE programid <> ''").arg(table));
2396 while (query.
next())
2397 authMap[query.
value(0).toString()] = 1;
2401 int numAuths = authMap.count();
2402 LOG(VB_GENERAL, LOG_INFO,
2403 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2416 QString retval = QString(
"%1_%2.%3")
2417 .arg(QString::number(
m_chanId), starts, ext);
2423 uint chanid,
const QString &pathname,
bool use_remote)
2425 QString fn_lower = pathname.toLower();
2429 else if (fn_lower.startsWith(
"http:"))
2431 else if (fn_lower.startsWith(
"rtsp:"))
2437 if (fn_lower.startsWith(
"dvd:"))
2441 else if (fn_lower.startsWith(
"bd:"))
2445 else if (use_remote && fn_lower.startsWith(
"myth://"))
2447 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2448 QString tmpFileBD = pathname +
"/BDMV";
2476 LOG(VB_GUI, LOG_INFO,
2491 query.
prepare(
"UPDATE recorded "
2492 "SET basename = :BASENAME "
2493 "WHERE recordedid = :RECORDEDID;");
2503 query.
prepare(
"UPDATE recordedfile "
2504 "SET basename = :BASENAME "
2505 "WHERE recordedid = :RECORDEDID;");
2537 "FROM recordedfile "
2538 "WHERE recordedid = :RECORDEDID;");
2545 else if (query.
next())
2547 return query.
value(0).toString();
2551 LOG(VB_GENERAL, LOG_INFO,
2552 QString(
"QueryBasename found no entry for recording ID %1")
2567 bool checkMaster,
bool forceCheckLocal)
2574 if (basename.isEmpty())
2583 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2586 QUrl url = QUrl(fullpath);
2587 QString path = url.path();
2588 QString host = url.toString(QUrl::RemovePath).mid(7);
2589 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2593 list = host.split(
"@", Qt::SkipEmptyParts);
2595 if (!list.empty() && list.size() < 3)
2597 host = list.size() == 1 ? list[0] : list[1];
2598 group = list.size() == 1 ? QString() : list[0];
2601 if (!local.isEmpty() && sg.
FileExists(local))
2614 LOG(VB_FILE, LOG_DEBUG,
LOC +
2615 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2617 tmpURL = sgroup.
FindFile(basename);
2619 if (!tmpURL.isEmpty())
2621 LOG(VB_FILE, LOG_INFO,
LOC +
2622 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2627 LOG(VB_GENERAL, LOG_ERR,
LOC +
2628 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2629 "not be found.").arg(basename));
2632 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2638 if ((checkMaster) &&
2646 LOG(VB_FILE, LOG_INFO,
LOC +
2647 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2656 LOG(VB_FILE, LOG_INFO,
LOC +
2657 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2671 query.
prepare(
"SELECT mplexid FROM channel "
2672 "WHERE chanid = :CHANID");
2677 else if (query.
next())
2678 ret = query.
value(0).toUInt();
2681 ret = (32767 == ret) ? 0 : ret;
2693 bool is_valid = (frame > 0);
2714 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2715 " bookmark = :BOOKMARKFLAG "
2716 "WHERE recordedid = :RECORDEDID");
2718 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2730 bool isValid = frame > 0;
2755 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2756 " lastplay = :LASTPLAYFLAG "
2757 "WHERE recordedid = :RECORDEDID");
2759 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2790 "SELECT bookmarkupdate "
2792 "WHERE chanid = :CHANID AND"
2793 " starttime = :STARTTIME");
2801 else if (query.
next())
2821 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2831 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2848 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2865 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2873 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2880 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2887 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2894 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2898 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2908 const QString &serialid)
const
2910 QStringList fields = QStringList();
2915 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2916 " FROM dvdbookmark "
2917 " WHERE serialid = :SERIALID ");
2922 QString dvdstate = query.
value(0).toString();
2924 if (!dvdstate.isEmpty())
2926 fields.append(dvdstate);
2931 for(
int i = 1; i < 5; i++)
2932 fields.append(query.
value(i).toString());
2942 QStringList::const_iterator it = fields.begin();
2945 QString serialid = *(it);
2946 QString name = *(++it);
2948 if( fields.count() == 3 )
2951 QString state = *(++it);
2953 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2955 " VALUES ( :SERIALID, :NAME );");
2962 query.
prepare(
" UPDATE dvdbookmark "
2963 " SET dvdstate = :STATE , "
2964 " timestamp = NOW() "
2965 " WHERE serialid = :SERIALID");
2972 query.
prepare(
"DELETE FROM dvdbookmark "
2973 "WHERE serialid = :SERIALID");
2986 QStringList fields = QStringList();
2991 query.
prepare(
" SELECT bdstate FROM bdbookmark "
2992 " WHERE serialid = :SERIALID ");
2996 fields.append(query.
value(0).toString());
3004 QStringList::const_iterator it = fields.begin();
3007 QString serialid = *(it);
3008 QString name = *(++it);
3010 if( fields.count() == 3 )
3013 QString state = *(++it);
3015 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
3017 " VALUES ( :SERIALID, :NAME );");
3024 query.
prepare(
" UPDATE bdbookmark "
3025 " SET bdstate = :STATE , "
3026 " timestamp = NOW() "
3027 " WHERE serialid = :SERIALID");
3034 query.
prepare(
"DELETE FROM bdbookmark "
3035 "WHERE serialid = :SERIALID");
3054 query.
prepare(
" SELECT category_type "
3055 " FROM recordedprogram "
3056 " WHERE chanid = :CHANID "
3057 " AND starttime = :STARTTIME;");
3077 query.
prepare(
"UPDATE recorded"
3078 " SET watched = :WATCHEDFLAG"
3079 " WHERE chanid = :CHANID"
3080 " AND starttime = :STARTTIME ;");
3083 query.
bindValue(
":WATCHEDFLAG", watched);
3095 if (url.startsWith(
"myth://"))
3097 url = QUrl(url).path();
3102 query.
prepare(
"UPDATE videometadata"
3103 " SET watched = :WATCHEDFLAG"
3104 " WHERE title = :TITLE"
3105 " AND subtitle = :SUBTITLE"
3106 " AND filename = :FILENAME ;");
3110 query.
bindValue(
":WATCHEDFLAG", watched);
3129 query.
prepare(
"SELECT editing FROM recorded"
3130 " WHERE chanid = :CHANID"
3131 " AND starttime = :STARTTIME ;");
3136 editing = query.
value(0).toBool();
3153 query.
prepare(
"UPDATE recorded"
3154 " SET editing = :EDIT"
3155 " WHERE chanid = :CHANID"
3156 " AND starttime = :STARTTIME ;");
3178 query.
prepare(
"UPDATE recorded"
3179 " SET deletepending = :DELETEFLAG, "
3181 " WHERE chanid = :CHANID"
3182 " AND starttime = :STARTTIME ;");
3185 query.
bindValue(
":DELETEFLAG", deleteFlag);
3210 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3211 " WHERE chanid = :CHANID"
3212 " AND starttime = :STARTTIME "
3213 " AND lastupdatetime > :ONEHOURAGO ;");
3216 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3219 if (query.
exec() && query.
size() > 0)
3223 while (query.
next())
3225 usageStr = QObject::tr(
"Unknown");
3226 recusage = query.
value(1).toString();
3229 usageStr = QObject::tr(
"Playing");
3231 usageStr = QObject::tr(
"PIP");
3233 usageStr = QObject::tr(
"PBP");
3236 usageStr = QObject::tr(
"Recording");
3238 usageStr = QObject::tr(
"File transfer");
3240 usageStr = QObject::tr(
"Delete");
3242 usageStr = QObject::tr(
"Commercial Detection");
3244 usageStr = QObject::tr(
"Transcoding");
3246 usageStr = QObject::tr(
"Preview Generation");
3248 usageStr = QObject::tr(
"User Job");
3250 byWho.push_back(recusage);
3251 byWho.push_back(query.
value(0).toString());
3252 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3270 for (
int i = 0; i+2 < users.size(); i+=3)
3271 byWho += users[i+2] +
"\n";
3298 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3308 (one_playback_allowed && (play_cnt <= 1)));
3310 ok = ok && (ft_cnt == jq_cnt);
3321 query.
prepare(
"SELECT transcoded FROM recorded"
3322 " WHERE chanid = :CHANID"
3323 " AND starttime = :STARTTIME ;");
3343 "SET transcoded = :VALUE "
3344 "WHERE chanid = :CHANID AND"
3345 " starttime = :STARTTIME");
3364 query.
prepare(
"UPDATE recorded"
3365 " SET commflagged = :FLAG"
3366 " WHERE chanid = :CHANID"
3367 " AND starttime = :STARTTIME ;");
3390 query.
prepare(
"UPDATE recorded"
3391 " SET preserve = :PRESERVE"
3392 " WHERE chanid = :CHANID"
3393 " AND starttime = :STARTTIME ;");
3394 query.
bindValue(
":PRESERVE", preserveEpisode);
3417 query.
prepare(
"UPDATE recorded"
3418 " SET autoexpire = :AUTOEXPIRE"
3419 " WHERE chanid = :CHANID"
3420 " AND starttime = :STARTTIME ;");
3427 else if (updateDelete)
3446 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3447 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3450 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3451 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3452 "WHERE recordid = :RECORDID");
3454 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3458 query.
prepare(
"UPDATE record SET last_delete = NULL "
3459 "WHERE recordid = :RECORDID");
3472 query.
prepare(
"SELECT autoexpire FROM recorded"
3473 " WHERE chanid = :CHANID"
3474 " AND starttime = :STARTTIME ;");
3495 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3497 uint64_t frame = i.key();
3503 delMap[frame] = mark;
3513 return !delMap.isEmpty();
3529 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3531 uint64_t frame = i.key();
3540 tmpDelMap[frame] = mark;
3549 query.
prepare(
"UPDATE recorded"
3550 " SET cutlist = :CUTLIST"
3551 " WHERE chanid = :CHANID"
3552 " AND starttime = :STARTTIME ;");
3554 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3583 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3586 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3589 comp += QString(
" AND type = :TYPE ");
3593 query.
prepare(
"DELETE FROM filemarkup"
3594 " WHERE filename = :PATH "
3600 query.
prepare(
"DELETE FROM recordedmarkup"
3601 " WHERE chanid = :CHANID"
3602 " AND STARTTIME = :STARTTIME"
3619 int64_t min_frame, int64_t max_frame)
const
3631 query.
prepare(
"SELECT starttime FROM recorded"
3632 " WHERE chanid = :CHANID"
3633 " AND starttime = :STARTTIME ;");
3648 frm_dir_map_t::const_iterator it;
3649 for (it = marks.begin(); it != marks.end(); ++it)
3651 uint64_t frame = it.key();
3653 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3656 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3663 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3664 " VALUES ( :PATH , :MARK , :TYPE );");
3669 query.
prepare(
"INSERT INTO recordedmarkup"
3670 " (chanid, starttime, mark, type)"
3671 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3675 query.
bindValue(
":MARK", (quint64)frame);
3692 marks,
type, merge);
3701 const QString &video_pathname,
3710 query.
prepare(
"SELECT mark, type, `offset` "
3712 "WHERE filename = :PATH AND "
3715 query.
bindValue(
":PATH", video_pathname);
3724 while (query.
next())
3728 int entryType = query.
value(1).toInt();
3738 uint chanid,
const QDateTime &recstartts,
3746 query.
prepare(
"SELECT mark, type, data "
3747 "FROM recordedmarkup "
3748 "WHERE chanid = :CHANID AND "
3749 " starttime = :STARTTIME AND"
3753 query.
bindValue(
":STARTTIME", recstartts);
3762 while (query.
next())
3766 int entryType = query.
value(1).toInt();
3781 return flagMap.contains(0);
3809 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3810 " WHERE filename = :PATH"
3811 " AND type = :TYPE ;");
3816 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3817 " WHERE chanid = :CHANID"
3818 " AND starttime = :STARTTIME"
3819 " AND type = :TYPE ;");
3835 while (query.
next())
3836 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3852 query.
prepare(
"DELETE FROM filemarkup"
3853 " WHERE filename = :PATH"
3854 " AND type = :TYPE ;");
3859 query.
prepare(
"DELETE FROM recordedseek"
3860 " WHERE chanid = :CHANID"
3861 " AND starttime = :STARTTIME"
3862 " AND type = :TYPE ;");
3879 int64_t min_frame, int64_t max_frame)
const
3885 if ((min_frame >= 0) || (max_frame >= 0))
3893 uint64_t frame = it.key();
3894 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3896 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3898 new_map.insert(it.key(), *it);
3908 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3910 uint64_t frame = it.key();
3911 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3913 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3917 .insert(frame, *it);
3927 comp +=
" AND mark >= :MIN_FRAME ";
3929 comp +=
" AND mark <= :MAX_FRAME ";
3936 query.
prepare(
"DELETE FROM filemarkup"
3937 " WHERE filename = :PATH"
3944 query.
prepare(
"DELETE FROM recordedseek"
3945 " WHERE chanid = :CHANID"
3946 " AND starttime = :STARTTIME"
3959 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3961 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3966 if (posMap.isEmpty())
3970 QStringList q(
"INSERT INTO ");
3974 q <<
"filemarkup (filename, type, mark, `offset`)";
3975 qfields = QString(
"('%1',%2,") .
3982 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
3983 qfields = QString(
"(%1,'%2',%3,") .
3990 bool add_comma =
false;
3991 frm_pos_map_t::iterator it;
3992 for (it = posMap.begin(); it != posMap.end(); ++it)
3994 uint64_t frame = it.key();
3996 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3999 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
4002 uint64_t offset = *it;
4012 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4024 if (posMap.isEmpty())
4031 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4038 QStringList q(
"INSERT INTO ");
4042 q <<
"filemarkup (filename, type, mark, `offset`)";
4043 qfields = QString(
"('%1',%2,") .
4050 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4051 qfields = QString(
"(%1,'%2',%3,") .
4062 bool add_comma =
false;
4063 frm_pos_map_t::iterator it;
4064 for (it = posMap.begin(); it != posMap.end(); ++it)
4066 uint64_t frame = it.key();
4067 uint64_t offset = *it;
4077 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4089 "SELECT mark, `offset` FROM filemarkup"
4090 " WHERE filename = :PATH"
4092 " AND mark >= :QUERY_ARG"
4093 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4095 "SELECT mark, `offset` FROM filemarkup"
4096 " WHERE filename = :PATH"
4098 " AND mark <= :QUERY_ARG"
4099 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4101 "SELECT mark, `offset` FROM recordedseek"
4102 " WHERE chanid = :CHANID"
4103 " AND starttime = :STARTTIME"
4105 " AND mark >= :QUERY_ARG"
4106 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4108 "SELECT mark, `offset` FROM recordedseek"
4109 " WHERE chanid = :CHANID"
4110 " AND starttime = :STARTTIME"
4112 " AND mark <= :QUERY_ARG"
4113 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4115 "SELECT `offset`,mark FROM filemarkup"
4116 " WHERE filename = :PATH"
4118 " AND `offset` >= :QUERY_ARG"
4119 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4121 "SELECT `offset`,mark FROM filemarkup"
4122 " WHERE filename = :PATH"
4124 " AND `offset` <= :QUERY_ARG"
4125 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4127 "SELECT `offset`,mark FROM recordedseek"
4128 " WHERE chanid = :CHANID"
4129 " AND starttime = :STARTTIME"
4131 " AND `offset` >= :QUERY_ARG"
4132 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4134 "SELECT `offset`,mark FROM recordedseek"
4135 " WHERE chanid = :CHANID"
4136 " AND starttime = :STARTTIME"
4138 " AND `offset` <= :QUERY_ARG"
4139 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4142 uint64_t position_or_keyframe,
4145 const char *from_filemarkup_asc,
4146 const char *from_filemarkup_desc,
4147 const char *from_recordedseek_asc,
4148 const char *from_recordedseek_desc)
const
4155 query.
prepare(from_filemarkup_desc);
4157 query.
prepare(from_filemarkup_asc);
4163 query.
prepare(from_recordedseek_desc);
4165 query.
prepare(from_recordedseek_asc);
4170 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4180 *result = query.
value(1).toULongLong();
4187 query.
prepare(from_filemarkup_asc);
4189 query.
prepare(from_filemarkup_desc);
4195 query.
prepare(from_recordedseek_asc);
4197 query.
prepare(from_recordedseek_desc);
4202 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4212 *result = query.
value(1).toULongLong();
4221 bool backwards)
const
4230 bool backwards)
const
4239 bool backwards)
const
4248 bool backwards)
const
4268 query.
prepare(
"INSERT INTO recordedmarkup"
4269 " (chanid, starttime, mark, type, data)"
4271 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4275 query.
bindValue(
":MARK", (quint64)frame);
4283#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4284 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4286 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4304 query.
prepare(
"INSERT INTO recordedmarkup"
4305 " (chanid, starttime, mark, type, data)"
4307 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4310 query.
bindValue(
":MARK", (quint64)frame);
4329 query.
prepare(
"INSERT INTO recordedmarkup"
4330 " (chanid, starttime, mark, type, data)"
4332 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4335 query.
bindValue(
":MARK", (quint64)frame);
4349 query.
prepare(
"DELETE FROM recordedmarkup "
4350 " WHERE chanid=:CHANID "
4351 " AND starttime=:STARTTIME "
4354 query.
bindValue(
":STARTTIME", recstartts);
4367 query.
prepare(
"DELETE FROM filemarkup"
4368 " WHERE filename = :PATH "
4369 " AND type = :TYPE ;");
4383 query.
prepare(
"DELETE FROM filemarkup"
4384 " WHERE filename = :PATH "
4385 " AND mark = :MARK "
4386 " AND type = :TYPE ;");
4400 query.
prepare(
"INSERT INTO filemarkup"
4401 " (filename, mark, type, `offset`)"
4403 " ( :PATH , :MARK , :TYPE, :OFFSET );");
4418 query.
prepare(
"INSERT INTO recordedmarkup"
4419 " (chanid, starttime, mark, type, data)"
4421 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4423 query.
bindValue(
":STARTTIME", recstartts);
4480 query.
prepare(
"INSERT INTO recordedmarkup"
4481 " (chanid, starttime, mark, type, data)"
4483 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4486 query.
bindValue(
":MARK", (quint64)frame);
4493 query.
prepare(
"INSERT INTO recordedmarkup"
4494 " (chanid, starttime, mark, type, data)"
4496 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4499 query.
bindValue(
":MARK", (quint64)frame);
4510 QString qstr = QString(
4511 "SELECT recordedmarkup.data "
4512 "FROM recordedmarkup "
4513 "WHERE recordedmarkup.chanid = :CHANID AND "
4514 " recordedmarkup.starttime = :STARTTIME AND "
4515 " recordedmarkup.type = :TYPE "
4516 "GROUP BY recordedmarkup.data "
4517 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4518 " FROM recordedmarkup AS rm "
4519 " WHERE rm.chanid = recordedmarkup.chanid AND "
4520 " rm.starttime = recordedmarkup.starttime AND "
4521 " rm.type = recordedmarkup.type AND "
4522 " rm.mark > recordedmarkup.mark "
4523 " ORDER BY rm.mark ASC LIMIT 1 "
4524 " ) - recordedmarkup.mark "
4532 query.
bindValue(
":STARTTIME", recstartts);
4540 return (query.
next()) ? query.
value(0).toUInt() : 0;
4546 QString qstr = QString(
4547 "SELECT filemarkup.`offset` "
4549 "WHERE filemarkup.filename = :PATH AND "
4550 " filemarkup.type = :TYPE "
4551 "GROUP BY filemarkup.`offset` "
4552 "ORDER BY SUM( ( SELECT IFNULL(fm.mark, filemarkup.mark)"
4553 " FROM filemarkup AS fm "
4554 " WHERE fm.filename = filemarkup.filename AND "
4555 " fm.type = filemarkup.type AND "
4556 " fm.mark > filemarkup.mark "
4557 " ORDER BY fm.mark ASC LIMIT 1 "
4558 " ) - filemarkup.mark "
4573 return (query.
next()) ? query.
value(0).toUInt() : 0;
4607 query.
prepare(
"SELECT recordedmarkup.type "
4608 "FROM recordedmarkup "
4609 "WHERE recordedmarkup.chanid = :CHANID AND "
4610 " recordedmarkup.starttime = :STARTTIME AND "
4611 " recordedmarkup.type >= :ASPECTSTART AND "
4612 " recordedmarkup.type <= :ASPECTEND "
4613 "GROUP BY recordedmarkup.type "
4614 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4615 " SELECT MAX(rmmax.mark) "
4616 " FROM recordedmarkup AS rmmax "
4617 " WHERE rmmax.chanid = recordedmarkup.chanid "
4618 " AND rmmax.starttime = recordedmarkup.starttime "
4620 " FROM recordedmarkup AS rm "
4621 " WHERE rm.chanid = recordedmarkup.chanid AND "
4622 " rm.starttime = recordedmarkup.starttime AND "
4623 " rm.type >= :ASPECTSTART2 AND "
4624 " rm.type <= :ASPECTEND2 AND "
4625 " rm.mark > recordedmarkup.mark "
4626 " ORDER BY rm.mark ASC LIMIT 1 "
4627 " ) - recordedmarkup.mark "
4698 QVector<MarkupEntry> &mapSeek)
const
4704 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4705 " WHERE filename = :PATH"
4706 " AND type NOT IN (:KEYFRAME,:DURATION)"
4707 " ORDER BY mark, type;");
4714 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4715 " WHERE chanid = :CHANID"
4716 " AND STARTTIME = :STARTTIME"
4717 " ORDER BY mark, type");
4730 while (query.
next())
4733 uint64_t frame = query.
value(1).toLongLong();
4735 bool isDataNull = query.
value(2).isNull();
4737 data = query.
value(2).toLongLong();
4744 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4745 " WHERE filename = :PATH"
4746 " AND type IN (:KEYFRAME,:DURATION)"
4747 " ORDER BY mark, type;");
4754 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4755 " WHERE chanid = :CHANID"
4756 " AND STARTTIME = :STARTTIME"
4757 " ORDER BY mark, type");
4766 while (query.
next())
4769 uint64_t frame = query.
value(1).toLongLong();
4771 bool isDataNull = query.
value(2).isNull();
4773 data = query.
value(2).toLongLong();
4779 const QVector<MarkupEntry> &mapSeek)
const
4785 if (mapMark.isEmpty())
4787 LOG(VB_GENERAL, LOG_INFO,
4788 QString(
"No mark entries in input, "
4789 "not removing marks from DB"));
4793 query.
prepare(
"DELETE FROM filemarkup"
4794 " WHERE filename = :PATH"
4795 " AND type NOT IN (:KEYFRAME,:DURATION)");
4804 for (
const auto& entry : std::as_const(mapMark))
4808 if (entry.isDataNull)
4810 query.
prepare(
"INSERT INTO filemarkup"
4811 " (filename,type,mark)"
4812 " VALUES (:PATH,:TYPE,:MARK)");
4816 query.
prepare(
"INSERT INTO filemarkup"
4817 " (filename,type,mark,`offset`)"
4818 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4819 query.
bindValue(
":OFFSET", (quint64)entry.data);
4823 query.
bindValue(
":MARK", (quint64)entry.frame);
4831 if (mapSeek.isEmpty())
4833 LOG(VB_GENERAL, LOG_INFO,
4834 QString(
"No seek entries in input, "
4835 "not removing marks from DB"));
4839 query.
prepare(
"DELETE FROM filemarkup"
4840 " WHERE filename = :PATH"
4841 " AND type IN (:KEYFRAME,:DURATION)");
4850 for (
int i = 0; i < mapSeek.size(); ++i)
4852 if (i > 0 && (i % 1000 == 0))
4854 LOG(VB_GENERAL, LOG_INFO,
4855 QString(
"Inserted %1 of %2 records")
4856 .arg(i).arg(mapSeek.size()));
4859 query.
prepare(
"INSERT INTO filemarkup"
4860 " (filename,type,mark,`offset`)"
4861 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4876 if (mapMark.isEmpty())
4878 LOG(VB_GENERAL, LOG_INFO,
4879 QString(
"No mark entries in input, "
4880 "not removing marks from DB"));
4884 query.
prepare(
"DELETE FROM recordedmarkup"
4885 " WHERE chanid = :CHANID"
4886 " AND starttime = :STARTTIME");
4894 for (
const auto& entry : std::as_const(mapMark))
4896 if (entry.isDataNull)
4898 query.
prepare(
"INSERT INTO recordedmarkup"
4899 " (chanid,starttime,type,mark)"
4900 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4904 query.
prepare(
"INSERT INTO recordedmarkup"
4905 " (chanid,starttime,type,mark,data)"
4906 " VALUES (:CHANID,:STARTTIME,"
4907 " :TYPE,:MARK,:OFFSET)");
4908 query.
bindValue(
":OFFSET", (quint64)entry.data);
4913 query.
bindValue(
":MARK", (quint64)entry.frame);
4921 if (mapSeek.isEmpty())
4923 LOG(VB_GENERAL, LOG_INFO,
4924 QString(
"No seek entries in input, "
4925 "not removing marks from DB"));
4929 query.
prepare(
"DELETE FROM recordedseek"
4930 " WHERE chanid = :CHANID"
4931 " AND starttime = :STARTTIME");
4939 for (
int i = 0; i < mapSeek.size(); ++i)
4941 if (i > 0 && (i % 1000 == 0))
4943 LOG(VB_GENERAL, LOG_INFO,
4944 QString(
"Inserted %1 of %2 records")
4945 .arg(i).arg(mapSeek.size()));
4948 query.
prepare(
"INSERT INTO recordedseek"
4949 " (chanid,starttime,type,mark,`offset`)"
4950 " VALUES (:CHANID,:STARTTIME,"
4951 " :TYPE,:MARK,:OFFSET)");
4971 LOG(VB_RECORD, LOG_INFO,
4972 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4973 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
4976 "UPDATE recordedprogram "
4977 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
4978 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
4981 query.
bindValue(
":FLAGS", video_property_flags);
4991 videoproperties &= ~mask;
4992 videoproperties |= video_property_flags;
5010 QString chan(format);
5020 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
5040 "SET season = :SEASON, episode = :EPISODE "
5041 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5042 "AND recordid = :RECORDID");
5064 "SET inetref = :INETREF "
5065 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5066 "AND recordid = :RECORDID");
5105 query.
prepare(
"SELECT password FROM recgroups "
5106 "WHERE recgroup = :GROUP");
5110 result = query.
value(0).toString();
5120 query.
prepare(
"SELECT recgroup FROM recorded "
5121 "WHERE chanid = :CHANID AND "
5122 " starttime = :START");
5128 grp = query.
value(0).toString();
5136 query.
prepare(
"SELECT transcoder FROM recorded "
5137 "WHERE chanid = :CHANID AND "
5138 " starttime = :START");
5143 return query.
value(0).toUInt();
5161 if (path.startsWith(
"/"))
5163 QFileInfo testFile(path);
5164 return testFile.path();
5175 if (testFile.exists())
5177 if (testFile.isSymLink())
5180 if (testFile.isFile())
5181 return testFile.path();
5182 if (testFile.isDir())
5183 return testFile.filePath();
5187 testFile.setFile(testFile.absolutePath());
5188 if (testFile.exists())
5190 if (testFile.isSymLink())
5193 if (testFile.isDir())
5194 return testFile.filePath();
5213 bool notifyOfChange =
false;
5219 if (!usedFor.isEmpty())
5225 LOG(VB_GENERAL, LOG_INFO,
LOC +
5226 QString(
"MarkAsInUse(true, '%1'->'%2')")
5228 " -- use has changed");
5232 LOG(VB_GENERAL, LOG_INFO,
LOC +
5233 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5242 .arg(QObject::tr(
"Unknown")).arg(getpid());
5243 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5245 " -- use was not explicitly set");
5248 notifyOfChange =
true;
5253 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5254 QString(
"MarkAsInUse(false, '%1'->'%2')")
5256 " -- use has changed since first setting as in use.");
5261 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5271 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5272 "MarkAsInUse requires a key to delete in use mark");
5280 "DELETE FROM inuseprograms "
5281 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5282 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5307 "FROM inuseprograms "
5308 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5309 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5319 else if (!query.
next())
5321 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5323 else if (query.
value(0).toBool())
5326 "UPDATE inuseprograms "
5327 "SET lastupdatetime = :UPDATETIME "
5328 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5329 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5334 query.
bindValue(
":UPDATETIME", inUseTime);
5344 "INSERT INTO inuseprograms "
5345 " (chanid, starttime, recusage, hostname, "
5346 " lastupdatetime, rechost, recdir) "
5348 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5349 " :UPDATETIME, :RECHOST, :RECDIR)");
5354 query.
bindValue(
":UPDATETIME", inUseTime);
5366 if (!notifyOfChange)
5371 query.
prepare(
"SELECT DISTINCT recusage "
5372 "FROM inuseprograms "
5373 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5374 " chanid = :CHANID AND "
5375 " starttime = :STARTTIME");
5378 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5382 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5383 while (query.
next())
5385 QString inUseForWhat = query.
value(0).toString();
5407 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5408 "FROM channel, capturecard "
5409 "WHERE channel.chanid = :CHANID AND "
5410 " capturecard.sourceid = :SOURCEID AND "
5411 " capturecard.cardid = :INPUTID");
5418 channum = query.
value(0).toString();
5419 input = query.
value(1).toString();
5428 static bool s_done =
false;
5429 static QMutex s_initTrLock;
5430 QMutexLocker locker(&s_initTrLock);
5434 QString rec_profile_names =
5435 QObject::tr(
"Default",
"Recording Profile Default") +
5436 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5437 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5438 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5439 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5440 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5441 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5444 QString rec_profile_groups =
5445 QObject::tr(
"CRC IP Recorders",
5446 "Recording Profile Group Name") +
5447 QObject::tr(
"FireWire Input",
5448 "Recording Profile Group Name") +
5449 QObject::tr(
"Freebox Input",
5450 "Recording Profile Group Name") +
5451 QObject::tr(
"Hardware DVB Encoders",
5452 "Recording Profile Group Name") +
5453 QObject::tr(
"Hardware HDTV",
5454 "Recording Profile Group Name") +
5455 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5456 "Recording Profile Group Name") +
5457 QObject::tr(
"HD-PVR Recorders",
5458 "Recording Profile Group Name") +
5459 QObject::tr(
"HDHomeRun Recorders",
5460 "Recording Profile Group Name") +
5461 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5462 "Recording Profile Group Name") +
5463 QObject::tr(
"Software Encoders (V4L based)",
5464 "Recording Profile Group Name") +
5465 QObject::tr(
"Transcoders",
5466 "Recording Profile Group Name") +
5467 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5468 "Recording Profile Group Name") +
5469 QObject::tr(
"V4L2 Encoders",
5470 "Recording Profile Group Name");
5472 QString display_rec_groups =
5473 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5474 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5475 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5476 QObject::tr(
"Default",
"Recording Group Default") +
5477 QObject::tr(
"Deleted",
"Recording Group Deleted");
5479 QString special_program_groups =
5480 QObject::tr(
"All Programs - %1",
5481 "Show all programs from a specific recording group");
5483 QString storage_groups =
5484 QObject::tr(
"Default",
"Storage Group Name") +
5485 QObject::tr(
"Live TV",
"Storage Group Name") +
5486 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5487 QObject::tr(
"DB Backups",
"Storage Group Name");
5489 QString play_groups =
5490 QObject::tr(
"Default",
"Playback Group Name");
5493 return (rec_profile_names.length() +
5494 rec_profile_groups.length() +
5495 display_rec_groups.length() +
5496 special_program_groups.length() +
5497 storage_groups.length() +
5498 play_groups.length());
5513 QByteArray msg_arr = msg.toLatin1();
5514 QString msg_i18n = QObject::tr(msg_arr.constData());
5515 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5516 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5528 if (pburl.startsWith(
"myth://"))
5530 str.replace(QString(
"%DIR%"), pburl);
5534 QFileInfo dirInfo(pburl);
5535 str.replace(QString(
"%DIR%"), dirInfo.path());
5543 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5544 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5545 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5546 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5547 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5549 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5550 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5551 str.replace(QString(
"%CATEGORY%"),
m_category);
5552 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5554 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5555 str.replace(QString(
"%INETREF%"),
m_inetRef);
5556 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5557 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5558 str.replace(QString(
"%ORIGINALAIRDATE%"),
5560 static const std::array<const QString,4> s_timeStr
5561 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5562 const std::array<const QDateTime *,4> time_dtr
5564 for (
size_t i = 0; i < s_timeStr.size(); i++)
5566 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5567 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5568 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5570 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5571 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5572 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5575 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5580 QMap<QString, uint32_t> inUseMap;
5585 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5586 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5587 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5592 while (query.
next())
5595 query.
value(0).toUInt(),
5598 QString inUseForWhat = query.
value(2).toString();
5600 if (!inUseMap.contains(inUseKey))
5601 inUseMap[inUseKey] = 0;
5604 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5606 inUseMap[inUseKey] |= FL_INUSERECORDING;
5608 inUseMap[inUseKey] |= FL_INUSEOTHER;
5616 QMap<QString,bool> is_job_running;
5619 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5620 "WHERE type = :TYPE");
5623 return is_job_running;
5625 while (query.
next())
5629 int tmpStatus = query.
value(2).toInt();
5630 if ((tmpStatus != 0x0000) &&
5631 (tmpStatus != 0x0001) &&
5632 (!(tmpStatus & 0x0100)))
5639 return is_job_running;
5643 const QString &tmptable,
int recordid)
5648 if (
sched && tmptable.isEmpty())
5656 LOG(VB_GENERAL, LOG_ERR,
5657 "Called from master backend\n\t\t\t"
5658 "with recordid or tmptable, this is not currently supported");
5663 (tmptable.isEmpty()) ?
5664 QString(
"QUERY_GETALLPENDING") :
5665 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5669 LOG(VB_GENERAL, LOG_ALERT,
5670 "LoadFromScheduler(): Error querying master.");
5689 QString columns = QString(
5690 "program.chanid, program.starttime, program.endtime, "
5691 "program.title, program.subtitle, program.description, "
5692 "program.category, channel.channum, channel.callsign, "
5693 "channel.name, program.previouslyshown, channel.commmethod, "
5694 "channel.outputfilters, program.seriesid, program.programid, "
5695 "program.airdate, program.stars, program.originalairdate, "
5696 "program.category_type, oldrecstatus.recordid, "
5697 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5698 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5699 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5700 "program.partnumber, program.parttotal, "
5701 "program.season, program.episode, program.totalepisodes ");
5703 QString querystr = QString(
5707 " LEFT JOIN channel ON program.chanid = channel.chanid "
5708 " LEFT JOIN oldrecorded AS oldrecstatus ON "
5709 " oldrecstatus.future = 0 AND "
5710 " program.title = oldrecstatus.title AND "
5711 " channel.callsign = oldrecstatus.station AND "
5712 " program.starttime = oldrecstatus.starttime "
5723 ", row_number() over ( "
5726 columns +=
"channel.channum, "
5727 " channel.callsign, ";
5729 columns +=
"channel.callsign, ";
5731 columns +=
"program.programid, ";
5734 " program.starttime "
5735 " order by channel.recpriority desc, "
5736 " channel.sourceid, "
5737 " channel.channum+0 "
5739 querystr +=
"WHERE grouprn = 1 ";
5745 querystr += QString(
"LIMIT %1 ").arg(limit);
5746 else if (!querystr.contains(
" LIMIT "))
5747 querystr +=
" LIMIT 20000 ";
5749 MSqlBindings::const_iterator it;
5766 if (start > 0 || limit > 0)
5768 QString countStr = querystr
5769 .arg(
"SQL_CALC_FOUND_ROWS chanid", columns);
5771 for (it = bindings.begin(); it != bindings.end(); ++it)
5773 if (countStr.contains(it.key()))
5783 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5784 count = query.
value(0).toUInt();
5788 querystr += QString(
"OFFSET %1 ").arg(start);
5790 querystr = querystr.arg(
"*", columns);
5792 for (it = bindings.begin(); it != bindings.end(); ++it)
5794 if (querystr.contains(it.key()))
5808 const QString &groupBy,
const QString &orderBy,
5813 QString queryStr =
"";
5815 if (!where.isEmpty())
5816 queryStr.append(QString(
"WHERE %1 ").arg(where));
5818 if (!groupBy.isEmpty())
5819 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5821 if (!orderBy.isEmpty())
5822 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5826 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5836 QString queryStr = sql;
5850 if (!queryStr.contains(
"WHERE"))
5851 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5853 if (!queryStr.contains(
"ORDER BY"))
5855 queryStr +=
" ORDER BY program.starttime, ";
5858 if (chanorder !=
"channum")
5859 queryStr += chanorder +
" ";
5861 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5866 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5876 destination.
clear();
5878 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5880 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5881 "clause, caller should be updated to use "
5882 "start parameter instead");
5885 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5887 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5888 "clause, caller should be updated to use "
5889 "limit parameter instead");
5898 count = query.
size();
5900 while (query.
next())
5904 query.
value(3).toString(),
5906 query.
value(4).toString(),
5908 query.
value(5).toString(),
5909 query.
value(26).toString(),
5910 query.
value(6).toString(),
5912 query.
value(0).toUInt(),
5913 query.
value(7).toString(),
5914 query.
value(8).toString(),
5915 query.
value(9).toString(),
5916 query.
value(12).toString(),
5923 query.
value(13).toString(),
5924 query.
value(14).toString(),
5927 query.
value(16).toFloat(),
5928 query.
value(15).toUInt(),
5929 query.
value(27).toUInt(),
5930 query.
value(28).toUInt(),
5931 query.
value(17).toDate(),
5933 query.
value(19).toUInt(),
5935 query.
value(22).toUInt(),
5938 query.
value(10).toBool(),
5939 query.
value(23).toInt(),
5940 query.
value(24).toInt(),
5941 query.
value(25).toInt(),
5942 query.
value(29).toUInt(),
5943 query.
value(30).toUInt(),
5944 query.
value(31).toUInt(),
5953 const QDateTime& starttime)
5960 QString sSQL =
"WHERE program.chanid = :ChanId "
5961 "AND program.starttime = :StartTime ";
5963 bindings[
":ChanId" ] = chanid;
5964 bindings[
":StartTime"] = starttime;
5969 bool hasConflicts =
false;
5978 if (progList.
empty())
5999 destination.
clear();
6005 "oldrecorded.chanid, starttime, endtime, "
6006 "title, subtitle, description, season, episode, category, seriesid, "
6007 "programid, inetref, channel.channum, channel.callsign, "
6008 "channel.name, findid, rectype, recstatus, recordid, duplicate ";
6013 "LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
6014 "WHERE oldrecorded.future = 0 "
6017 bool hasLimit = querystr.contains(
" LIMIT ",Qt::CaseInsensitive);
6021 if (!hasLimit && !querystr.contains(
" ORDER ",Qt::CaseInsensitive))
6022 querystr +=
" ORDER BY starttime DESC ";
6027 querystr += QString(
"LIMIT %1 ").arg(limit);
6033 nLimit = std::max(nLimit, 100);
6034 querystr += QString(
"LIMIT %1 ").arg(nLimit);
6037 MSqlBindings::const_iterator it;
6054 if (count > 0 && (start > 0 || limit > 0))
6056 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS oldrecorded.chanid");
6058 for (it = bindings.begin(); it != bindings.end(); ++it)
6060 if (countStr.contains(it.key()))
6070 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
6071 count = query.
value(0).toUInt();
6075 querystr += QString(
"OFFSET %1 ").arg(start);
6077 querystr = querystr.arg(columns);
6079 for (it = bindings.begin(); it != bindings.end(); ++it)
6081 if (querystr.contains(it.key()))
6091 while (query.
next())
6094 QString channum = QString(
"#%1").arg(chanid);
6095 QString chansign = channum;
6096 QString channame = channum;
6097 if (!query.
value(12).toString().isEmpty())
6099 channum = query.
value(12).toString();
6100 chansign = query.
value(13).toString();
6101 channame = query.
value(14).toString();
6105 query.
value(3).toString(),
6107 query.
value(4).toString(),
6109 query.
value(5).toString(),
6110 query.
value(6).toUInt(),
6111 query.
value(7).toUInt(),
6112 query.
value(8).toString(),
6114 chanid, channum, chansign, channame,
6116 query.
value(9).toString(), query.
value(10).toString(),
6117 query.
value(11).toString(),
6125 query.
value(18).toUInt(),
6127 query.
value(15).toUInt(),
6129 query.
value(19).toBool()));
6155 bool possiblyInProgressRecordingsOnly,
6156 const QMap<QString,uint32_t> &inUseMap,
6157 const QMap<QString,bool> &isJobRunning,
6158 const QMap<QString, ProgramInfo*> &recMap,
6160 const QString &sortBy,
6164 destination.
clear();
6172 if (possiblyInProgressRecordingsOnly || ignoreLiveTV || ignoreDeleted)
6174 thequery +=
"WHERE ";
6175 if (possiblyInProgressRecordingsOnly)
6177 thequery +=
"(r.endtime >= NOW() AND r.starttime <= NOW()) ";
6181 thequery += QString(
"%1 r.recgroup != 'LiveTV' ")
6182 .arg(possiblyInProgressRecordingsOnly ?
"AND" :
"");
6186 thequery += QString(
"%1 r.recgroup != 'Deleted' ")
6187 .arg((possiblyInProgressRecordingsOnly || ignoreLiveTV)
6192 if (sortBy.isEmpty())
6195 thequery +=
"ORDER BY r.starttime ";
6197 thequery +=
"DESC ";
6201 QStringList sortByFields;
6202 sortByFields <<
"starttime" <<
"title" <<
"subtitle" <<
"season" <<
"episode" <<
"category"
6203 <<
"watched" <<
"stars" <<
"originalairdate" <<
"recgroup" <<
"storagegroup"
6204 <<
"channum" <<
"callsign" <<
"name" <<
"filesize" <<
"duration";
6207 QStringList fields = sortBy.split(
",");
6208 for (
const QString& oneField : std::as_const(fields))
6210 bool ascending =
true;
6211 QString field = oneField.simplified().toLower();
6213 if (field.endsWith(
"desc"))
6216 field = field.remove(
"desc");
6219 if (field.endsWith(
"asc"))
6222 field = field.remove(
"asc");
6225 field = field.simplified();
6227 if (field ==
"channelname")
6230 if (sortByFields.contains(field))
6233 if (field ==
"channum" || field ==
"callsign" || field ==
"name")
6238 if (field ==
"channum")
6241 field =
"channum*1000-ifnull(regexp_substr(c.channum,'-.*'),0)";
6244 else if (field ==
"duration")
6246 field =
"timestampdiff(second,r.starttime,r.endtime)";
6250 else if (field ==
"season")
6252 field =
"if(r.season,r.season,p.season)";
6256 else if (field ==
"episode")
6258 field =
"if(r.episode,r.episode,p.episode)";
6262 else if (field ==
"title")
6265 QString prefixes = sh->getPrefixes();
6266 field =
"REGEXP_REPLACE(r.title,'" + prefixes +
"','')";
6270 else if (field ==
"subtitle")
6273 QString prefixes = sh->getPrefixes();
6274 field =
"REGEXP_REPLACE(r.subtitle,'" + prefixes +
"','')";
6278 else if (field ==
"originalairdate")
6280 field =
"IF(r.originalairdate != '0000-00-00', r.originalairdate, STR_TO_DATE(CONCAT(p.airdate,',01,01'),'%Y,%m,%d'))";
6284 if (sSortBy.isEmpty())
6285 sSortBy = QString(
"%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6287 sSortBy += QString(
",%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6291 LOG(VB_GENERAL, LOG_WARNING, QString(
"ProgramInfo::LoadFromRecorded() got an unknown sort field '%1' - ignoring").arg(oneField));
6295 thequery +=
"ORDER BY " + sSortBy;
6307 while (query.
next())
6309 const uint chanid = query.
value(6).toUInt();
6310 QString channum = QString(
"#%1").arg(chanid);
6311 QString chansign = channum;
6312 QString channame = channum;
6314 if (!query.
value(7).toString().isEmpty())
6316 channum = query.
value(7).toString();
6317 chansign = query.
value(8).toString();
6318 channame = query.
value(9).toString();
6319 chanfilt = query.
value(10).toString();
6331 recMap.contains(key))
6336 bool save_not_commflagged =
false;
6343 set_flag(flags, FL_COMMPROCESSING ,
6348 set_flag(flags, FL_DELETEPENDING, query.
value(35).toBool());
6352 set_flag(flags, FL_REALLYEDITING, query.
value(39).toBool());
6357 if (inUseMap.contains(key))
6358 flags |= inUseMap[key];
6360 if (((flags & FL_COMMPROCESSING) != 0U) &&
6361 (!isJobRunning.contains(key)))
6363 flags &= ~FL_COMMPROCESSING;
6364 save_not_commflagged =
true;
6368 ((flags & FL_REALLYEDITING) != 0U) ||
6374 season = query.
value(51).toUInt();
6379 episode = query.
value(52).toUInt();
6382 uint totalepisodes = query.
value(53).toUInt();
6386 query.
value(55).toUInt(),
6387 query.
value(0).toString(),
6389 query.
value(1).toString(),
6391 query.
value(2).toString(),
6395 query.
value(48).toString(),
6396 query.
value(5).toString(),
6398 chanid, channum, chansign, channame, chanfilt,
6400 query.
value(11).toString(), query.
value(12).toString(),
6402 query.
value(14).toString(),
6406 query.
value(17).toString(), query.
value(18).toString(),
6407 query.
value(19).toString(),
6410 query.
value(16).toInt(),
6412 query.
value(20).toULongLong(),
6419 query.
value(23).toFloat(),
6421 query.
value(26).toUInt(),
6422 query.
value(49).toUInt(),
6423 query.
value(50).toUInt(),
6424 query.
value(27).toDate(),
6429 query.
value(29).toUInt(),
6434 query.
value(45).toUInt(),
6437 query.
value(42).toUInt(),
6438 query.
value(43).toUInt(),
6439 query.
value(44).toUInt(),
6440 query.
value(56).toString(),
6444 if (save_not_commflagged)
6453 std::vector<ProgramInfo> *list)
6455 nextRecordingStart = QDateTime();
6458 bool *conflicts = (hasConflicts) ? hasConflicts : &dummy;
6465 for (
auto *prog : progList)
6469 (nextRecordingStart.isNull() ||
6470 nextRecordingStart > prog->GetRecordingStartTime()))
6472 nextRecordingStart = prog->GetRecordingStartTime();
6480 for (
auto & prog : progList)
6484 (prog->GetRecordingStartTime() == nextRecordingStart))
6524 "SET filesize = :FILESIZE "
6525 "WHERE chanid = :CHANID AND "
6526 " starttime = :STARTTIME");
6527 query.
bindValue(
":FILESIZE", (quint64)fsize);
6558 uint64_t db_filesize = 0;
6565 "WHERE chanid = :CHANID AND "
6566 " starttime = :STARTTIME");
6570 db_filesize = query.
value(0).toULongLong();
6573 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"RI Filesize=0, DB Filesize=%1")
6587 if (now < startTime)
6591 int current = startTime.secsTo(now);
6592 int duration = startTime.secsTo(endTime);
6597 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 recorded percent %2/%3 = %4%")
6626 total = rate1000 * duration / 1000;
6638 LOG(VB_GUI, LOG_DEBUG,
6639 QString(
"%1 %2 no frame count. Please rebuild seek table for this video.")
6644 LOG(VB_GUI, LOG_DEBUG,
6645 QString(
"%1 %2 no frame count. Please rebuild seek table for this recording.")
6653 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 %2 watched percent %3/%4 = %5%")
6671 return tr(
"Channel Number");
6673 return tr(
"CallSign");
6675 return tr(
"ProgramId");
6677 return tr(
"Unknown");
6683 QStringList strlist(
"QUERY_CHECKFILE");
6684 strlist << QString::number((
int)checkSlaves);
6688 (strlist.size() < 2) || !strlist[0].toInt())
6693 QString localpath = strlist[1];
6694 QFile checkFile(localpath);
6695 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.