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) ";
82 static 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;
125 static 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 : 0),
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)
765 int64_t minutes = length_in_minutes.count();
771 QString pn = _pathname;
772 if (!_pathname.startsWith(
"myth://"))
783 const QDateTime &_startts,
784 const QDateTime &_endts)
790 "SELECT chanid, channum, callsign, name, outputfilters, commmethod "
792 "WHERE chanid=:CHANID");
811 QString channelFormat =
819 QString(
"%1 (%2)").arg(
m_title, QObject::tr(
"Manual Record"));
837 bool ignore_non_serialized_data)
865 if (!ignore_non_serialized_data || !is_same ||
921 if (!ignore_non_serialized_data)
1027 if (a.isEmpty() and (b ==
"Default"))
1029 if ((a ==
"Default") and b.isEmpty())
1169 uint chanid,
const QDateTime &recstartts)
1171 return QString(
"%1_%2").arg(chanid).arg(recstartts.toString(
Qt::ISODate));
1178 uint &chanid, QDateTime &recstartts)
1180 QStringList keyParts = uniquekey.split(
'_');
1181 if (keyParts.size() != 2)
1183 chanid = keyParts[0].toUInt();
1185 return (chanid != 0U) && recstartts.isValid();
1189 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1191 QString basename = pathname.section(
'/', -1);
1192 if (basename.isEmpty())
1195 QStringList lr = basename.split(
"_");
1198 chanid = lr[0].toUInt();
1199 QStringList ts = lr[1].split(
".");
1200 if (chanid && !ts.empty())
1203 return recstartts.isValid();
1211 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1213 QString basename = pathname.section(
'/', -1);
1214 if (basename.isEmpty())
1219 "SELECT chanid, starttime "
1221 "WHERE basename = :BASENAME");
1225 chanid = query.
value(0).toUInt();
1236 QString basename = pathname.section(
'/', -1);
1237 if (basename.isEmpty())
1242 "SELECT recordedid "
1244 "WHERE basename = :BASENAME");
1248 recordedid = query.
value(0).toUInt();
1257 return QString::number(x.toSecsSinceEpoch());
1272 list << QString::number(
m_season );
1296 list << QString::number(
m_dupIn);
1308 list << QString(
"%1").arg(
m_stars);
1318 list << QString::number(
m_year);
1332 #define NEXT_STR() do { if (it == listend) \
1334 LOG(VB_GENERAL, LOG_ERR, listerror); \
1338 ts = *it++; } while (false)
1349 if (str.isEmpty() || (str ==
"0000-00-00"))
1367 const QStringList::const_iterator& listend)
1369 QString listerror =
LOC +
"FromStringList, not enough items in list.";
1433 if (!origChanid || !origRecstartts.isValid() ||
1448 template <
typename T>
1453 return propNames[0];
1456 for (
uint i = 0; i <
sizeof(T)*8 - 1; ++i)
1459 if ((props & bit) == 0)
1461 if (propNames.contains(bit))
1463 result += propNames[bit];
1466 QString
tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1467 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1471 return result.join(
'|');
1474 template <
typename T>
1476 const QString& props)
1478 if (props.isEmpty())
1483 QStringList names = props.split(
'|');
1484 for (
const auto& n : std::as_const(names) )
1486 uint bit = propNames.key(n, 0);
1489 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1545 uint date_format)
const
1550 QString channelFormat =
1552 QString longChannelFormat =
1562 QString tempSubTitle =
m_title;
1566 tempSubTitle = QString(
"%1 - \"%2\"")
1568 tempSortSubtitle = QString(
"%1 - \"%2\"")
1572 progMap[
"titlesubtitle"] = tempSubTitle;
1573 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1575 progMap[
"description"] = progMap[
"description0"] =
m_description;
1582 progMap[
"s00e00"] = QString(
"s%1e%2")
1585 progMap[
"00x00"] = QString(
"%1x%2")
1591 progMap[
"season"] = progMap[
"episode"] =
"";
1592 progMap[
"totalepisodes"] =
"";
1593 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1601 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1605 progMap[
"starttime"] =
"";
1606 progMap[
"startdate"] =
"";
1607 progMap[
"endtime"] =
"";
1608 progMap[
"enddate"] =
"";
1609 progMap[
"recstarttime"] =
"";
1610 progMap[
"recstartdate"] =
"";
1611 progMap[
"recendtime"] =
"";
1612 progMap[
"recenddate"] =
"";
1616 progMap[
"startdate"] =
"";
1617 progMap[
"recstartdate"] =
"";
1621 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1622 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1629 progMap[
"startdate"] =
1639 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1640 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1641 if (timeNow.toLocalTime().date().year() !=
1643 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1644 if (timeNow.toLocalTime().date().year() !=
1645 m_endTs.toLocalTime().date().year())
1646 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1650 progMap[
"timedate"] =
1654 progMap[
"shorttimedate"] =
1658 progMap[
"starttimedate"] =
1661 progMap[
"shortstarttimedate"] =
1665 progMap[
"lastmodifieddate"] =
1667 progMap[
"lastmodified"] =
1674 progMap[
"chanid"] = QString::number(
m_chanId);
1677 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1679 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1680 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1682 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1685 int minutes = seconds / 60;
1687 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1689 progMap[
"lenmins"] = min_str;
1690 int hours = minutes / 60;
1691 minutes = minutes % 60;
1693 progMap[
"lentime"] = min_str;
1694 if (hours > 0 && minutes > 0)
1696 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1697 progMap[
"lentime"] = QString(
"%1 %2")
1698 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1702 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1705 progMap[
"recordedpercent"] =
1708 progMap[
"watchedpercent"] =
1716 QString tmp_rec = progMap[
"rectype"];
1734 tmp_rec += QObject::tr(
"Re-Record");
1741 progMap[
"rectypestatus"] = tmp_rec;
1751 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1756 progMap[
"storagegroup"] = QObject::tr(
"Default");
1762 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1786 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1787 progMap[
"longrepeat"] = progMap[
"repeat"];
1790 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1791 .arg(QObject::tr(
"Repeat"),
1799 progMap[
"repeat"] =
"";
1800 progMap[
"longrepeat"] =
"";
1808 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1813 QString star_str = (
m_stars != 0.0F) ?
1814 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1815 progMap[
"stars"] = star_str;
1816 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1819 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1821 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1823 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1825 progMap[
"yearstars"] =
"";
1830 progMap[
"originalairdate"] =
"";
1831 progMap[
"shortoriginalairdate"] =
"";
1845 QString mediaTypeString;
1849 mediaType =
"video";
1850 mediaTypeString = QObject::tr(
"Video");
1854 mediaTypeString = QObject::tr(
"DVD");
1857 mediaType =
"httpstream";
1858 mediaTypeString = QObject::tr(
"HTTP Streaming");
1861 mediaType =
"rtspstream";
1862 mediaTypeString = QObject::tr(
"RTSP Streaming");
1865 mediaType =
"bluraydisc";
1866 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1870 mediaType =
"recording";
1871 mediaTypeString = QObject::tr(
"Recording",
1872 "Recorded file, object not action");
1874 progMap[
"mediatype"] = mediaType;
1875 progMap[
"mediatypestring"] = mediaTypeString;
1883 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1895 uint64_t last_frame = 0;
1904 if (!posMap.empty())
1906 frm_pos_map_t::const_iterator it = posMap.constEnd();
1908 last_frame = it.key();
1915 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1942 str +=
" startts(" +
1945 ") recendts(" +
m_recEndTs.toString() +
")\n";
1946 str +=
" title(" +
m_title +
")";
1954 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1959 str = QString(
"%1 at %2")
1963 str = QString(
"%1 @ %2")
1986 const uint _chanid,
const QDateTime &_recstartts)
1988 if (!_chanid || !_recstartts.isValid())
1997 "WHERE r.chanid = :CHANID AND "
1998 " r.starttime = :RECSTARTTS");
2000 query.
bindValue(
":RECSTARTTS", _recstartts);
2053 if (!query.
value(7).toString().isEmpty())
2067 QString new_basename = query.
value(14).toString();
2068 if ((
GetBasename() != new_basename) || !is_reload)
2072 LOG(VB_FILE, LOG_INFO,
LOC +
2073 QString(
"Updated pathname '%1':'%2' -> '%3'")
2096 m_stars = std::clamp((
float)query.
value(23).toDouble(), 0.0F, 1.0F);
2209 if (index == oindex && (index < 0 ||
2268 if (index == oindex && (index < 0 ||
2363 QMap<QString, int> authMap;
2364 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2367 for (
const QString& table : tables)
2370 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2371 "FROM %1 WHERE programid <> ''").arg(table));
2376 while (query.
next())
2377 authMap[query.
value(0).toString()] = 1;
2381 int numAuths = authMap.count();
2382 LOG(VB_GENERAL, LOG_INFO,
2383 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2396 QString retval = QString(
"%1_%2.%3")
2397 .arg(QString::number(
m_chanId), starts, ext);
2403 uint chanid,
const QString &pathname,
bool use_remote)
2405 QString fn_lower = pathname.toLower();
2409 else if (fn_lower.startsWith(
"http:"))
2411 else if (fn_lower.startsWith(
"rtsp:"))
2417 if (fn_lower.startsWith(
"dvd:"))
2421 else if (fn_lower.startsWith(
"bd:"))
2425 else if (use_remote && fn_lower.startsWith(
"myth://"))
2427 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2428 QString tmpFileBD = pathname +
"/BDMV";
2456 LOG(VB_GUI, LOG_INFO,
2471 query.
prepare(
"UPDATE recorded "
2472 "SET basename = :BASENAME "
2473 "WHERE recordedid = :RECORDEDID;");
2483 query.
prepare(
"UPDATE recordedfile "
2484 "SET basename = :BASENAME "
2485 "WHERE recordedid = :RECORDEDID;");
2517 "FROM recordedfile "
2518 "WHERE recordedid = :RECORDEDID;");
2525 else if (query.
next())
2527 return query.
value(0).toString();
2531 LOG(VB_GENERAL, LOG_INFO,
2532 QString(
"QueryBasename found no entry for recording ID %1")
2547 bool checkMaster,
bool forceCheckLocal)
2554 if (basename.isEmpty())
2563 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2566 QUrl url = QUrl(fullpath);
2567 QString path = url.path();
2568 QString host = url.toString(QUrl::RemovePath).mid(7);
2569 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2573 list = host.split(
"@", Qt::SkipEmptyParts);
2575 if (!list.empty() && list.size() < 3)
2577 host = list.size() == 1 ? list[0] : list[1];
2578 group = list.size() == 1 ? QString() : list[0];
2581 if (!local.isEmpty() && sg.
FileExists(local))
2594 LOG(VB_FILE, LOG_DEBUG,
LOC +
2595 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2597 tmpURL = sgroup.
FindFile(basename);
2599 if (!tmpURL.isEmpty())
2601 LOG(VB_FILE, LOG_INFO,
LOC +
2602 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2607 LOG(VB_GENERAL, LOG_ERR,
LOC +
2608 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2609 "not be found.").arg(basename));
2612 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2618 if ((checkMaster) &&
2626 LOG(VB_FILE, LOG_INFO,
LOC +
2627 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2636 LOG(VB_FILE, LOG_INFO,
LOC +
2637 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2651 query.
prepare(
"SELECT mplexid FROM channel "
2652 "WHERE chanid = :CHANID");
2657 else if (query.
next())
2658 ret = query.
value(0).toUInt();
2661 ret = (32767 == ret) ? 0 : ret;
2673 bool is_valid = (frame > 0);
2694 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2695 " bookmark = :BOOKMARKFLAG "
2696 "WHERE recordedid = :RECORDEDID");
2698 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2710 bool isValid = frame > 0;
2735 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2736 " lastplay = :LASTPLAYFLAG "
2737 "WHERE recordedid = :RECORDEDID");
2739 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2770 "SELECT bookmarkupdate "
2772 "WHERE chanid = :CHANID AND"
2773 " starttime = :STARTTIME");
2781 else if (query.
next())
2801 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2811 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2828 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2845 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2853 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2857 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2862 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2866 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2870 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2881 const QString &serialid)
const
2883 QStringList fields = QStringList();
2888 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2889 " FROM dvdbookmark "
2890 " WHERE serialid = :SERIALID ");
2895 QString dvdstate = query.
value(0).toString();
2897 if (!dvdstate.isEmpty())
2899 fields.append(dvdstate);
2904 for(
int i = 1; i < 5; i++)
2905 fields.append(query.
value(i).toString());
2915 QStringList::const_iterator it = fields.begin();
2918 QString serialid = *(it);
2919 QString name = *(++it);
2921 if( fields.count() == 3 )
2924 QString state = *(++it);
2926 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2928 " VALUES ( :SERIALID, :NAME );");
2935 query.
prepare(
" UPDATE dvdbookmark "
2936 " SET dvdstate = :STATE , "
2937 " timestamp = NOW() "
2938 " WHERE serialid = :SERIALID");
2945 query.
prepare(
"DELETE FROM dvdbookmark "
2946 "WHERE serialid = :SERIALID");
2959 QStringList fields = QStringList();
2964 query.
prepare(
" SELECT bdstate FROM bdbookmark "
2965 " WHERE serialid = :SERIALID ");
2969 fields.append(query.
value(0).toString());
2977 QStringList::const_iterator it = fields.begin();
2980 QString serialid = *(it);
2981 QString name = *(++it);
2983 if( fields.count() == 3 )
2986 QString state = *(++it);
2988 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
2990 " VALUES ( :SERIALID, :NAME );");
2997 query.
prepare(
" UPDATE bdbookmark "
2998 " SET bdstate = :STATE , "
2999 " timestamp = NOW() "
3000 " WHERE serialid = :SERIALID");
3007 query.
prepare(
"DELETE FROM bdbookmark "
3008 "WHERE serialid = :SERIALID");
3027 query.
prepare(
" SELECT category_type "
3028 " FROM recordedprogram "
3029 " WHERE chanid = :CHANID "
3030 " AND starttime = :STARTTIME;");
3050 query.
prepare(
"UPDATE recorded"
3051 " SET watched = :WATCHEDFLAG"
3052 " WHERE chanid = :CHANID"
3053 " AND starttime = :STARTTIME ;");
3056 query.
bindValue(
":WATCHEDFLAG", watched);
3068 if (url.startsWith(
"myth://"))
3070 url = QUrl(url).path();
3075 query.
prepare(
"UPDATE videometadata"
3076 " SET watched = :WATCHEDFLAG"
3077 " WHERE title = :TITLE"
3078 " AND subtitle = :SUBTITLE"
3079 " AND filename = :FILENAME ;");
3083 query.
bindValue(
":WATCHEDFLAG", watched);
3102 query.
prepare(
"SELECT editing FROM recorded"
3103 " WHERE chanid = :CHANID"
3104 " AND starttime = :STARTTIME ;");
3109 editing = query.
value(0).toBool();
3126 query.
prepare(
"UPDATE recorded"
3127 " SET editing = :EDIT"
3128 " WHERE chanid = :CHANID"
3129 " AND starttime = :STARTTIME ;");
3151 query.
prepare(
"UPDATE recorded"
3152 " SET deletepending = :DELETEFLAG, "
3154 " WHERE chanid = :CHANID"
3155 " AND starttime = :STARTTIME ;");
3158 query.
bindValue(
":DELETEFLAG", deleteFlag);
3183 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3184 " WHERE chanid = :CHANID"
3185 " AND starttime = :STARTTIME "
3186 " AND lastupdatetime > :ONEHOURAGO ;");
3189 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3192 if (query.
exec() && query.
size() > 0)
3196 while (query.
next())
3198 usageStr = QObject::tr(
"Unknown");
3199 recusage = query.
value(1).toString();
3202 usageStr = QObject::tr(
"Playing");
3204 usageStr = QObject::tr(
"PIP");
3206 usageStr = QObject::tr(
"PBP");
3209 usageStr = QObject::tr(
"Recording");
3211 usageStr = QObject::tr(
"File transfer");
3213 usageStr = QObject::tr(
"Delete");
3215 usageStr = QObject::tr(
"Commercial Detection");
3217 usageStr = QObject::tr(
"Transcoding");
3219 usageStr = QObject::tr(
"Preview Generation");
3221 usageStr = QObject::tr(
"User Job");
3223 byWho.push_back(recusage);
3224 byWho.push_back(query.
value(0).toString());
3225 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3243 for (
int i = 0; i+2 < users.size(); i+=3)
3244 byWho += users[i+2] +
"\n";
3271 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3281 (one_playback_allowed && (play_cnt <= 1)));
3283 ok = ok && (ft_cnt == jq_cnt);
3294 query.
prepare(
"SELECT transcoded FROM recorded"
3295 " WHERE chanid = :CHANID"
3296 " AND starttime = :STARTTIME ;");
3316 "SET transcoded = :VALUE "
3317 "WHERE chanid = :CHANID AND"
3318 " starttime = :STARTTIME");
3337 query.
prepare(
"UPDATE recorded"
3338 " SET commflagged = :FLAG"
3339 " WHERE chanid = :CHANID"
3340 " AND starttime = :STARTTIME ;");
3363 query.
prepare(
"UPDATE recorded"
3364 " SET preserve = :PRESERVE"
3365 " WHERE chanid = :CHANID"
3366 " AND starttime = :STARTTIME ;");
3367 query.
bindValue(
":PRESERVE", preserveEpisode);
3390 query.
prepare(
"UPDATE recorded"
3391 " SET autoexpire = :AUTOEXPIRE"
3392 " WHERE chanid = :CHANID"
3393 " AND starttime = :STARTTIME ;");
3400 else if (updateDelete)
3419 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3420 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3421 delay = std::clamp(delay, 1h, 200h);
3423 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3424 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3425 "WHERE recordid = :RECORDID");
3427 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3431 query.
prepare(
"UPDATE record SET last_delete = NULL "
3432 "WHERE recordid = :RECORDID");
3445 query.
prepare(
"SELECT autoexpire FROM recorded"
3446 " WHERE chanid = :CHANID"
3447 " AND starttime = :STARTTIME ;");
3468 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3470 uint64_t frame = i.key();
3476 delMap[frame] =
mark;
3486 return !delMap.isEmpty();
3502 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3504 uint64_t frame = i.key();
3513 tmpDelMap[frame] =
mark;
3522 query.
prepare(
"UPDATE recorded"
3523 " SET cutlist = :CUTLIST"
3524 " WHERE chanid = :CHANID"
3525 " AND starttime = :STARTTIME ;");
3527 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3556 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3559 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3562 comp += QString(
" AND type = :TYPE ");
3566 query.
prepare(
"DELETE FROM filemarkup"
3567 " WHERE filename = :PATH "
3573 query.
prepare(
"DELETE FROM recordedmarkup"
3574 " WHERE chanid = :CHANID"
3575 " AND STARTTIME = :STARTTIME"
3592 int64_t min_frame, int64_t max_frame)
const
3604 query.
prepare(
"SELECT starttime FROM recorded"
3605 " WHERE chanid = :CHANID"
3606 " AND starttime = :STARTTIME ;");
3621 frm_dir_map_t::const_iterator it;
3622 for (it =
marks.begin(); it !=
marks.end(); ++it)
3624 uint64_t frame = it.key();
3626 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3629 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3636 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3637 " VALUES ( :PATH , :MARK , :TYPE );");
3642 query.
prepare(
"INSERT INTO recordedmarkup"
3643 " (chanid, starttime, mark, type)"
3644 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3648 query.
bindValue(
":MARK", (quint64)frame);
3674 const QString &video_pathname,
3683 query.
prepare(
"SELECT mark, type "
3685 "WHERE filename = :PATH AND "
3688 query.
bindValue(
":PATH", video_pathname);
3697 while (query.
next())
3705 uint chanid,
const QDateTime &recstartts,
3713 query.
prepare(
"SELECT mark, type "
3714 "FROM recordedmarkup "
3715 "WHERE chanid = :CHANID AND "
3716 " starttime = :STARTTIME AND"
3720 query.
bindValue(
":STARTTIME", recstartts);
3729 while (query.
next())
3743 return flagMap.contains(0);
3771 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3772 " WHERE filename = :PATH"
3773 " AND type = :TYPE ;");
3778 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3779 " WHERE chanid = :CHANID"
3780 " AND starttime = :STARTTIME"
3781 " AND type = :TYPE ;");
3797 while (query.
next())
3798 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3814 query.
prepare(
"DELETE FROM filemarkup"
3815 " WHERE filename = :PATH"
3816 " AND type = :TYPE ;");
3821 query.
prepare(
"DELETE FROM recordedseek"
3822 " WHERE chanid = :CHANID"
3823 " AND starttime = :STARTTIME"
3824 " AND type = :TYPE ;");
3841 int64_t min_frame, int64_t max_frame)
const
3847 if ((min_frame >= 0) || (max_frame >= 0))
3855 uint64_t frame = it.key();
3856 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3858 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3860 new_map.insert(it.key(), *it);
3870 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3872 uint64_t frame = it.key();
3873 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3875 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3879 .insert(frame, *it);
3889 comp +=
" AND mark >= :MIN_FRAME ";
3891 comp +=
" AND mark <= :MAX_FRAME ";
3898 query.
prepare(
"DELETE FROM filemarkup"
3899 " WHERE filename = :PATH"
3906 query.
prepare(
"DELETE FROM recordedseek"
3907 " WHERE chanid = :CHANID"
3908 " AND starttime = :STARTTIME"
3921 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3923 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3928 if (posMap.isEmpty())
3932 QStringList q(
"INSERT INTO ");
3936 q <<
"filemarkup (filename, type, mark, `offset`)";
3937 qfields = QString(
"('%1',%2,") .
3944 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
3945 qfields = QString(
"(%1,'%2',%3,") .
3952 bool add_comma =
false;
3953 frm_pos_map_t::iterator it;
3954 for (it = posMap.begin(); it != posMap.end(); ++it)
3956 uint64_t frame = it.key();
3958 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3961 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3964 uint64_t offset = *it;
3974 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
3986 if (posMap.isEmpty())
3993 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4000 QStringList q(
"INSERT INTO ");
4004 q <<
"filemarkup (filename, type, mark, `offset`)";
4005 qfields = QString(
"('%1',%2,") .
4012 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4013 qfields = QString(
"(%1,'%2',%3,") .
4024 bool add_comma =
false;
4025 frm_pos_map_t::iterator it;
4026 for (it = posMap.begin(); it != posMap.end(); ++it)
4028 uint64_t frame = it.key();
4029 uint64_t offset = *it;
4039 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4051 "SELECT mark, `offset` FROM filemarkup"
4052 " WHERE filename = :PATH"
4054 " AND mark >= :QUERY_ARG"
4055 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4057 "SELECT mark, `offset` FROM filemarkup"
4058 " WHERE filename = :PATH"
4060 " AND mark <= :QUERY_ARG"
4061 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4063 "SELECT mark, `offset` FROM recordedseek"
4064 " WHERE chanid = :CHANID"
4065 " AND starttime = :STARTTIME"
4067 " AND mark >= :QUERY_ARG"
4068 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4070 "SELECT mark, `offset` FROM recordedseek"
4071 " WHERE chanid = :CHANID"
4072 " AND starttime = :STARTTIME"
4074 " AND mark <= :QUERY_ARG"
4075 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4077 "SELECT `offset`,mark FROM filemarkup"
4078 " WHERE filename = :PATH"
4080 " AND `offset` >= :QUERY_ARG"
4081 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4083 "SELECT `offset`,mark FROM filemarkup"
4084 " WHERE filename = :PATH"
4086 " AND `offset` <= :QUERY_ARG"
4087 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4089 "SELECT `offset`,mark FROM recordedseek"
4090 " WHERE chanid = :CHANID"
4091 " AND starttime = :STARTTIME"
4093 " AND `offset` >= :QUERY_ARG"
4094 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4096 "SELECT `offset`,mark FROM recordedseek"
4097 " WHERE chanid = :CHANID"
4098 " AND starttime = :STARTTIME"
4100 " AND `offset` <= :QUERY_ARG"
4101 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4104 uint64_t position_or_keyframe,
4107 const char *from_filemarkup_asc,
4108 const char *from_filemarkup_desc,
4109 const char *from_recordedseek_asc,
4110 const char *from_recordedseek_desc)
const
4117 query.
prepare(from_filemarkup_desc);
4119 query.
prepare(from_filemarkup_asc);
4125 query.
prepare(from_recordedseek_desc);
4127 query.
prepare(from_recordedseek_asc);
4132 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4142 *result = query.
value(1).toULongLong();
4149 query.
prepare(from_filemarkup_asc);
4151 query.
prepare(from_filemarkup_desc);
4157 query.
prepare(from_recordedseek_asc);
4159 query.
prepare(from_recordedseek_desc);
4164 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4174 *result = query.
value(1).toULongLong();
4183 bool backwards)
const
4192 bool backwards)
const
4201 bool backwards)
const
4210 bool backwards)
const
4230 query.
prepare(
"INSERT INTO recordedmarkup"
4231 " (chanid, starttime, mark, type, data)"
4233 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4237 query.
bindValue(
":MARK", (quint64)frame);
4245 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4246 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4248 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4266 query.
prepare(
"INSERT INTO recordedmarkup"
4267 " (chanid, starttime, mark, type, data)"
4269 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4272 query.
bindValue(
":MARK", (quint64)frame);
4291 query.
prepare(
"INSERT INTO recordedmarkup"
4292 " (chanid, starttime, mark, type, data)"
4294 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4297 query.
bindValue(
":MARK", (quint64)frame);
4311 query.
prepare(
"DELETE FROM recordedmarkup "
4312 " WHERE chanid=:CHANID "
4313 " AND starttime=:STARTTIME "
4316 query.
bindValue(
":STARTTIME", recstartts);
4328 query.
prepare(
"DELETE FROM filemarkup"
4329 " WHERE filename = :PATH "
4330 " AND type = :TYPE ;");
4343 query.
prepare(
"INSERT INTO filemarkup"
4344 " (filename, mark, type, `offset`)"
4346 " ( :PATH , :MARK , :TYPE, :OFFSET );");
4361 query.
prepare(
"INSERT INTO recordedmarkup"
4362 " (chanid, starttime, mark, type, data)"
4364 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4366 query.
bindValue(
":STARTTIME", recstartts);
4418 query.
prepare(
"INSERT INTO recordedmarkup"
4419 " (chanid, starttime, mark, type, data)"
4421 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4424 query.
bindValue(
":MARK", (quint64)frame);
4431 query.
prepare(
"INSERT INTO recordedmarkup"
4432 " (chanid, starttime, mark, type, data)"
4434 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4437 query.
bindValue(
":MARK", (quint64)frame);
4448 QString qstr = QString(
4449 "SELECT recordedmarkup.data "
4450 "FROM recordedmarkup "
4451 "WHERE recordedmarkup.chanid = :CHANID AND "
4452 " recordedmarkup.starttime = :STARTTIME AND "
4453 " recordedmarkup.type = :TYPE "
4454 "GROUP BY recordedmarkup.data "
4455 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4456 " FROM recordedmarkup AS rm "
4457 " WHERE rm.chanid = recordedmarkup.chanid AND "
4458 " rm.starttime = recordedmarkup.starttime AND "
4459 " rm.type = recordedmarkup.type AND "
4460 " rm.mark > recordedmarkup.mark "
4461 " ORDER BY rm.mark ASC LIMIT 1 "
4462 " ) - recordedmarkup.mark "
4470 query.
bindValue(
":STARTTIME", recstartts);
4478 return (query.
next()) ? query.
value(0).toUInt() : 0;
4484 QString qstr = QString(
4485 "SELECT filemarkup.`offset` "
4487 "WHERE filemarkup.filename = :PATH AND "
4488 " filemarkup.type = :TYPE "
4489 "GROUP BY filemarkup.`offset` "
4490 "ORDER BY SUM( ( SELECT IFNULL(fm.mark, filemarkup.mark)"
4491 " FROM filemarkup AS fm "
4492 " WHERE fm.filename = filemarkup.filename AND "
4493 " fm.type = filemarkup.type AND "
4494 " fm.mark > filemarkup.mark "
4495 " ORDER BY fm.mark ASC LIMIT 1 "
4496 " ) - filemarkup.mark "
4511 return (query.
next()) ? query.
value(0).toUInt() : 0;
4545 query.
prepare(
"SELECT recordedmarkup.type "
4546 "FROM recordedmarkup "
4547 "WHERE recordedmarkup.chanid = :CHANID AND "
4548 " recordedmarkup.starttime = :STARTTIME AND "
4549 " recordedmarkup.type >= :ASPECTSTART AND "
4550 " recordedmarkup.type <= :ASPECTEND "
4551 "GROUP BY recordedmarkup.type "
4552 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4553 " SELECT MAX(rmmax.mark) "
4554 " FROM recordedmarkup AS rmmax "
4555 " WHERE rmmax.chanid = recordedmarkup.chanid "
4556 " AND rmmax.starttime = recordedmarkup.starttime "
4558 " FROM recordedmarkup AS rm "
4559 " WHERE rm.chanid = recordedmarkup.chanid AND "
4560 " rm.starttime = recordedmarkup.starttime AND "
4561 " rm.type >= :ASPECTSTART2 AND "
4562 " rm.type <= :ASPECTEND2 AND "
4563 " rm.mark > recordedmarkup.mark "
4564 " ORDER BY rm.mark ASC LIMIT 1 "
4565 " ) - recordedmarkup.mark "
4636 QVector<MarkupEntry> &mapSeek)
const
4642 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4643 " WHERE filename = :PATH"
4644 " AND type NOT IN (:KEYFRAME,:DURATION)"
4645 " ORDER BY mark, type;");
4652 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4653 " WHERE chanid = :CHANID"
4654 " AND STARTTIME = :STARTTIME"
4655 " ORDER BY mark, type");
4668 while (query.
next())
4671 uint64_t frame = query.
value(1).toLongLong();
4673 bool isDataNull = query.
value(2).isNull();
4675 data = query.
value(2).toLongLong();
4682 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4683 " WHERE filename = :PATH"
4684 " AND type IN (:KEYFRAME,:DURATION)"
4685 " ORDER BY mark, type;");
4692 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4693 " WHERE chanid = :CHANID"
4694 " AND STARTTIME = :STARTTIME"
4695 " ORDER BY mark, type");
4704 while (query.
next())
4707 uint64_t frame = query.
value(1).toLongLong();
4709 bool isDataNull = query.
value(2).isNull();
4711 data = query.
value(2).toLongLong();
4717 const QVector<MarkupEntry> &mapSeek)
const
4723 if (mapMark.isEmpty())
4725 LOG(VB_GENERAL, LOG_INFO,
4726 QString(
"No mark entries in input, "
4727 "not removing marks from DB"));
4731 query.
prepare(
"DELETE FROM filemarkup"
4732 " WHERE filename = :PATH"
4733 " AND type NOT IN (:KEYFRAME,:DURATION)");
4742 for (
const auto& entry : std::as_const(mapMark))
4746 if (entry.isDataNull)
4748 query.
prepare(
"INSERT INTO filemarkup"
4749 " (filename,type,mark)"
4750 " VALUES (:PATH,:TYPE,:MARK)");
4754 query.
prepare(
"INSERT INTO filemarkup"
4755 " (filename,type,mark,`offset`)"
4756 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4757 query.
bindValue(
":OFFSET", (quint64)entry.data);
4761 query.
bindValue(
":MARK", (quint64)entry.frame);
4769 if (mapSeek.isEmpty())
4771 LOG(VB_GENERAL, LOG_INFO,
4772 QString(
"No seek entries in input, "
4773 "not removing marks from DB"));
4777 query.
prepare(
"DELETE FROM filemarkup"
4778 " WHERE filename = :PATH"
4779 " AND type IN (:KEYFRAME,:DURATION)");
4788 for (
int i = 0; i < mapSeek.size(); ++i)
4790 if (i > 0 && (i % 1000 == 0))
4792 LOG(VB_GENERAL, LOG_INFO,
4793 QString(
"Inserted %1 of %2 records")
4794 .arg(i).arg(mapSeek.size()));
4797 query.
prepare(
"INSERT INTO filemarkup"
4798 " (filename,type,mark,`offset`)"
4799 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4814 if (mapMark.isEmpty())
4816 LOG(VB_GENERAL, LOG_INFO,
4817 QString(
"No mark entries in input, "
4818 "not removing marks from DB"));
4822 query.
prepare(
"DELETE FROM recordedmarkup"
4823 " WHERE chanid = :CHANID"
4824 " AND starttime = :STARTTIME");
4832 for (
const auto& entry : std::as_const(mapMark))
4834 if (entry.isDataNull)
4836 query.
prepare(
"INSERT INTO recordedmarkup"
4837 " (chanid,starttime,type,mark)"
4838 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4842 query.
prepare(
"INSERT INTO recordedmarkup"
4843 " (chanid,starttime,type,mark,data)"
4844 " VALUES (:CHANID,:STARTTIME,"
4845 " :TYPE,:MARK,:OFFSET)");
4846 query.
bindValue(
":OFFSET", (quint64)entry.data);
4851 query.
bindValue(
":MARK", (quint64)entry.frame);
4859 if (mapSeek.isEmpty())
4861 LOG(VB_GENERAL, LOG_INFO,
4862 QString(
"No seek entries in input, "
4863 "not removing marks from DB"));
4867 query.
prepare(
"DELETE FROM recordedseek"
4868 " WHERE chanid = :CHANID"
4869 " AND starttime = :STARTTIME");
4877 for (
int i = 0; i < mapSeek.size(); ++i)
4879 if (i > 0 && (i % 1000 == 0))
4881 LOG(VB_GENERAL, LOG_INFO,
4882 QString(
"Inserted %1 of %2 records")
4883 .arg(i).arg(mapSeek.size()));
4886 query.
prepare(
"INSERT INTO recordedseek"
4887 " (chanid,starttime,type,mark,`offset`)"
4888 " VALUES (:CHANID,:STARTTIME,"
4889 " :TYPE,:MARK,:OFFSET)");
4909 LOG(VB_RECORD, LOG_INFO,
4910 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4911 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
4914 "UPDATE recordedprogram "
4915 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
4916 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
4919 query.
bindValue(
":FLAGS", video_property_flags);
4929 videoproperties &= ~mask;
4930 videoproperties |= video_property_flags;
4948 QString chan(format);
4958 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
4978 "SET season = :SEASON, episode = :EPISODE "
4979 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
4980 "AND recordid = :RECORDID");
5002 "SET inetref = :INETREF "
5003 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5004 "AND recordid = :RECORDID");
5043 query.
prepare(
"SELECT password FROM recgroups "
5044 "WHERE recgroup = :GROUP");
5048 result = query.
value(0).toString();
5058 query.
prepare(
"SELECT recgroup FROM recorded "
5059 "WHERE chanid = :CHANID AND "
5060 " starttime = :START");
5066 grp = query.
value(0).toString();
5074 query.
prepare(
"SELECT transcoder FROM recorded "
5075 "WHERE chanid = :CHANID AND "
5076 " starttime = :START");
5081 return query.
value(0).toUInt();
5099 if (path.startsWith(
"/"))
5101 QFileInfo testFile(path);
5102 return testFile.path();
5113 if (testFile.exists())
5115 if (testFile.isSymLink())
5118 if (testFile.isFile())
5119 return testFile.path();
5120 if (testFile.isDir())
5121 return testFile.filePath();
5125 testFile.setFile(testFile.absolutePath());
5126 if (testFile.exists())
5128 if (testFile.isSymLink())
5131 if (testFile.isDir())
5132 return testFile.filePath();
5151 bool notifyOfChange =
false;
5157 if (!usedFor.isEmpty())
5163 LOG(VB_GENERAL, LOG_INFO,
LOC +
5164 QString(
"MarkAsInUse(true, '%1'->'%2')")
5166 " -- use has changed");
5170 LOG(VB_GENERAL, LOG_INFO,
LOC +
5171 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5173 #endif // DEBUG_IN_USE
5180 .arg(QObject::tr(
"Unknown")).arg(getpid());
5181 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5183 " -- use was not explicitly set");
5186 notifyOfChange =
true;
5191 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5192 QString(
"MarkAsInUse(false, '%1'->'%2')")
5194 " -- use has changed since first setting as in use.");
5199 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5202 #endif // DEBUG_IN_USE
5209 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5210 "MarkAsInUse requires a key to delete in use mark");
5218 "DELETE FROM inuseprograms "
5219 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5220 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5245 "FROM inuseprograms "
5246 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5247 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5257 else if (!query.
next())
5259 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5261 else if (query.
value(0).toBool())
5264 "UPDATE inuseprograms "
5265 "SET lastupdatetime = :UPDATETIME "
5266 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5267 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5272 query.
bindValue(
":UPDATETIME", inUseTime);
5282 "INSERT INTO inuseprograms "
5283 " (chanid, starttime, recusage, hostname, "
5284 " lastupdatetime, rechost, recdir) "
5286 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5287 " :UPDATETIME, :RECHOST, :RECDIR)");
5292 query.
bindValue(
":UPDATETIME", inUseTime);
5304 if (!notifyOfChange)
5309 query.
prepare(
"SELECT DISTINCT recusage "
5310 "FROM inuseprograms "
5311 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5312 " chanid = :CHANID AND "
5313 " starttime = :STARTTIME");
5316 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5320 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5321 while (query.
next())
5323 QString inUseForWhat = query.
value(0).toString();
5345 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5346 "FROM channel, capturecard "
5347 "WHERE channel.chanid = :CHANID AND "
5348 " capturecard.sourceid = :SOURCEID AND "
5349 " capturecard.cardid = :INPUTID");
5356 channum = query.
value(0).toString();
5357 input = query.
value(1).toString();
5366 static bool s_done =
false;
5367 static QMutex s_initTrLock;
5368 QMutexLocker locker(&s_initTrLock);
5372 QString rec_profile_names =
5373 QObject::tr(
"Default",
"Recording Profile Default") +
5374 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5375 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5376 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5377 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5378 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5379 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5382 QString rec_profile_groups =
5383 QObject::tr(
"CRC IP Recorders",
5384 "Recording Profile Group Name") +
5385 QObject::tr(
"FireWire Input",
5386 "Recording Profile Group Name") +
5387 QObject::tr(
"Freebox Input",
5388 "Recording Profile Group Name") +
5389 QObject::tr(
"Hardware DVB Encoders",
5390 "Recording Profile Group Name") +
5391 QObject::tr(
"Hardware HDTV",
5392 "Recording Profile Group Name") +
5393 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5394 "Recording Profile Group Name") +
5395 QObject::tr(
"HD-PVR Recorders",
5396 "Recording Profile Group Name") +
5397 QObject::tr(
"HDHomeRun Recorders",
5398 "Recording Profile Group Name") +
5399 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5400 "Recording Profile Group Name") +
5401 QObject::tr(
"Software Encoders (V4L based)",
5402 "Recording Profile Group Name") +
5403 QObject::tr(
"Transcoders",
5404 "Recording Profile Group Name") +
5405 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5406 "Recording Profile Group Name") +
5407 QObject::tr(
"V4L2 Encoders",
5408 "Recording Profile Group Name");
5410 QString display_rec_groups =
5411 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5412 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5413 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5414 QObject::tr(
"Default",
"Recording Group Default") +
5415 QObject::tr(
"Deleted",
"Recording Group Deleted");
5417 QString special_program_groups =
5418 QObject::tr(
"All Programs - %1",
5419 "Show all programs from a specific recording group");
5421 QString storage_groups =
5422 QObject::tr(
"Default",
"Storage Group Name") +
5423 QObject::tr(
"Live TV",
"Storage Group Name") +
5424 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5425 QObject::tr(
"DB Backups",
"Storage Group Name");
5427 QString play_groups =
5428 QObject::tr(
"Default",
"Playback Group Name");
5431 return (rec_profile_names.length() +
5432 rec_profile_groups.length() +
5433 display_rec_groups.length() +
5434 special_program_groups.length() +
5435 storage_groups.length() +
5436 play_groups.length());
5451 QByteArray msg_arr = msg.toLatin1();
5452 QString msg_i18n = QObject::tr(msg_arr.constData());
5453 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5454 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5466 if (pburl.startsWith(
"myth://"))
5468 str.replace(QString(
"%DIR%"), pburl);
5472 QFileInfo dirInfo(pburl);
5473 str.replace(QString(
"%DIR%"), dirInfo.path());
5481 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5482 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5483 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5484 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5485 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5487 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5488 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5489 str.replace(QString(
"%CATEGORY%"),
m_category);
5490 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5492 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5493 str.replace(QString(
"%INETREF%"),
m_inetRef);
5494 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5495 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5496 str.replace(QString(
"%ORIGINALAIRDATE%"),
5498 static const std::array<const QString,4> s_timeStr
5499 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5500 const std::array<const QDateTime *,4> time_dtr
5502 for (
size_t i = 0; i < s_timeStr.size(); i++)
5504 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5505 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5506 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5508 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5509 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5510 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5513 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5518 QMap<QString, uint32_t> inUseMap;
5523 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5524 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5525 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5530 while (query.
next())
5533 query.
value(0).toUInt(),
5536 QString inUseForWhat = query.
value(2).toString();
5538 if (!inUseMap.contains(inUseKey))
5539 inUseMap[inUseKey] = 0;
5542 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5544 inUseMap[inUseKey] |= FL_INUSERECORDING;
5546 inUseMap[inUseKey] |= FL_INUSEOTHER;
5554 QMap<QString,bool> is_job_running;
5557 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5558 "WHERE type = :TYPE");
5561 return is_job_running;
5563 while (query.
next())
5567 int tmpStatus = query.
value(2).toInt();
5568 if ((tmpStatus != 0x0000) &&
5569 (tmpStatus != 0x0001) &&
5570 (!(tmpStatus & 0x0100)))
5577 return is_job_running;
5581 const QString &tmptable,
int recordid)
5586 if (
sched && tmptable.isEmpty())
5594 LOG(VB_GENERAL, LOG_ERR,
5595 "Called from master backend\n\t\t\t"
5596 "with recordid or tmptable, this is not currently supported");
5601 (tmptable.isEmpty()) ?
5602 QString(
"QUERY_GETALLPENDING") :
5603 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5607 LOG(VB_GENERAL, LOG_ALERT,
5608 "LoadFromScheduler(): Error querying master.");
5626 QString columns = QString(
5627 "program.chanid, program.starttime, program.endtime, "
5628 "program.title, program.subtitle, program.description, "
5629 "program.category, channel.channum, channel.callsign, "
5630 "channel.name, program.previouslyshown, channel.commmethod, "
5631 "channel.outputfilters, program.seriesid, program.programid, "
5632 "program.airdate, program.stars, program.originalairdate, "
5633 "program.category_type, oldrecstatus.recordid, "
5634 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5635 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5636 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5637 "program.partnumber, program.parttotal, "
5638 "program.season, program.episode, program.totalepisodes ");
5640 QString querystr = QString(
5643 "LEFT JOIN channel ON program.chanid = channel.chanid "
5644 "LEFT JOIN oldrecorded AS oldrecstatus ON "
5645 " oldrecstatus.future = 0 AND "
5646 " program.title = oldrecstatus.title AND "
5647 " channel.callsign = oldrecstatus.station AND "
5648 " program.starttime = oldrecstatus.starttime "
5654 querystr += QString(
"LIMIT %1 ").arg(limit);
5655 else if (!querystr.contains(
" LIMIT "))
5656 querystr +=
" LIMIT 20000 ";
5658 MSqlBindings::const_iterator it;
5675 if (start > 0 || limit > 0)
5677 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS program.chanid");
5679 for (it = bindings.begin(); it != bindings.end(); ++it)
5681 if (countStr.contains(it.key()))
5691 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5692 count = query.
value(0).toUInt();
5696 querystr += QString(
"OFFSET %1 ").arg(start);
5698 querystr = querystr.arg(columns);
5700 for (it = bindings.begin(); it != bindings.end(); ++it)
5702 if (querystr.contains(it.key()))
5716 const QString &groupBy,
const QString &orderBy,
5721 QString queryStr =
"";
5723 if (!where.isEmpty())
5724 queryStr.append(QString(
"WHERE %1 ").arg(where));
5726 if (!groupBy.isEmpty())
5727 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5729 if (!orderBy.isEmpty())
5730 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5734 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0, count);
5743 QString queryStr = sql;
5757 if (!queryStr.contains(
"WHERE"))
5758 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5766 if (!queryStr.contains(
"GROUP BY"))
5767 queryStr +=
" GROUP BY program.starttime, channel.channum, "
5768 " channel.callsign, program.title ";
5770 if (!queryStr.contains(
"ORDER BY"))
5772 queryStr +=
" ORDER BY program.starttime, ";
5775 if (chanorder !=
"channum")
5776 queryStr += chanorder +
" ";
5778 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5783 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0, count);
5791 destination.
clear();
5793 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5795 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5796 "clause, caller should be updated to use "
5797 "start parameter instead");
5800 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5802 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5803 "clause, caller should be updated to use "
5804 "limit parameter instead");
5813 count = query.
size();
5815 while (query.
next())
5819 query.
value(3).toString(),
5821 query.
value(4).toString(),
5823 query.
value(5).toString(),
5824 query.
value(26).toString(),
5825 query.
value(6).toString(),
5827 query.
value(0).toUInt(),
5828 query.
value(7).toString(),
5829 query.
value(8).toString(),
5830 query.
value(9).toString(),
5831 query.
value(12).toString(),
5838 query.
value(13).toString(),
5839 query.
value(14).toString(),
5842 query.
value(16).toFloat(),
5843 query.
value(15).toUInt(),
5844 query.
value(27).toUInt(),
5845 query.
value(28).toUInt(),
5846 query.
value(17).toDate(),
5848 query.
value(19).toUInt(),
5850 query.
value(22).toUInt(),
5853 query.
value(10).toBool(),
5854 query.
value(23).toInt(),
5855 query.
value(24).toInt(),
5856 query.
value(25).toInt(),
5857 query.
value(29).toUInt(),
5858 query.
value(30).toUInt(),
5859 query.
value(31).toUInt(),
5868 const QDateTime& starttime)
5875 QString sSQL =
"WHERE program.chanid = :ChanId "
5876 "AND program.starttime = :StartTime ";
5878 bindings[
":ChanId" ] = chanid;
5879 bindings[
":StartTime"] = starttime;
5884 bool hasConflicts =
false;
5893 if (progList.
empty())
5914 destination.
clear();
5920 "oldrecorded.chanid, starttime, endtime, "
5921 "title, subtitle, description, season, episode, category, seriesid, "
5922 "programid, inetref, channel.channum, channel.callsign, "
5923 "channel.name, findid, rectype, recstatus, recordid, duplicate ";
5928 "LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
5929 "WHERE oldrecorded.future = 0 "
5932 bool hasLimit = querystr.contains(
" LIMIT ",Qt::CaseInsensitive);
5936 if (!hasLimit && !querystr.contains(
" ORDER ",Qt::CaseInsensitive))
5937 querystr +=
" ORDER BY starttime DESC ";
5942 querystr += QString(
"LIMIT %1 ").arg(limit);
5950 querystr += QString(
"LIMIT %1 ").arg(nLimit);
5953 MSqlBindings::const_iterator it;
5970 if (count > 0 && (start > 0 || limit > 0))
5972 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS oldrecorded.chanid");
5974 for (it = bindings.begin(); it != bindings.end(); ++it)
5976 if (countStr.contains(it.key()))
5986 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5987 count = query.
value(0).toUInt();
5991 querystr += QString(
"OFFSET %1 ").arg(start);
5993 querystr = querystr.arg(columns);
5995 for (it = bindings.begin(); it != bindings.end(); ++it)
5997 if (querystr.contains(it.key()))
6007 while (query.
next())
6010 QString channum = QString(
"#%1").arg(chanid);
6011 QString chansign = channum;
6012 QString channame = channum;
6013 if (!query.
value(12).toString().isEmpty())
6015 channum = query.
value(12).toString();
6016 chansign = query.
value(13).toString();
6017 channame = query.
value(14).toString();
6021 query.
value(3).toString(),
6023 query.
value(4).toString(),
6025 query.
value(5).toString(),
6026 query.
value(6).toUInt(),
6027 query.
value(7).toUInt(),
6028 query.
value(8).toString(),
6030 chanid, channum, chansign, channame,
6032 query.
value(9).toString(), query.
value(10).toString(),
6033 query.
value(11).toString(),
6041 query.
value(18).toUInt(),
6043 query.
value(15).toUInt(),
6045 query.
value(19).toBool()));
6071 bool possiblyInProgressRecordingsOnly,
6072 const QMap<QString,uint32_t> &inUseMap,
6073 const QMap<QString,bool> &isJobRunning,
6074 const QMap<QString, ProgramInfo*> &recMap,
6076 const QString &sortBy,
6080 destination.
clear();
6088 if (possiblyInProgressRecordingsOnly || ignoreLiveTV || ignoreDeleted)
6090 thequery +=
"WHERE ";
6091 if (possiblyInProgressRecordingsOnly)
6093 thequery +=
"(r.endtime >= NOW() AND r.starttime <= NOW()) ";
6097 thequery += QString(
"%1 r.recgroup != 'LiveTV' ")
6098 .arg(possiblyInProgressRecordingsOnly ?
"AND" :
"");
6102 thequery += QString(
"%1 r.recgroup != 'Deleted' ")
6103 .arg((possiblyInProgressRecordingsOnly || ignoreLiveTV)
6108 if (sortBy.isEmpty())
6111 thequery +=
"ORDER BY r.starttime ";
6113 thequery +=
"DESC ";
6117 QStringList sortByFields;
6118 sortByFields <<
"starttime" <<
"title" <<
"subtitle" <<
"season" <<
"episode" <<
"category"
6119 <<
"watched" <<
"stars" <<
"originalairdate" <<
"recgroup" <<
"storagegroup"
6120 <<
"channum" <<
"callsign" <<
"name";
6124 QStringList fields = sortBy.split(
",");
6125 for (
const QString& oneField : std::as_const(fields))
6127 bool ascending =
true;
6128 QString field = oneField.simplified().toLower();
6130 if (field.endsWith(
"desc"))
6133 field = field.remove(
"desc");
6136 if (field.endsWith(
"asc"))
6139 field = field.remove(
"asc");
6142 field = field.simplified();
6144 if (field ==
"channelname")
6147 if (sortByFields.contains(field))
6150 if (field ==
"channum" || field ==
"callsign" || field ==
"name")
6155 if (sSortBy.isEmpty())
6156 sSortBy = QString(
"%1.%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6158 sSortBy += QString(
",%1.%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6162 LOG(VB_GENERAL, LOG_WARNING, QString(
"ProgramInfo::LoadFromRecorded() got an unknown sort field '%1' - ignoring").arg(oneField));
6166 thequery +=
"ORDER BY " + sSortBy;
6178 while (query.
next())
6180 const uint chanid = query.
value(6).toUInt();
6181 QString channum = QString(
"#%1").arg(chanid);
6182 QString chansign = channum;
6183 QString channame = channum;
6185 if (!query.
value(7).toString().isEmpty())
6187 channum = query.
value(7).toString();
6188 chansign = query.
value(8).toString();
6189 channame = query.
value(9).toString();
6190 chanfilt = query.
value(10).toString();
6202 recMap.contains(key))
6207 bool save_not_commflagged =
false;
6214 set_flag(flags, FL_COMMPROCESSING ,
6219 set_flag(flags, FL_DELETEPENDING, query.
value(35).toBool());
6223 set_flag(flags, FL_REALLYEDITING, query.
value(39).toBool());
6228 if (inUseMap.contains(key))
6229 flags |= inUseMap[key];
6231 if (((flags & FL_COMMPROCESSING) != 0U) &&
6232 (isJobRunning.find(key) == isJobRunning.end()))
6234 flags &= ~FL_COMMPROCESSING;
6235 save_not_commflagged =
true;
6239 ((flags & FL_REALLYEDITING) != 0U) ||
6245 season = query.
value(51).toUInt();
6250 episode = query.
value(52).toUInt();
6253 uint totalepisodes = query.
value(53).toUInt();
6257 query.
value(55).toUInt(),
6258 query.
value(0).toString(),
6260 query.
value(1).toString(),
6262 query.
value(2).toString(),
6266 query.
value(48).toString(),
6267 query.
value(5).toString(),
6269 chanid, channum, chansign, channame, chanfilt,
6271 query.
value(11).toString(), query.
value(12).toString(),
6273 query.
value(14).toString(),
6277 query.
value(17).toString(), query.
value(18).toString(),
6278 query.
value(19).toString(),
6281 query.
value(16).toInt(),
6283 query.
value(20).toULongLong(),
6290 query.
value(23).toFloat(),
6292 query.
value(26).toUInt(),
6293 query.
value(49).toUInt(),
6294 query.
value(50).toUInt(),
6295 query.
value(27).toDate(),
6300 query.
value(29).toUInt(),
6305 query.
value(45).toUInt(),
6308 query.
value(42).toUInt(),
6309 query.
value(43).toUInt(),
6310 query.
value(44).toUInt(),
6311 query.
value(56).toString(),
6315 if (save_not_commflagged)
6324 std::vector<ProgramInfo> *list)
6326 nextRecordingStart = QDateTime();
6329 bool *conflicts = (hasConflicts) ? hasConflicts : &dummy;
6336 for (
auto *prog : progList)
6340 (nextRecordingStart.isNull() ||
6341 nextRecordingStart > prog->GetRecordingStartTime()))
6343 nextRecordingStart = prog->GetRecordingStartTime();
6351 for (
auto & prog : progList)
6355 (prog->GetRecordingStartTime() == nextRecordingStart))
6395 "SET filesize = :FILESIZE "
6396 "WHERE chanid = :CHANID AND "
6397 " starttime = :STARTTIME");
6398 query.
bindValue(
":FILESIZE", (quint64)fsize);
6429 uint64_t db_filesize = 0;
6436 "WHERE chanid = :CHANID AND "
6437 " starttime = :STARTTIME");
6441 db_filesize = query.
value(0).toULongLong();
6444 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"RI Filesize=0, DB Filesize=%1")
6458 if (now < startTime)
6462 int current = startTime.secsTo(now);
6463 int duration = startTime.secsTo(endTime);
6468 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 recorded percent %2/%3 = %4%")
6497 total = rate1000 * duration / 1000;
6509 LOG(VB_GUI, LOG_DEBUG,
6510 QString(
"%1 %2 no frame count. Please rebuild seek table for this video.")
6515 LOG(VB_GUI, LOG_DEBUG,
6516 QString(
"%1 %2 no frame count. Please rebuild seek table for this recording.")
6523 m_watchedPercent = std::clamp(100 * pos / total, (uint64_t)0, (uint64_t)100);
6524 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 %2 watched percent %3/%4 = %5%")