33#define LOC QString("ProgramInfo(%1): ").arg(GetBasename())
48#define DEFINE_FLAGS_NAMES
50#undef DEFINE_FLAGS_NAMES
53 "SELECT r.title, r.subtitle, r.description, "
54 " r.season, r.episode, r.category, "
55 " r.chanid, c.channum, c.callsign, "
56 " c.name, c.outputfilters,r.recgroup, "
57 " r.playgroup, r.storagegroup, r.basename, "
58 " r.hostname, r.recpriority, r.seriesid, "
59 " r.programid, r.inetref, r.filesize, "
60 " r.progstart, r.progend, r.stars, "
61 " r.starttime, r.endtime, p.airdate+0, "
62 " r.originalairdate, r.lastmodified, r.recordid, "
63 " c.commmethod, r.commflagged, r.previouslyshown, "
64 " r.transcoder, r.transcoded, r.deletepending, "
65 " r.preserve, r.cutlist, r.autoexpire, "
66 " r.editing, r.bookmark, r.watched, "
67 " p.audioprop+0, p.videoprop+0, p.subtitletypes+0, "
68 " r.findid, rec.dupin, rec.dupmethod, "
69 " p.syndicatedepisodenumber, p.partnumber, p.parttotal, "
70 " p.season, p.episode, p.totalepisodes, "
71 " p.category_type, r.recordedid, r.inputname, "
72 " r.bookmarkupdate, r.lastplay "
74 "LEFT JOIN channel AS c "
75 "ON (r.chanid = c.chanid) "
76 "LEFT JOIN recordedprogram AS p "
77 "ON (r.chanid = p.chanid AND "
78 " r.progstart = p.starttime) "
79 "LEFT JOIN record AS rec "
80 "ON (r.recordid = rec.recordid) ";
82static void set_flag(uint32_t &flags,
int flag_to_set,
bool is_set)
84 flags &= ~flag_to_set;
93 if (!url.startsWith(
"dvd:") && !url.startsWith(
"bd:"))
95 if(url.endsWith(
".img", Qt::CaseInsensitive) ||
96 url.endsWith(
".iso", Qt::CaseInsensitive))
101 result =
"bd:" + url;
105 result =
"dvd:" + url;
115 if (QDir(url +
"/BDMV").
exists())
116 result =
"bd:" + url;
117 else if (QDir(url +
"/VIDEO_TS").
exists())
118 result =
"dvd:" + url;
125static const std::array<const QString,ProgramInfo::kNumCatTypes>
kCatName
126{
"",
"movie",
"series",
"sports",
"tvshow" };
139 for (
size_t i = 1; i <
kCatName.size(); i++)
149 m_title(other.m_title),
150 m_sortTitle(other.m_sortTitle),
151 m_subtitle(other.m_subtitle),
152 m_sortSubtitle(other.m_sortSubtitle),
153 m_description(other.m_description),
154 m_season(other.m_season),
155 m_episode(other.m_episode),
156 m_totalEpisodes(other.m_totalEpisodes),
157 m_syndicatedEpisode(other.m_syndicatedEpisode),
158 m_category(other.m_category),
159 m_director(other.m_director),
161 m_recPriority(other.m_recPriority),
163 m_chanId(other.m_chanId),
164 m_chanStr(other.m_chanStr),
165 m_chanSign(other.m_chanSign),
166 m_chanName(other.m_chanName),
167 m_chanPlaybackFilters(other.m_chanPlaybackFilters),
169 m_recGroup(other.m_recGroup),
170 m_playGroup(other.m_playGroup),
172 m_pathname(other.m_pathname),
174 m_hostname(other.m_hostname),
175 m_storageGroup(other.m_storageGroup),
177 m_seriesId(other.m_seriesId),
178 m_programId(other.m_programId),
179 m_inetRef(other.m_inetRef),
180 m_catType(other.m_catType),
182 m_fileSize(other.m_fileSize),
184 m_startTs(other.m_startTs),
185 m_endTs(other.m_endTs),
186 m_recStartTs(other.m_recStartTs),
187 m_recEndTs(other.m_recEndTs),
189 m_stars(other.m_stars),
191 m_originalAirDate(other.m_originalAirDate),
192 m_lastModified(other.m_lastModified),
195 m_recPriority2(other.m_recPriority2),
196 m_recordId(other.m_recordId),
197 m_parentId(other.m_parentId),
199 m_sourceId(other.m_sourceId),
200 m_inputId(other.m_inputId),
202 m_findId(other.m_findId),
203 m_programFlags(other.m_programFlags),
204 m_videoProperties(other.m_videoProperties),
205 m_audioProperties(other.m_audioProperties),
206 m_subtitleProperties(other.m_subtitleProperties),
207 m_year(other.m_year),
208 m_partNumber(other.m_partNumber),
209 m_partTotal(other.m_partTotal),
211 m_recStatus(other.m_recStatus),
212 m_recType(other.m_recType),
213 m_dupIn(other.m_dupIn),
214 m_dupMethod(other.m_dupMethod),
216 m_recordedId(other.m_recordedId),
217 m_inputName(other.m_inputName),
218 m_bookmarkUpdate(other.m_bookmarkUpdate),
221 m_availableStatus(other.m_availableStatus),
222 m_spread(other.m_spread),
223 m_startCol(other.m_startCol),
226 m_positionMapDBReplacement(other.m_positionMapDBReplacement)
240 "SELECT chanid, starttime "
242 "WHERE recordedid = :RECORDEDID");
243 query.
bindValue(
":RECORDEDID", _recordedid);
253 LOG(VB_GENERAL, LOG_CRIT,
LOC +
254 QString(
"Failed to find recorded entry for %1.")
281 QString _sortSubtitle,
282 QString _description,
286 QString _syndicatedepisode,
293 QString _chanplaybackfilters,
298 const QString &_pathname,
301 QString _storagegroup,
314 QDateTime _recstartts,
322 QDate _originalAirDate,
323 QDateTime _lastmodified,
335 uint _audioproperties,
336 uint _videoproperties,
339 QDateTime _bookmarkupdate) :
340 m_title(std::move(_title)),
341 m_sortTitle(std::move(_sortTitle)),
342 m_subtitle(std::move(_subtitle)),
343 m_sortSubtitle(std::move(_sortSubtitle)),
344 m_description(std::move(_description)),
347 m_totalEpisodes(_totalepisodes),
348 m_syndicatedEpisode(std::move(_syndicatedepisode)),
349 m_category(std::move(_category)),
351 m_recPriority(_recpriority),
354 m_chanStr(std::move(_channum)),
355 m_chanSign(std::move(_chansign)),
356 m_chanName(std::move(_channame)),
357 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
359 m_recGroup(std::move(_recgroup)),
360 m_playGroup(std::move(_playgroup)),
362 m_pathname(_pathname),
364 m_hostname(std::move(_hostname)),
365 m_storageGroup(std::move(_storagegroup)),
367 m_seriesId(std::move(_seriesid)),
368 m_programId(std::move(_programid)),
369 m_inetRef(std::move(_inetref)),
372 m_fileSize(_filesize),
374 m_startTs(std::move(_startts)),
375 m_endTs(std::move(_endts)),
376 m_recStartTs(std::move(_recstartts)),
377 m_recEndTs(std::move(_recendts)),
379 m_stars(std::
clamp(_stars, 0.0F, 1.0F)),
381 m_originalAirDate(_originalAirDate),
382 m_lastModified(std::move(_lastmodified)),
385 m_recordId(_recordid),
388 m_programFlags(_programflags),
389 m_videoProperties(_videoproperties),
390 m_audioProperties(_audioproperties),
391 m_subtitleProperties(_subtitleType),
393 m_partNumber(_partnumber),
394 m_partTotal(_parttotal),
396 m_recStatus(_recstatus),
398 m_dupMethod(_dupmethod),
400 m_recordedId(_recordedid),
401 m_inputName(std::move(_inputname)),
402 m_bookmarkUpdate(std::move(_bookmarkupdate))
418 QString _sortSubtitle,
419 QString _description,
435 QDateTime _recstartts,
447 m_title(std::move(_title)),
448 m_sortTitle(std::move(_sortTitle)),
449 m_subtitle(std::move(_subtitle)),
450 m_sortSubtitle(std::move(_sortSubtitle)),
451 m_description(std::move(_description)),
454 m_category(std::move(_category)),
457 m_chanStr(std::move(_channum)),
458 m_chanSign(std::move(_chansign)),
459 m_chanName(std::move(_channame)),
461 m_seriesId(std::move(_seriesid)),
462 m_programId(std::move(_programid)),
463 m_inetRef(std::move(_inetref)),
465 m_startTs(std::move(_startts)),
466 m_endTs(std::move(_endts)),
467 m_recStartTs(std::move(_recstartts)),
468 m_recEndTs(std::move(_recendts)),
470 m_lastModified(m_startTs),
473 m_recordId(_recordid),
476 m_programFlags((duplicate) ? FL_DUPLICATE : FL_NONE),
478 m_recStatus(_recstatus),
493 QString _sortSubtitle,
494 QString _description,
495 QString _syndicatedepisode,
502 QString _chanplaybackfilters,
506 QDateTime _recstartts,
518 QDate _originalAirDate,
527 uint _videoproperties,
528 uint _audioproperties,
536 m_title(std::move(_title)),
537 m_sortTitle(std::move(_sortTitle)),
538 m_subtitle(std::move(_subtitle)),
539 m_sortSubtitle(std::move(_sortSubtitle)),
540 m_description(std::move(_description)),
543 m_totalEpisodes(_totalepisodes),
544 m_syndicatedEpisode(std::move(_syndicatedepisode)),
545 m_category(std::move(_category)),
548 m_chanStr(std::move(_channum)),
549 m_chanSign(std::move(_chansign)),
550 m_chanName(std::move(_channame)),
551 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
553 m_seriesId(std::move(_seriesid)),
554 m_programId(std::move(_programid)),
557 m_startTs(std::move(_startts)),
558 m_endTs(std::move(_endts)),
559 m_recStartTs(std::move(_recstartts)),
560 m_recEndTs(std::move(_recendts)),
562 m_stars(std::
clamp(_stars, 0.0F, 1.0F)),
564 m_originalAirDate(_originalAirDate),
565 m_lastModified(m_startTs),
566 m_lastInUseTime(m_startTs.addSecs(-kLastInUseOffset)),
568 m_recordId(_recordid),
571 m_videoProperties(_videoproperties),
572 m_audioProperties(_audioproperties),
573 m_subtitleProperties(_subtitleType),
575 m_partNumber(_partnumber),
576 m_partTotal(_parttotal),
578 m_recStatus(_recstatus),
587 for (
auto *it : schedList)
637 QString _sortSubtitle,
638 QString _description,
648 QString _chanplaybackfilters,
655 QDateTime _recstartts,
661 QString _inputname) :
662 m_title(std::move(_title)),
663 m_sortTitle(std::move(_sortTitle)),
664 m_subtitle(std::move(_subtitle)),
665 m_sortSubtitle(std::move(_sortSubtitle)),
666 m_description(std::move(_description)),
669 m_totalEpisodes(_totalepisodes),
670 m_category(std::move(_category)),
673 m_chanStr(std::move(_channum)),
674 m_chanSign(std::move(_chansign)),
675 m_chanName(std::move(_channame)),
676 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
678 m_recGroup(std::move(_recgroup)),
679 m_playGroup(std::move(_playgroup)),
681 m_seriesId(std::move(_seriesid)),
682 m_programId(std::move(_programid)),
683 m_inetRef(std::move(_inetref)),
685 m_startTs(std::move(_startts)),
686 m_endTs(std::move(_endts)),
687 m_recStartTs(std::move(_recstartts)),
688 m_recEndTs(std::move(_recendts)),
691 m_lastInUseTime(m_lastModified.addSecs(-kLastInUseOffset)),
693 m_inputName(std::move(_inputname))
704 if (_pathname.isEmpty())
710 QDateTime _recstartts;
724 QString basename = _pathname.section(
'/', -1);
725 if (_pathname == basename)
726 SetPathname(QDir::currentPath() +
'/' + _pathname);
727 else if (_pathname.contains(
"./") && !_pathname.contains(
":"))
728 SetPathname(QFileInfo(_pathname).absoluteFilePath());
738 const QString &_plot,
739 const QString &_title,
740 const QString &_sortTitle,
741 const QString &_subtitle,
742 const QString &_sortSubtitle,
743 const QString &_director,
744 int _season,
int _episode,
745 const QString &_inetref,
746 std::chrono::minutes length_in_minutes,
748 const QString &_programid)
768 int64_t minutes = length_in_minutes.count();
771#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
775 QTimeZone(QTimeZone::UTC));
779 QString pn = _pathname;
780 if (!_pathname.startsWith(
"myth://"))
791 const QDateTime &_startts,
792 const QDateTime &_endts)
798 "SELECT chanid, channum, callsign, name, outputfilters, commmethod "
800 "WHERE chanid=:CHANID");
819 QString channelFormat =
827 QString(
"%1 (%2)").arg(
m_title, QObject::tr(
"Manual Record"));
845 bool ignore_non_serialized_data)
873 if (!ignore_non_serialized_data || !is_same ||
929 if (!ignore_non_serialized_data)
1035 if (a.isEmpty() and (b ==
"Default"))
1037 if ((a ==
"Default") and b.isEmpty())
1177 uint chanid,
const QDateTime &recstartts)
1179 return QString(
"%1_%2").arg(chanid).arg(recstartts.toString(
Qt::ISODate));
1186 uint &chanid, QDateTime &recstartts)
1188 QStringList keyParts = uniquekey.split(
'_');
1189 if (keyParts.size() != 2)
1191 chanid = keyParts[0].toUInt();
1193 return (chanid != 0U) && recstartts.isValid();
1197 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1199 QString basename = pathname.section(
'/', -1);
1200 if (basename.isEmpty())
1203 QStringList lr = basename.split(
"_");
1206 chanid = lr[0].toUInt();
1207 QStringList ts = lr[1].split(
".");
1208 if (chanid && !ts.empty())
1211 return recstartts.isValid();
1219 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1221 QString basename = pathname.section(
'/', -1);
1222 if (basename.isEmpty())
1227 "SELECT chanid, starttime "
1229 "WHERE basename = :BASENAME");
1233 chanid = query.
value(0).toUInt();
1244 QString basename = pathname.section(
'/', -1);
1245 if (basename.isEmpty())
1250 "SELECT recordedid "
1252 "WHERE basename = :BASENAME");
1256 recordedid = query.
value(0).toUInt();
1265 return QString::number(x.toSecsSinceEpoch());
1280 list << QString::number(
m_season );
1304 list << QString::number(
m_dupIn);
1316 list << QString(
"%1").arg(
m_stars);
1326 list << QString::number(
m_year);
1340#define NEXT_STR() do { if (it == listend) \
1342 LOG(VB_GENERAL, LOG_ERR, listerror); \
1346 ts = *it++; } while (false)
1357 if (str.isEmpty() || (str ==
"0000-00-00"))
1375 const QStringList::const_iterator& listend)
1377 QString listerror =
LOC +
"FromStringList, not enough items in list.";
1441 if (!origChanid || !origRecstartts.isValid() ||
1456template <
typename T>
1461 return propNames[0];
1464 for (
uint i = 0; i < (
sizeof(T)*8) - 1; ++i)
1467 if ((props & bit) == 0)
1469 if (propNames.contains(bit))
1471 result += propNames[bit];
1475 if (bit & FL_TYPEMASK)
1477 QString tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1478 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1482 return result.join(
'|');
1485template <
typename T>
1487 const QString& props)
1489 if (props.isEmpty())
1494 QStringList names = props.split(
'|');
1495 for (
const auto& n : std::as_const(names) )
1497 uint bit = propNames.key(n, 0);
1500 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1538 tmp_rec += QObject::tr(
"Re-Record");
1593 uint date_format)
const
1598 QString channelFormat =
1600 QString longChannelFormat =
1610 QString tempSubTitle =
m_title;
1614 tempSubTitle = QString(
"%1 - \"%2\"")
1616 tempSortSubtitle = QString(
"%1 - \"%2\"")
1620 progMap[
"titlesubtitle"] = tempSubTitle;
1621 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1623 progMap[
"description"] = progMap[
"description0"]
1627 progMap[
"season"] = progMap[
"episode"] =
"";
1628 progMap[
"totalepisodes"] =
"";
1629 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1632 progMap[
"seasonepisode"] =
"";
1641 progMap[
"s00e00"] = QString(
"s%1e%2")
1644 progMap[
"00x00"] = QString(
"%1x%2")
1648 if (progMap[
"seasonepisode"].isEmpty())
1650 progMap[
"seasonepisode"] = QString(
"s%1e%2")
1659 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1663 progMap[
"starttime"] =
"";
1664 progMap[
"startdate"] =
"";
1665 progMap[
"endtime"] =
"";
1666 progMap[
"enddate"] =
"";
1667 progMap[
"recstarttime"] =
"";
1668 progMap[
"recstartdate"] =
"";
1669 progMap[
"recendtime"] =
"";
1670 progMap[
"recenddate"] =
"";
1674 progMap[
"startdate"] =
"";
1675 progMap[
"recstartdate"] =
"";
1679 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1680 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1687 progMap[
"startdate"] =
1697 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1698 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1699 if (timeNow.toLocalTime().date().year() !=
1701 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1702 if (timeNow.toLocalTime().date().year() !=
1703 m_endTs.toLocalTime().date().year())
1704 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1708 progMap[
"timedate"] =
1712 progMap[
"shorttimedate"] =
1716 progMap[
"starttimedate"] =
1719 progMap[
"shortstarttimedate"] =
1723 progMap[
"lastmodifieddate"] =
1725 progMap[
"lastmodified"] =
1732 progMap[
"chanid"] = QString::number(
m_chanId);
1735 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1737 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1738 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1740 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1743 int minutes = seconds / 60;
1745 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1747 progMap[
"lenmins"] = min_str;
1748 int hours = minutes / 60;
1749 minutes = minutes % 60;
1751 progMap[
"lentime"] = min_str;
1752 if (hours > 0 && minutes > 0)
1754 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1755 progMap[
"lentime"] = QString(
"%1 %2")
1756 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1760 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1763 progMap[
"recordedpercent"] =
1766 progMap[
"watchedpercent"] =
1784 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1789 progMap[
"storagegroup"] = QObject::tr(
"Default");
1795 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1819 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1820 progMap[
"longrepeat"] = progMap[
"repeat"];
1823 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1824 .arg(QObject::tr(
"Repeat"),
1832 progMap[
"repeat"] =
"";
1833 progMap[
"longrepeat"] =
"";
1841 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1846 QString star_str = (
m_stars != 0.0F) ?
1847 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1848 progMap[
"stars"] = star_str;
1849 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1852 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1854 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1856 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1858 progMap[
"yearstars"] =
"";
1863 progMap[
"originalairdate"] =
"";
1864 progMap[
"shortoriginalairdate"] =
"";
1878 QString mediaTypeString;
1882 mediaType =
"video";
1883 mediaTypeString = QObject::tr(
"Video");
1887 mediaTypeString = QObject::tr(
"DVD");
1890 mediaType =
"httpstream";
1891 mediaTypeString = QObject::tr(
"HTTP Streaming");
1894 mediaType =
"rtspstream";
1895 mediaTypeString = QObject::tr(
"RTSP Streaming");
1898 mediaType =
"bluraydisc";
1899 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1903 mediaType =
"recording";
1904 mediaTypeString = QObject::tr(
"Recording",
1905 "Recorded file, object not action");
1907 progMap[
"mediatype"] = mediaType;
1908 progMap[
"mediatypestring"] = mediaTypeString;
1916 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1928 uint64_t last_frame = 0;
1937 if (!posMap.empty())
1939 frm_pos_map_t::const_iterator it = posMap.constEnd();
1941 last_frame = it.key();
1948 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1975 str +=
" startts(" +
1978 ") recendts(" +
m_recEndTs.toString() +
")\n";
1979 str +=
" title(" +
m_title +
")";
1987 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1992 str = QString(
"%1 at %2")
1996 str = QString(
"%1 @ %2")
2019 const uint _chanid,
const QDateTime &_recstartts)
2021 if (!_chanid || !_recstartts.isValid())
2030 "WHERE r.chanid = :CHANID AND "
2031 " r.starttime = :RECSTARTTS");
2033 query.
bindValue(
":RECSTARTTS", _recstartts);
2086 if (!query.
value(7).toString().isEmpty())
2100 QString new_basename = query.
value(14).toString();
2101 if ((
GetBasename() != new_basename) || !is_reload)
2105 LOG(VB_FILE, LOG_INFO,
LOC +
2106 QString(
"Updated pathname '%1':'%2' -> '%3'")
2242 if (index == oindex && (index < 0 ||
2301 if (index == oindex && (index < 0 ||
2396 QMap<QString, int> authMap;
2397 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2400 for (
const QString& table : tables)
2403 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2404 "FROM %1 WHERE programid <> ''").arg(table));
2409 while (query.
next())
2410 authMap[query.
value(0).toString()] = 1;
2414 int numAuths = authMap.count();
2415 LOG(VB_GENERAL, LOG_INFO,
2416 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2429 QString retval = QString(
"%1_%2.%3")
2430 .arg(QString::number(
m_chanId), starts, ext);
2436 uint chanid,
const QString &pathname,
bool use_remote)
2438 QString fn_lower = pathname.toLower();
2442 else if (fn_lower.startsWith(
"http:"))
2444 else if (fn_lower.startsWith(
"rtsp:"))
2450 if (fn_lower.startsWith(
"dvd:"))
2454 else if (fn_lower.startsWith(
"bd:"))
2458 else if (use_remote && fn_lower.startsWith(
"myth://"))
2460 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2461 QString tmpFileBD = pathname +
"/BDMV";
2489 LOG(VB_GUI, LOG_INFO,
2504 query.
prepare(
"UPDATE recorded "
2505 "SET basename = :BASENAME "
2506 "WHERE recordedid = :RECORDEDID;");
2516 query.
prepare(
"UPDATE recordedfile "
2517 "SET basename = :BASENAME "
2518 "WHERE recordedid = :RECORDEDID;");
2550 "FROM recordedfile "
2551 "WHERE recordedid = :RECORDEDID;");
2558 else if (query.
next())
2560 return query.
value(0).toString();
2564 LOG(VB_GENERAL, LOG_INFO,
2565 QString(
"QueryBasename found no entry for recording ID %1")
2580 bool checkMaster,
bool forceCheckLocal)
2587 if (basename.isEmpty())
2596 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2599 QUrl url = QUrl(fullpath);
2600 QString path = url.path();
2601 QString host = url.toString(QUrl::RemovePath).mid(7);
2602 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2606 list = host.split(
"@", Qt::SkipEmptyParts);
2608 if (!list.empty() && list.size() < 3)
2610 host = list.size() == 1 ? list[0] : list[1];
2611 group = list.size() == 1 ? QString() : list[0];
2614 if (!local.isEmpty() && sg.
FileExists(local))
2627 LOG(VB_FILE, LOG_DEBUG,
LOC +
2628 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2630 tmpURL = sgroup.
FindFile(basename);
2632 if (!tmpURL.isEmpty())
2634 LOG(VB_FILE, LOG_INFO,
LOC +
2635 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2640 LOG(VB_GENERAL, LOG_ERR,
LOC +
2641 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2642 "not be found.").arg(basename));
2645 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2651 if ((checkMaster) &&
2659 LOG(VB_FILE, LOG_INFO,
LOC +
2660 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2669 LOG(VB_FILE, LOG_INFO,
LOC +
2670 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2684 query.
prepare(
"SELECT mplexid FROM channel "
2685 "WHERE chanid = :CHANID");
2690 else if (query.
next())
2691 ret = query.
value(0).toUInt();
2694 ret = (32767 == ret) ? 0 : ret;
2706 bool is_valid = (frame > 0);
2727 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2728 " bookmark = :BOOKMARKFLAG "
2729 "WHERE recordedid = :RECORDEDID");
2731 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2743 bool isValid = frame > 0;
2768 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2769 " lastplay = :LASTPLAYFLAG "
2770 "WHERE recordedid = :RECORDEDID");
2772 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2803 "SELECT bookmarkupdate "
2805 "WHERE chanid = :CHANID AND"
2806 " starttime = :STARTTIME");
2814 else if (query.
next())
2834 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2844 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2861 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2878 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2886 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2893 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2900 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2907 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2911 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2921 const QString &serialid)
const
2923 QStringList fields = QStringList();
2928 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2929 " FROM dvdbookmark "
2930 " WHERE serialid = :SERIALID ");
2935 QString dvdstate = query.
value(0).toString();
2937 if (!dvdstate.isEmpty())
2939 fields.append(dvdstate);
2944 for(
int i = 1; i < 5; i++)
2945 fields.append(query.
value(i).toString());
2955 QStringList::const_iterator it = fields.begin();
2958 QString serialid = *(it);
2959 QString name = *(++it);
2961 if( fields.count() == 3 )
2964 QString state = *(++it);
2966 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2968 " VALUES ( :SERIALID, :NAME );");
2975 query.
prepare(
" UPDATE dvdbookmark "
2976 " SET dvdstate = :STATE , "
2977 " timestamp = NOW() "
2978 " WHERE serialid = :SERIALID");
2985 query.
prepare(
"DELETE FROM dvdbookmark "
2986 "WHERE serialid = :SERIALID");
2999 QStringList fields = QStringList();
3004 query.
prepare(
" SELECT bdstate FROM bdbookmark "
3005 " WHERE serialid = :SERIALID ");
3009 fields.append(query.
value(0).toString());
3017 QStringList::const_iterator it = fields.begin();
3020 QString serialid = *(it);
3021 QString name = *(++it);
3023 if( fields.count() == 3 )
3026 QString state = *(++it);
3028 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
3030 " VALUES ( :SERIALID, :NAME );");
3037 query.
prepare(
" UPDATE bdbookmark "
3038 " SET bdstate = :STATE , "
3039 " timestamp = NOW() "
3040 " WHERE serialid = :SERIALID");
3047 query.
prepare(
"DELETE FROM bdbookmark "
3048 "WHERE serialid = :SERIALID");
3067 query.
prepare(
" SELECT category_type "
3068 " FROM recordedprogram "
3069 " WHERE chanid = :CHANID "
3070 " AND starttime = :STARTTIME;");
3090 query.
prepare(
"UPDATE recorded"
3091 " SET watched = :WATCHEDFLAG"
3092 " WHERE chanid = :CHANID"
3093 " AND starttime = :STARTTIME ;");
3096 query.
bindValue(
":WATCHEDFLAG", watched);
3108 if (url.startsWith(
"myth://"))
3110 url = QUrl(url).path();
3115 query.
prepare(
"UPDATE videometadata"
3116 " SET watched = :WATCHEDFLAG"
3117 " WHERE title = :TITLE"
3118 " AND subtitle = :SUBTITLE"
3119 " AND filename = :FILENAME ;");
3123 query.
bindValue(
":WATCHEDFLAG", watched);
3142 query.
prepare(
"SELECT editing FROM recorded"
3143 " WHERE chanid = :CHANID"
3144 " AND starttime = :STARTTIME ;");
3149 editing = query.
value(0).toBool();
3166 query.
prepare(
"UPDATE recorded"
3167 " SET editing = :EDIT"
3168 " WHERE chanid = :CHANID"
3169 " AND starttime = :STARTTIME ;");
3191 query.
prepare(
"UPDATE recorded"
3192 " SET deletepending = :DELETEFLAG, "
3194 " WHERE chanid = :CHANID"
3195 " AND starttime = :STARTTIME ;");
3198 query.
bindValue(
":DELETEFLAG", deleteFlag);
3223 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3224 " WHERE chanid = :CHANID"
3225 " AND starttime = :STARTTIME "
3226 " AND lastupdatetime > :ONEHOURAGO ;");
3229 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3232 if (query.
exec() && query.
size() > 0)
3236 while (query.
next())
3238 usageStr = QObject::tr(
"Unknown");
3239 recusage = query.
value(1).toString();
3242 usageStr = QObject::tr(
"Playing");
3244 usageStr = QObject::tr(
"PIP");
3246 usageStr = QObject::tr(
"PBP");
3249 usageStr = QObject::tr(
"Recording");
3251 usageStr = QObject::tr(
"File transfer");
3253 usageStr = QObject::tr(
"Delete");
3255 usageStr = QObject::tr(
"Commercial Detection");
3257 usageStr = QObject::tr(
"Transcoding");
3259 usageStr = QObject::tr(
"Preview Generation");
3261 usageStr = QObject::tr(
"User Job");
3263 byWho.push_back(recusage);
3264 byWho.push_back(query.
value(0).toString());
3265 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3283 for (
int i = 0; i+2 < users.size(); i+=3)
3284 byWho += users[i+2] +
"\n";
3311 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3321 (one_playback_allowed && (play_cnt <= 1)));
3323 ok = ok && (ft_cnt == jq_cnt);
3334 query.
prepare(
"SELECT transcoded FROM recorded"
3335 " WHERE chanid = :CHANID"
3336 " AND starttime = :STARTTIME ;");
3356 "SET transcoded = :VALUE "
3357 "WHERE chanid = :CHANID AND"
3358 " starttime = :STARTTIME");
3377 query.
prepare(
"UPDATE recorded"
3378 " SET commflagged = :FLAG"
3379 " WHERE chanid = :CHANID"
3380 " AND starttime = :STARTTIME ;");
3403 query.
prepare(
"UPDATE recorded"
3404 " SET preserve = :PRESERVE"
3405 " WHERE chanid = :CHANID"
3406 " AND starttime = :STARTTIME ;");
3407 query.
bindValue(
":PRESERVE", preserveEpisode);
3430 query.
prepare(
"UPDATE recorded"
3431 " SET autoexpire = :AUTOEXPIRE"
3432 " WHERE chanid = :CHANID"
3433 " AND starttime = :STARTTIME ;");
3440 else if (updateDelete)
3459 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3460 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3463 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3464 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3465 "WHERE recordid = :RECORDID");
3467 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3471 query.
prepare(
"UPDATE record SET last_delete = NULL "
3472 "WHERE recordid = :RECORDID");
3485 query.
prepare(
"SELECT autoexpire FROM recorded"
3486 " WHERE chanid = :CHANID"
3487 " AND starttime = :STARTTIME ;");
3508 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3510 uint64_t frame = i.key();
3516 delMap[frame] = mark;
3526 return !delMap.isEmpty();
3542 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3544 uint64_t frame = i.key();
3553 tmpDelMap[frame] = mark;
3562 query.
prepare(
"UPDATE recorded"
3563 " SET cutlist = :CUTLIST"
3564 " WHERE chanid = :CHANID"
3565 " AND starttime = :STARTTIME ;");
3567 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3596 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3599 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3602 comp += QString(
" AND type = :TYPE ");
3606 query.
prepare(
"DELETE FROM filemarkup"
3607 " WHERE filename = :PATH "
3613 query.
prepare(
"DELETE FROM recordedmarkup"
3614 " WHERE chanid = :CHANID"
3615 " AND STARTTIME = :STARTTIME"
3632 int64_t min_frame, int64_t max_frame)
const
3644 query.
prepare(
"SELECT starttime FROM recorded"
3645 " WHERE chanid = :CHANID"
3646 " AND starttime = :STARTTIME ;");
3661 frm_dir_map_t::const_iterator it;
3662 for (it = marks.begin(); it != marks.end(); ++it)
3664 uint64_t frame = it.key();
3666 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3669 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3676 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3677 " VALUES ( :PATH , :MARK , :TYPE );");
3682 query.
prepare(
"INSERT INTO recordedmarkup"
3683 " (chanid, starttime, mark, type)"
3684 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3688 query.
bindValue(
":MARK", (quint64)frame);
3705 marks,
type, merge);
3714 const QString &video_pathname,
3723 query.
prepare(
"SELECT mark, type, `offset` "
3725 "WHERE filename = :PATH AND "
3728 query.
bindValue(
":PATH", video_pathname);
3737 while (query.
next())
3741 int entryType = query.
value(1).toInt();
3751 uint chanid,
const QDateTime &recstartts,
3759 query.
prepare(
"SELECT mark, type, data "
3760 "FROM recordedmarkup "
3761 "WHERE chanid = :CHANID AND "
3762 " starttime = :STARTTIME AND"
3766 query.
bindValue(
":STARTTIME", recstartts);
3775 while (query.
next())
3779 int entryType = query.
value(1).toInt();
3794 return flagMap.contains(0);
3822 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3823 " WHERE filename = :PATH"
3824 " AND type = :TYPE ;");
3829 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3830 " WHERE chanid = :CHANID"
3831 " AND starttime = :STARTTIME"
3832 " AND type = :TYPE ;");
3848 while (query.
next())
3849 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3865 query.
prepare(
"DELETE FROM filemarkup"
3866 " WHERE filename = :PATH"
3867 " AND type = :TYPE ;");
3872 query.
prepare(
"DELETE FROM recordedseek"
3873 " WHERE chanid = :CHANID"
3874 " AND starttime = :STARTTIME"
3875 " AND type = :TYPE ;");
3892 int64_t min_frame, int64_t max_frame)
const
3898 if ((min_frame >= 0) || (max_frame >= 0))
3906 uint64_t frame = it.key();
3907 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3909 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3911 new_map.insert(it.key(), *it);
3921 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3923 uint64_t frame = it.key();
3924 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3926 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3930 .insert(frame, *it);
3940 comp +=
" AND mark >= :MIN_FRAME ";
3942 comp +=
" AND mark <= :MAX_FRAME ";
3949 query.
prepare(
"DELETE FROM filemarkup"
3950 " WHERE filename = :PATH"
3957 query.
prepare(
"DELETE FROM recordedseek"
3958 " WHERE chanid = :CHANID"
3959 " AND starttime = :STARTTIME"
3972 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3974 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3979 if (posMap.isEmpty())
3983 QStringList q(
"INSERT INTO ");
3987 q <<
"filemarkup (filename, type, mark, `offset`)";
3988 qfields = QString(
"('%1',%2,") .
3995 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
3996 qfields = QString(
"(%1,'%2',%3,") .
4003 bool add_comma =
false;
4004 frm_pos_map_t::iterator it;
4005 for (it = posMap.begin(); it != posMap.end(); ++it)
4007 uint64_t frame = it.key();
4009 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
4012 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
4015 uint64_t offset = *it;
4025 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4037 if (posMap.isEmpty())
4044 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4051 QStringList q(
"INSERT INTO ");
4055 q <<
"filemarkup (filename, type, mark, `offset`)";
4056 qfields = QString(
"('%1',%2,") .
4063 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4064 qfields = QString(
"(%1,'%2',%3,") .
4075 bool add_comma =
false;
4076 frm_pos_map_t::iterator it;
4077 for (it = posMap.begin(); it != posMap.end(); ++it)
4079 uint64_t frame = it.key();
4080 uint64_t offset = *it;
4090 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4102 "SELECT mark, `offset` FROM filemarkup"
4103 " WHERE filename = :PATH"
4105 " AND mark >= :QUERY_ARG"
4106 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4108 "SELECT mark, `offset` FROM filemarkup"
4109 " WHERE filename = :PATH"
4111 " AND mark <= :QUERY_ARG"
4112 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4114 "SELECT mark, `offset` FROM recordedseek"
4115 " WHERE chanid = :CHANID"
4116 " AND starttime = :STARTTIME"
4118 " AND mark >= :QUERY_ARG"
4119 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4121 "SELECT mark, `offset` FROM recordedseek"
4122 " WHERE chanid = :CHANID"
4123 " AND starttime = :STARTTIME"
4125 " AND mark <= :QUERY_ARG"
4126 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4128 "SELECT `offset`,mark FROM filemarkup"
4129 " WHERE filename = :PATH"
4131 " AND `offset` >= :QUERY_ARG"
4132 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4134 "SELECT `offset`,mark FROM filemarkup"
4135 " WHERE filename = :PATH"
4137 " AND `offset` <= :QUERY_ARG"
4138 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4140 "SELECT `offset`,mark FROM recordedseek"
4141 " WHERE chanid = :CHANID"
4142 " AND starttime = :STARTTIME"
4144 " AND `offset` >= :QUERY_ARG"
4145 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4147 "SELECT `offset`,mark FROM recordedseek"
4148 " WHERE chanid = :CHANID"
4149 " AND starttime = :STARTTIME"
4151 " AND `offset` <= :QUERY_ARG"
4152 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4155 uint64_t position_or_keyframe,
4158 const char *from_filemarkup_asc,
4159 const char *from_filemarkup_desc,
4160 const char *from_recordedseek_asc,
4161 const char *from_recordedseek_desc)
const
4168 query.
prepare(from_filemarkup_desc);
4170 query.
prepare(from_filemarkup_asc);
4176 query.
prepare(from_recordedseek_desc);
4178 query.
prepare(from_recordedseek_asc);
4183 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4193 *result = query.
value(1).toULongLong();
4200 query.
prepare(from_filemarkup_asc);
4202 query.
prepare(from_filemarkup_desc);
4208 query.
prepare(from_recordedseek_asc);
4210 query.
prepare(from_recordedseek_desc);
4215 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4225 *result = query.
value(1).toULongLong();
4234 bool backwards)
const
4243 bool backwards)
const
4252 bool backwards)
const
4261 bool backwards)
const
4281 query.
prepare(
"INSERT INTO recordedmarkup"
4282 " (chanid, starttime, mark, type, data)"
4284 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4288 query.
bindValue(
":MARK", (quint64)frame);
4296#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4297 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4299 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4317 query.
prepare(
"INSERT INTO recordedmarkup"
4318 " (chanid, starttime, mark, type, data)"
4320 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4323 query.
bindValue(
":MARK", (quint64)frame);
4342 query.
prepare(
"INSERT INTO recordedmarkup"
4343 " (chanid, starttime, mark, type, data)"
4345 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4348 query.
bindValue(
":MARK", (quint64)frame);
4362 query.
prepare(
"DELETE FROM recordedmarkup "
4363 " WHERE chanid=:CHANID "
4364 " AND starttime=:STARTTIME "
4367 query.
bindValue(
":STARTTIME", recstartts);
4380 query.
prepare(
"DELETE FROM filemarkup"
4381 " WHERE filename = :PATH "
4382 " AND type = :TYPE ;");
4396 query.
prepare(
"DELETE FROM filemarkup"
4397 " WHERE filename = :PATH "
4398 " AND mark = :MARK "
4399 " AND type = :TYPE ;");
4413 query.
prepare(
"INSERT INTO filemarkup"
4414 " (filename, mark, type, `offset`)"
4416 " ( :PATH , :MARK , :TYPE, :OFFSET );");
4431 query.
prepare(
"INSERT INTO recordedmarkup"
4432 " (chanid, starttime, mark, type, data)"
4434 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4436 query.
bindValue(
":STARTTIME", recstartts);
4493 query.
prepare(
"INSERT INTO recordedmarkup"
4494 " (chanid, starttime, mark, type, data)"
4496 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4499 query.
bindValue(
":MARK", (quint64)frame);
4506 query.
prepare(
"INSERT INTO recordedmarkup"
4507 " (chanid, starttime, mark, type, data)"
4509 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4512 query.
bindValue(
":MARK", (quint64)frame);
4523 QString qstr = QString(
4524 "SELECT recordedmarkup.data "
4525 "FROM recordedmarkup "
4526 "WHERE recordedmarkup.chanid = :CHANID AND "
4527 " recordedmarkup.starttime = :STARTTIME AND "
4528 " recordedmarkup.type = :TYPE "
4529 "GROUP BY recordedmarkup.data "
4530 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4531 " FROM recordedmarkup AS rm "
4532 " WHERE rm.chanid = recordedmarkup.chanid AND "
4533 " rm.starttime = recordedmarkup.starttime AND "
4534 " rm.type = recordedmarkup.type AND "
4535 " rm.mark > recordedmarkup.mark "
4536 " ORDER BY rm.mark ASC LIMIT 1 "
4537 " ) - recordedmarkup.mark "
4545 query.
bindValue(
":STARTTIME", recstartts);
4553 return (query.
next()) ? query.
value(0).toUInt() : 0;
4559 QString qstr = QString(
4560 "SELECT filemarkup.`offset` "
4562 "WHERE filemarkup.filename = :PATH AND "
4563 " filemarkup.type = :TYPE "
4564 "GROUP BY filemarkup.`offset` "
4565 "ORDER BY SUM( ( SELECT IFNULL(fm.mark, filemarkup.mark)"
4566 " FROM filemarkup AS fm "
4567 " WHERE fm.filename = filemarkup.filename AND "
4568 " fm.type = filemarkup.type AND "
4569 " fm.mark > filemarkup.mark "
4570 " ORDER BY fm.mark ASC LIMIT 1 "
4571 " ) - filemarkup.mark "
4586 return (query.
next()) ? query.
value(0).toUInt() : 0;
4620 query.
prepare(
"SELECT recordedmarkup.type "
4621 "FROM recordedmarkup "
4622 "WHERE recordedmarkup.chanid = :CHANID AND "
4623 " recordedmarkup.starttime = :STARTTIME AND "
4624 " recordedmarkup.type >= :ASPECTSTART AND "
4625 " recordedmarkup.type <= :ASPECTEND "
4626 "GROUP BY recordedmarkup.type "
4627 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4628 " SELECT MAX(rmmax.mark) "
4629 " FROM recordedmarkup AS rmmax "
4630 " WHERE rmmax.chanid = recordedmarkup.chanid "
4631 " AND rmmax.starttime = recordedmarkup.starttime "
4633 " FROM recordedmarkup AS rm "
4634 " WHERE rm.chanid = recordedmarkup.chanid AND "
4635 " rm.starttime = recordedmarkup.starttime AND "
4636 " rm.type >= :ASPECTSTART2 AND "
4637 " rm.type <= :ASPECTEND2 AND "
4638 " rm.mark > recordedmarkup.mark "
4639 " ORDER BY rm.mark ASC LIMIT 1 "
4640 " ) - recordedmarkup.mark "
4711 QVector<MarkupEntry> &mapSeek)
const
4717 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4718 " WHERE filename = :PATH"
4719 " AND type NOT IN (:KEYFRAME,:DURATION)"
4720 " ORDER BY mark, type;");
4727 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4728 " WHERE chanid = :CHANID"
4729 " AND STARTTIME = :STARTTIME"
4730 " ORDER BY mark, type");
4743 while (query.
next())
4746 uint64_t frame = query.
value(1).toLongLong();
4748 bool isDataNull = query.
value(2).isNull();
4750 data = query.
value(2).toLongLong();
4757 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4758 " WHERE filename = :PATH"
4759 " AND type IN (:KEYFRAME,:DURATION)"
4760 " ORDER BY mark, type;");
4767 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4768 " WHERE chanid = :CHANID"
4769 " AND STARTTIME = :STARTTIME"
4770 " ORDER BY mark, type");
4779 while (query.
next())
4782 uint64_t frame = query.
value(1).toLongLong();
4784 bool isDataNull = query.
value(2).isNull();
4786 data = query.
value(2).toLongLong();
4792 const QVector<MarkupEntry> &mapSeek)
const
4798 if (mapMark.isEmpty())
4800 LOG(VB_GENERAL, LOG_INFO,
4801 QString(
"No mark entries in input, "
4802 "not removing marks from DB"));
4806 query.
prepare(
"DELETE FROM filemarkup"
4807 " WHERE filename = :PATH"
4808 " AND type NOT IN (:KEYFRAME,:DURATION)");
4817 for (
const auto& entry : std::as_const(mapMark))
4821 if (entry.isDataNull)
4823 query.
prepare(
"INSERT INTO filemarkup"
4824 " (filename,type,mark)"
4825 " VALUES (:PATH,:TYPE,:MARK)");
4829 query.
prepare(
"INSERT INTO filemarkup"
4830 " (filename,type,mark,`offset`)"
4831 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4832 query.
bindValue(
":OFFSET", (quint64)entry.data);
4836 query.
bindValue(
":MARK", (quint64)entry.frame);
4844 if (mapSeek.isEmpty())
4846 LOG(VB_GENERAL, LOG_INFO,
4847 QString(
"No seek entries in input, "
4848 "not removing marks from DB"));
4852 query.
prepare(
"DELETE FROM filemarkup"
4853 " WHERE filename = :PATH"
4854 " AND type IN (:KEYFRAME,:DURATION)");
4863 for (
int i = 0; i < mapSeek.size(); ++i)
4865 if (i > 0 && (i % 1000 == 0))
4867 LOG(VB_GENERAL, LOG_INFO,
4868 QString(
"Inserted %1 of %2 records")
4869 .arg(i).arg(mapSeek.size()));
4872 query.
prepare(
"INSERT INTO filemarkup"
4873 " (filename,type,mark,`offset`)"
4874 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4889 if (mapMark.isEmpty())
4891 LOG(VB_GENERAL, LOG_INFO,
4892 QString(
"No mark entries in input, "
4893 "not removing marks from DB"));
4897 query.
prepare(
"DELETE FROM recordedmarkup"
4898 " WHERE chanid = :CHANID"
4899 " AND starttime = :STARTTIME");
4907 for (
const auto& entry : std::as_const(mapMark))
4909 if (entry.isDataNull)
4911 query.
prepare(
"INSERT INTO recordedmarkup"
4912 " (chanid,starttime,type,mark)"
4913 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4917 query.
prepare(
"INSERT INTO recordedmarkup"
4918 " (chanid,starttime,type,mark,data)"
4919 " VALUES (:CHANID,:STARTTIME,"
4920 " :TYPE,:MARK,:OFFSET)");
4921 query.
bindValue(
":OFFSET", (quint64)entry.data);
4926 query.
bindValue(
":MARK", (quint64)entry.frame);
4934 if (mapSeek.isEmpty())
4936 LOG(VB_GENERAL, LOG_INFO,
4937 QString(
"No seek entries in input, "
4938 "not removing marks from DB"));
4942 query.
prepare(
"DELETE FROM recordedseek"
4943 " WHERE chanid = :CHANID"
4944 " AND starttime = :STARTTIME");
4952 for (
int i = 0; i < mapSeek.size(); ++i)
4954 if (i > 0 && (i % 1000 == 0))
4956 LOG(VB_GENERAL, LOG_INFO,
4957 QString(
"Inserted %1 of %2 records")
4958 .arg(i).arg(mapSeek.size()));
4961 query.
prepare(
"INSERT INTO recordedseek"
4962 " (chanid,starttime,type,mark,`offset`)"
4963 " VALUES (:CHANID,:STARTTIME,"
4964 " :TYPE,:MARK,:OFFSET)");
4984 LOG(VB_RECORD, LOG_INFO,
4985 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4986 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
4989 "UPDATE recordedprogram "
4990 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
4991 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
4994 query.
bindValue(
":FLAGS", video_property_flags);
5004 videoproperties &= ~mask;
5005 videoproperties |= video_property_flags;
5023 QString chan(format);
5033 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
5053 "SET season = :SEASON, episode = :EPISODE "
5054 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5055 "AND recordid = :RECORDID");
5077 "SET inetref = :INETREF "
5078 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5079 "AND recordid = :RECORDID");
5118 query.
prepare(
"SELECT password FROM recgroups "
5119 "WHERE recgroup = :GROUP");
5123 result = query.
value(0).toString();
5133 query.
prepare(
"SELECT recgroup FROM recorded "
5134 "WHERE chanid = :CHANID AND "
5135 " starttime = :START");
5141 grp = query.
value(0).toString();
5149 query.
prepare(
"SELECT transcoder FROM recorded "
5150 "WHERE chanid = :CHANID AND "
5151 " starttime = :START");
5156 return query.
value(0).toUInt();
5174 if (path.startsWith(
"/"))
5176 QFileInfo testFile(path);
5177 return testFile.path();
5188 if (testFile.exists())
5190 if (testFile.isSymLink())
5193 if (testFile.isFile())
5194 return testFile.path();
5195 if (testFile.isDir())
5196 return testFile.filePath();
5200 testFile.setFile(testFile.absolutePath());
5201 if (testFile.exists())
5203 if (testFile.isSymLink())
5206 if (testFile.isDir())
5207 return testFile.filePath();
5226 bool notifyOfChange =
false;
5232 if (!usedFor.isEmpty())
5238 LOG(VB_GENERAL, LOG_INFO,
LOC +
5239 QString(
"MarkAsInUse(true, '%1'->'%2')")
5241 " -- use has changed");
5245 LOG(VB_GENERAL, LOG_INFO,
LOC +
5246 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5255 .arg(QObject::tr(
"Unknown")).arg(getpid());
5256 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5258 " -- use was not explicitly set");
5261 notifyOfChange =
true;
5266 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5267 QString(
"MarkAsInUse(false, '%1'->'%2')")
5269 " -- use has changed since first setting as in use.");
5274 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5284 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5285 "MarkAsInUse requires a key to delete in use mark");
5293 "DELETE FROM inuseprograms "
5294 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5295 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5320 "FROM inuseprograms "
5321 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5322 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5332 else if (!query.
next())
5334 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5336 else if (query.
value(0).toBool())
5339 "UPDATE inuseprograms "
5340 "SET lastupdatetime = :UPDATETIME "
5341 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5342 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5347 query.
bindValue(
":UPDATETIME", inUseTime);
5357 "INSERT INTO inuseprograms "
5358 " (chanid, starttime, recusage, hostname, "
5359 " lastupdatetime, rechost, recdir) "
5361 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5362 " :UPDATETIME, :RECHOST, :RECDIR)");
5367 query.
bindValue(
":UPDATETIME", inUseTime);
5379 if (!notifyOfChange)
5384 query.
prepare(
"SELECT DISTINCT recusage "
5385 "FROM inuseprograms "
5386 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5387 " chanid = :CHANID AND "
5388 " starttime = :STARTTIME");
5391 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5395 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5396 while (query.
next())
5398 QString inUseForWhat = query.
value(0).toString();
5420 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5421 "FROM channel, capturecard "
5422 "WHERE channel.chanid = :CHANID AND "
5423 " capturecard.sourceid = :SOURCEID AND "
5424 " capturecard.cardid = :INPUTID");
5431 channum = query.
value(0).toString();
5432 input = query.
value(1).toString();
5441 static bool s_done =
false;
5442 static QMutex s_initTrLock;
5443 QMutexLocker locker(&s_initTrLock);
5447 QString rec_profile_names =
5448 QObject::tr(
"Default",
"Recording Profile Default") +
5449 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5450 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5451 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5452 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5453 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5454 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5457 QString rec_profile_groups =
5458 QObject::tr(
"CRC IP Recorders",
5459 "Recording Profile Group Name") +
5460 QObject::tr(
"FireWire Input",
5461 "Recording Profile Group Name") +
5462 QObject::tr(
"Freebox Input",
5463 "Recording Profile Group Name") +
5464 QObject::tr(
"Hardware DVB Encoders",
5465 "Recording Profile Group Name") +
5466 QObject::tr(
"Hardware HDTV",
5467 "Recording Profile Group Name") +
5468 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5469 "Recording Profile Group Name") +
5470 QObject::tr(
"HD-PVR Recorders",
5471 "Recording Profile Group Name") +
5472 QObject::tr(
"HDHomeRun Recorders",
5473 "Recording Profile Group Name") +
5474 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5475 "Recording Profile Group Name") +
5476 QObject::tr(
"Software Encoders (V4L based)",
5477 "Recording Profile Group Name") +
5478 QObject::tr(
"Transcoders",
5479 "Recording Profile Group Name") +
5480 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5481 "Recording Profile Group Name") +
5482 QObject::tr(
"V4L2 Encoders",
5483 "Recording Profile Group Name");
5485 QString display_rec_groups =
5486 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5487 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5488 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5489 QObject::tr(
"Default",
"Recording Group Default") +
5490 QObject::tr(
"Deleted",
"Recording Group Deleted");
5492 QString special_program_groups =
5493 QObject::tr(
"All Programs - %1",
5494 "Show all programs from a specific recording group");
5496 QString storage_groups =
5497 QObject::tr(
"Default",
"Storage Group Name") +
5498 QObject::tr(
"Live TV",
"Storage Group Name") +
5499 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5500 QObject::tr(
"DB Backups",
"Storage Group Name");
5502 QString play_groups =
5503 QObject::tr(
"Default",
"Playback Group Name");
5506 return (rec_profile_names.length() +
5507 rec_profile_groups.length() +
5508 display_rec_groups.length() +
5509 special_program_groups.length() +
5510 storage_groups.length() +
5511 play_groups.length());
5526 QByteArray msg_arr = msg.toLatin1();
5527 QString msg_i18n = QObject::tr(msg_arr.constData());
5528 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5529 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5541 if (pburl.startsWith(
"myth://"))
5543 str.replace(QString(
"%DIR%"), pburl);
5547 QFileInfo dirInfo(pburl);
5548 str.replace(QString(
"%DIR%"), dirInfo.path());
5556 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5557 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5558 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5559 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5560 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5562 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5563 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5564 str.replace(QString(
"%CATEGORY%"),
m_category);
5565 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5567 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5568 str.replace(QString(
"%INETREF%"),
m_inetRef);
5569 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5570 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5571 str.replace(QString(
"%ORIGINALAIRDATE%"),
5573 static const std::array<const QString,4> s_timeStr
5574 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5575 const std::array<const QDateTime *,4> time_dtr
5577 for (
size_t i = 0; i < s_timeStr.size(); i++)
5579 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5580 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5581 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5583 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5584 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5585 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5588 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5593 QMap<QString, uint32_t> inUseMap;
5598 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5599 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5600 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5605 while (query.
next())
5608 query.
value(0).toUInt(),
5611 QString inUseForWhat = query.
value(2).toString();
5613 if (!inUseMap.contains(inUseKey))
5614 inUseMap[inUseKey] = 0;
5617 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5619 inUseMap[inUseKey] |= FL_INUSERECORDING;
5621 inUseMap[inUseKey] |= FL_INUSEOTHER;
5629 QMap<QString,bool> is_job_running;
5632 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5633 "WHERE type = :TYPE");
5636 return is_job_running;
5638 while (query.
next())
5642 int tmpStatus = query.
value(2).toInt();
5643 if ((tmpStatus != 0x0000) &&
5644 (tmpStatus != 0x0001) &&
5645 (!(tmpStatus & 0x0100)))
5652 return is_job_running;
5656 const QString &tmptable,
int recordid)
5661 if (
sched && tmptable.isEmpty())
5669 LOG(VB_GENERAL, LOG_ERR,
5670 "Called from master backend\n\t\t\t"
5671 "with recordid or tmptable, this is not currently supported");
5676 (tmptable.isEmpty()) ?
5677 QString(
"QUERY_GETALLPENDING") :
5678 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5682 LOG(VB_GENERAL, LOG_ALERT,
5683 "LoadFromScheduler(): Error querying master.");
5702 QString columns = QString(
5703 "program.chanid, program.starttime, program.endtime, "
5704 "program.title, program.subtitle, program.description, "
5705 "program.category, channel.channum, channel.callsign, "
5706 "channel.name, program.previouslyshown, channel.commmethod, "
5707 "channel.outputfilters, program.seriesid, program.programid, "
5708 "program.airdate, program.stars, program.originalairdate, "
5709 "program.category_type, oldrecstatus.recordid, "
5710 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5711 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5712 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5713 "program.partnumber, program.parttotal, "
5714 "program.season, program.episode, program.totalepisodes ");
5716 QString querystr = QString(
5720 " LEFT JOIN channel ON program.chanid = channel.chanid "
5721 " LEFT JOIN oldrecorded AS oldrecstatus ON "
5722 " oldrecstatus.future = 0 AND "
5723 " program.title = oldrecstatus.title AND "
5724 " channel.callsign = oldrecstatus.station AND "
5725 " program.starttime = oldrecstatus.starttime "
5736 ", row_number() over ( "
5739 columns +=
"channel.channum, "
5740 " channel.callsign, ";
5742 columns +=
"channel.callsign, ";
5744 columns +=
"program.programid, ";
5747 " program.starttime "
5748 " order by channel.recpriority desc, "
5749 " channel.sourceid, "
5750 " channel.channum+0 "
5752 querystr +=
"WHERE grouprn = 1 ";
5758 querystr += QString(
"LIMIT %1 ").arg(limit);
5759 else if (!querystr.contains(
" LIMIT "))
5760 querystr +=
" LIMIT 20000 ";
5762 MSqlBindings::const_iterator it;
5779 if (start > 0 || limit > 0)
5781 QString countStr = querystr
5782 .arg(
"SQL_CALC_FOUND_ROWS chanid", columns);
5784 for (it = bindings.begin(); it != bindings.end(); ++it)
5786 if (countStr.contains(it.key()))
5796 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5797 count = query.
value(0).toUInt();
5801 querystr += QString(
"OFFSET %1 ").arg(start);
5803 querystr = querystr.arg(
"*", columns);
5805 for (it = bindings.begin(); it != bindings.end(); ++it)
5807 if (querystr.contains(it.key()))
5821 const QString &groupBy,
const QString &orderBy,
5826 QString queryStr =
"";
5828 if (!where.isEmpty())
5829 queryStr.append(QString(
"WHERE %1 ").arg(where));
5831 if (!groupBy.isEmpty())
5832 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5834 if (!orderBy.isEmpty())
5835 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5839 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5849 QString queryStr = sql;
5863 if (!queryStr.contains(
"WHERE"))
5864 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5866 if (!queryStr.contains(
"ORDER BY"))
5868 queryStr +=
" ORDER BY program.starttime, ";
5871 if (chanorder !=
"channum")
5872 queryStr += chanorder +
" ";
5874 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5879 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5889 destination.
clear();
5891 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5893 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5894 "clause, caller should be updated to use "
5895 "start parameter instead");
5898 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5900 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5901 "clause, caller should be updated to use "
5902 "limit parameter instead");
5911 count = query.
size();
5913 while (query.
next())
5917 query.
value(3).toString(),
5919 query.
value(4).toString(),
5921 query.
value(5).toString(),
5922 query.
value(26).toString(),
5923 query.
value(6).toString(),
5925 query.
value(0).toUInt(),
5926 query.
value(7).toString(),
5927 query.
value(8).toString(),
5928 query.
value(9).toString(),
5929 query.
value(12).toString(),
5936 query.
value(13).toString(),
5937 query.
value(14).toString(),
5940 query.
value(16).toFloat(),
5941 query.
value(15).toUInt(),
5942 query.
value(27).toUInt(),
5943 query.
value(28).toUInt(),
5944 query.
value(17).toDate(),
5946 query.
value(19).toUInt(),
5948 query.
value(22).toUInt(),
5951 query.
value(10).toBool(),
5952 query.
value(23).toInt(),
5953 query.
value(24).toInt(),
5954 query.
value(25).toInt(),
5955 query.
value(29).toUInt(),
5956 query.
value(30).toUInt(),
5957 query.
value(31).toUInt(),
5966 const QDateTime& starttime)
5973 QString sSQL =
"WHERE program.chanid = :ChanId "
5974 "AND program.starttime = :StartTime ";
5976 bindings[
":ChanId" ] = chanid;
5977 bindings[
":StartTime"] = starttime;
5982 bool hasConflicts =
false;
5991 if (progList.
empty())
6012 destination.
clear();
6018 "oldrecorded.chanid, starttime, endtime, "
6019 "title, subtitle, description, season, episode, category, seriesid, "
6020 "programid, inetref, channel.channum, channel.callsign, "
6021 "channel.name, findid, rectype, recstatus, recordid, duplicate ";
6026 "LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
6027 "WHERE oldrecorded.future = 0 "
6030 bool hasLimit = querystr.contains(
" LIMIT ",Qt::CaseInsensitive);
6034 if (!hasLimit && !querystr.contains(
" ORDER ",Qt::CaseInsensitive))
6035 querystr +=
" ORDER BY starttime DESC ";
6040 querystr += QString(
"LIMIT %1 ").arg(limit);
6046 nLimit = std::max(nLimit, 100);
6047 querystr += QString(
"LIMIT %1 ").arg(nLimit);
6050 MSqlBindings::const_iterator it;
6067 if (count > 0 && (start > 0 || limit > 0))
6069 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS oldrecorded.chanid");
6071 for (it = bindings.begin(); it != bindings.end(); ++it)
6073 if (countStr.contains(it.key()))
6083 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
6084 count = query.
value(0).toUInt();
6088 querystr += QString(
"OFFSET %1 ").arg(start);
6090 querystr = querystr.arg(columns);
6092 for (it = bindings.begin(); it != bindings.end(); ++it)
6094 if (querystr.contains(it.key()))
6104 while (query.
next())
6107 QString channum = QString(
"#%1").arg(chanid);
6108 QString chansign = channum;
6109 QString channame = channum;
6110 if (!query.
value(12).toString().isEmpty())
6112 channum = query.
value(12).toString();
6113 chansign = query.
value(13).toString();
6114 channame = query.
value(14).toString();
6118 query.
value(3).toString(),
6120 query.
value(4).toString(),
6122 query.
value(5).toString(),
6123 query.
value(6).toUInt(),
6124 query.
value(7).toUInt(),
6125 query.
value(8).toString(),
6127 chanid, channum, chansign, channame,
6129 query.
value(9).toString(), query.
value(10).toString(),
6130 query.
value(11).toString(),
6138 query.
value(18).toUInt(),
6140 query.
value(15).toUInt(),
6142 query.
value(19).toBool()));
6168 bool possiblyInProgressRecordingsOnly,
6169 const QMap<QString,uint32_t> &inUseMap,
6170 const QMap<QString,bool> &isJobRunning,
6171 const QMap<QString, ProgramInfo*> &recMap,
6173 const QString &sortBy,
6177 destination.
clear();
6185 if (possiblyInProgressRecordingsOnly || ignoreLiveTV || ignoreDeleted)
6187 thequery +=
"WHERE ";
6188 if (possiblyInProgressRecordingsOnly)
6190 thequery +=
"(r.endtime >= NOW() AND r.starttime <= NOW()) ";
6194 thequery += QString(
"%1 r.recgroup != 'LiveTV' ")
6195 .arg(possiblyInProgressRecordingsOnly ?
"AND" :
"");
6199 thequery += QString(
"%1 r.recgroup != 'Deleted' ")
6200 .arg((possiblyInProgressRecordingsOnly || ignoreLiveTV)
6205 if (sortBy.isEmpty())
6208 thequery +=
"ORDER BY r.starttime ";
6210 thequery +=
"DESC ";
6214 QStringList sortByFields;
6215 sortByFields <<
"starttime" <<
"title" <<
"subtitle" <<
"season" <<
"episode" <<
"category"
6216 <<
"watched" <<
"stars" <<
"originalairdate" <<
"recgroup" <<
"storagegroup"
6217 <<
"channum" <<
"callsign" <<
"name" <<
"filesize" <<
"duration";
6220 QStringList fields = sortBy.split(
",");
6221 for (
const QString& oneField : std::as_const(fields))
6223 bool ascending =
true;
6224 QString field = oneField.simplified().toLower();
6226 if (field.endsWith(
"desc"))
6229 field = field.remove(
"desc");
6232 if (field.endsWith(
"asc"))
6235 field = field.remove(
"asc");
6238 field = field.simplified();
6240 if (field ==
"channelname")
6243 if (sortByFields.contains(field))
6246 if (field ==
"channum" || field ==
"callsign" || field ==
"name")
6251 if (field ==
"channum")
6254 field =
"channum*1000-ifnull(regexp_substr(c.channum,'-.*'),0)";
6257 else if (field ==
"duration")
6259 field =
"timestampdiff(second,r.starttime,r.endtime)";
6263 else if (field ==
"season")
6265 field =
"if(r.season,r.season,p.season)";
6269 else if (field ==
"episode")
6271 field =
"if(r.episode,r.episode,p.episode)";
6275 else if (field ==
"title")
6278 QString prefixes = sh->getPrefixes();
6279 field =
"REGEXP_REPLACE(r.title,'" + prefixes +
"','')";
6283 else if (field ==
"subtitle")
6286 QString prefixes = sh->getPrefixes();
6287 field =
"REGEXP_REPLACE(r.subtitle,'" + prefixes +
"','')";
6291 else if (field ==
"originalairdate")
6293 field =
"IF(r.originalairdate != '0000-00-00', r.originalairdate, STR_TO_DATE(CONCAT(p.airdate,',01,01'),'%Y,%m,%d'))";
6297 if (sSortBy.isEmpty())
6298 sSortBy = QString(
"%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6300 sSortBy += QString(
",%1%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6304 LOG(VB_GENERAL, LOG_WARNING, QString(
"ProgramInfo::LoadFromRecorded() got an unknown sort field '%1' - ignoring").arg(oneField));
6308 thequery +=
"ORDER BY " + sSortBy;
6320 while (query.
next())
6322 const uint chanid = query.
value(6).toUInt();
6323 QString channum = QString(
"#%1").arg(chanid);
6324 QString chansign = channum;
6325 QString channame = channum;
6327 if (!query.
value(7).toString().isEmpty())
6329 channum = query.
value(7).toString();
6330 chansign = query.
value(8).toString();
6331 channame = query.
value(9).toString();
6332 chanfilt = query.
value(10).toString();
6344 recMap.contains(key))
6349 bool save_not_commflagged =
false;
6356 set_flag(flags, FL_COMMPROCESSING ,
6361 set_flag(flags, FL_DELETEPENDING, query.
value(35).toBool());
6365 set_flag(flags, FL_REALLYEDITING, query.
value(39).toBool());
6370 if (inUseMap.contains(key))
6371 flags |= inUseMap[key];
6373 if (((flags & FL_COMMPROCESSING) != 0U) &&
6374 (!isJobRunning.contains(key)))
6376 flags &= ~FL_COMMPROCESSING;
6377 save_not_commflagged =
true;
6381 ((flags & FL_REALLYEDITING) != 0U) ||
6387 season = query.
value(51).toUInt();
6392 episode = query.
value(52).toUInt();
6395 uint totalepisodes = query.
value(53).toUInt();
6399 query.
value(55).toUInt(),
6400 query.
value(0).toString(),
6402 query.
value(1).toString(),
6404 query.
value(2).toString(),
6408 query.
value(48).toString(),
6409 query.
value(5).toString(),
6411 chanid, channum, chansign, channame, chanfilt,
6413 query.
value(11).toString(), query.
value(12).toString(),
6415 query.
value(14).toString(),
6419 query.
value(17).toString(), query.
value(18).toString(),
6420 query.
value(19).toString(),
6423 query.
value(16).toInt(),
6425 query.
value(20).toULongLong(),
6432 query.
value(23).toFloat(),
6434 query.
value(26).toUInt(),
6435 query.
value(49).toUInt(),
6436 query.
value(50).toUInt(),
6437 query.
value(27).toDate(),
6442 query.
value(29).toUInt(),
6447 query.
value(45).toUInt(),
6450 query.
value(42).toUInt(),
6451 query.
value(43).toUInt(),
6452 query.
value(44).toUInt(),
6453 query.
value(56).toString(),
6457 if (save_not_commflagged)
6466 std::vector<ProgramInfo> *list)
6468 nextRecordingStart = QDateTime();
6471 bool *conflicts = (hasConflicts) ? hasConflicts : &dummy;
6478 for (
auto *prog : progList)
6482 (nextRecordingStart.isNull() ||
6483 nextRecordingStart > prog->GetRecordingStartTime()))
6485 nextRecordingStart = prog->GetRecordingStartTime();
6493 for (
auto & prog : progList)
6497 (prog->GetRecordingStartTime() == nextRecordingStart))
6537 "SET filesize = :FILESIZE "
6538 "WHERE chanid = :CHANID AND "
6539 " starttime = :STARTTIME");
6540 query.
bindValue(
":FILESIZE", (quint64)fsize);
6571 uint64_t db_filesize = 0;
6578 "WHERE chanid = :CHANID AND "
6579 " starttime = :STARTTIME");
6583 db_filesize = query.
value(0).toULongLong();
6586 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"RI Filesize=0, DB Filesize=%1")
6600 if (now < startTime)
6604 int current = startTime.secsTo(now);
6605 int duration = startTime.secsTo(endTime);
6610 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 recorded percent %2/%3 = %4%")
6639 total = rate1000 * duration / 1000;
6651 LOG(VB_GUI, LOG_DEBUG,
6652 QString(
"%1 %2 no frame count. Please rebuild seek table for this video.")
6657 LOG(VB_GUI, LOG_DEBUG,
6658 QString(
"%1 %2 no frame count. Please rebuild seek table for this recording.")
6666 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 %2 watched percent %3/%4 = %5%")
6684 return tr(
"Channel Number");
6686 return tr(
"CallSign");
6688 return tr(
"ProgramId");
6690 return tr(
"Unknown");
6696 QStringList strlist(
"QUERY_CHECKFILE");
6697 strlist << QString::number((
int)checkSlaves);
6701 (strlist.size() < 2) || !strlist[0].toInt())
6706 QString localpath = strlist[1];
6707 QFile checkFile(localpath);
6708 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)
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)
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.