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 : 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();
774 QString pn = _pathname;
775 if (!_pathname.startsWith(
"myth://"))
786 const QDateTime &_startts,
787 const QDateTime &_endts)
793 "SELECT chanid, channum, callsign, name, outputfilters, commmethod "
795 "WHERE chanid=:CHANID");
814 QString channelFormat =
822 QString(
"%1 (%2)").arg(
m_title, QObject::tr(
"Manual Record"));
840 bool ignore_non_serialized_data)
868 if (!ignore_non_serialized_data || !is_same ||
924 if (!ignore_non_serialized_data)
1030 if (a.isEmpty() and (b ==
"Default"))
1032 if ((a ==
"Default") and b.isEmpty())
1172 uint chanid,
const QDateTime &recstartts)
1174 return QString(
"%1_%2").arg(chanid).arg(recstartts.toString(
Qt::ISODate));
1181 uint &chanid, QDateTime &recstartts)
1183 QStringList keyParts = uniquekey.split(
'_');
1184 if (keyParts.size() != 2)
1186 chanid = keyParts[0].toUInt();
1188 return (chanid != 0U) && recstartts.isValid();
1192 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1194 QString basename = pathname.section(
'/', -1);
1195 if (basename.isEmpty())
1198 QStringList lr = basename.split(
"_");
1201 chanid = lr[0].toUInt();
1202 QStringList ts = lr[1].split(
".");
1203 if (chanid && !ts.empty())
1206 return recstartts.isValid();
1214 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1216 QString basename = pathname.section(
'/', -1);
1217 if (basename.isEmpty())
1222 "SELECT chanid, starttime "
1224 "WHERE basename = :BASENAME");
1228 chanid = query.
value(0).toUInt();
1239 QString basename = pathname.section(
'/', -1);
1240 if (basename.isEmpty())
1245 "SELECT recordedid "
1247 "WHERE basename = :BASENAME");
1251 recordedid = query.
value(0).toUInt();
1260 return QString::number(x.toSecsSinceEpoch());
1275 list << QString::number(
m_season );
1299 list << QString::number(
m_dupIn);
1311 list << QString(
"%1").arg(
m_stars);
1321 list << QString::number(
m_year);
1335 #define NEXT_STR() do { if (it == listend) \
1337 LOG(VB_GENERAL, LOG_ERR, listerror); \
1341 ts = *it++; } while (false)
1352 if (str.isEmpty() || (str ==
"0000-00-00"))
1370 const QStringList::const_iterator& listend)
1372 QString listerror =
LOC +
"FromStringList, not enough items in list.";
1436 if (!origChanid || !origRecstartts.isValid() ||
1451 template <
typename T>
1456 return propNames[0];
1459 for (
uint i = 0; i <
sizeof(T)*8 - 1; ++i)
1462 if ((props & bit) == 0)
1464 if (propNames.contains(bit))
1466 result += propNames[bit];
1469 QString
tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1470 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1474 return result.join(
'|');
1477 template <
typename T>
1479 const QString& props)
1481 if (props.isEmpty())
1486 QStringList names = props.split(
'|');
1487 for (
const auto& n : std::as_const(names) )
1489 uint bit = propNames.key(n, 0);
1492 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1550 uint date_format)
const
1555 QString channelFormat =
1557 QString longChannelFormat =
1567 QString tempSubTitle =
m_title;
1571 tempSubTitle = QString(
"%1 - \"%2\"")
1573 tempSortSubtitle = QString(
"%1 - \"%2\"")
1577 progMap[
"titlesubtitle"] = tempSubTitle;
1578 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1580 progMap[
"description"] = progMap[
"description0"] =
m_description;
1587 progMap[
"s00e00"] = QString(
"s%1e%2")
1590 progMap[
"00x00"] = QString(
"%1x%2")
1596 progMap[
"season"] = progMap[
"episode"] =
"";
1597 progMap[
"totalepisodes"] =
"";
1598 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1606 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1610 progMap[
"starttime"] =
"";
1611 progMap[
"startdate"] =
"";
1612 progMap[
"endtime"] =
"";
1613 progMap[
"enddate"] =
"";
1614 progMap[
"recstarttime"] =
"";
1615 progMap[
"recstartdate"] =
"";
1616 progMap[
"recendtime"] =
"";
1617 progMap[
"recenddate"] =
"";
1621 progMap[
"startdate"] =
"";
1622 progMap[
"recstartdate"] =
"";
1626 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1627 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1634 progMap[
"startdate"] =
1644 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1645 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1646 if (timeNow.toLocalTime().date().year() !=
1648 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1649 if (timeNow.toLocalTime().date().year() !=
1650 m_endTs.toLocalTime().date().year())
1651 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1655 progMap[
"timedate"] =
1659 progMap[
"shorttimedate"] =
1663 progMap[
"starttimedate"] =
1666 progMap[
"shortstarttimedate"] =
1670 progMap[
"lastmodifieddate"] =
1672 progMap[
"lastmodified"] =
1679 progMap[
"chanid"] = QString::number(
m_chanId);
1682 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1684 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1685 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1687 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1690 int minutes = seconds / 60;
1692 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1694 progMap[
"lenmins"] = min_str;
1695 int hours = minutes / 60;
1696 minutes = minutes % 60;
1698 progMap[
"lentime"] = min_str;
1699 if (hours > 0 && minutes > 0)
1701 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1702 progMap[
"lentime"] = QString(
"%1 %2")
1703 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1707 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1710 progMap[
"recordedpercent"] =
1713 progMap[
"watchedpercent"] =
1721 QString tmp_rec = progMap[
"rectype"];
1739 tmp_rec += QObject::tr(
"Re-Record");
1746 progMap[
"rectypestatus"] = tmp_rec;
1756 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1761 progMap[
"storagegroup"] = QObject::tr(
"Default");
1767 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1791 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1792 progMap[
"longrepeat"] = progMap[
"repeat"];
1795 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1796 .arg(QObject::tr(
"Repeat"),
1804 progMap[
"repeat"] =
"";
1805 progMap[
"longrepeat"] =
"";
1813 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1818 QString star_str = (
m_stars != 0.0F) ?
1819 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1820 progMap[
"stars"] = star_str;
1821 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1824 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1826 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1828 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1830 progMap[
"yearstars"] =
"";
1835 progMap[
"originalairdate"] =
"";
1836 progMap[
"shortoriginalairdate"] =
"";
1850 QString mediaTypeString;
1854 mediaType =
"video";
1855 mediaTypeString = QObject::tr(
"Video");
1859 mediaTypeString = QObject::tr(
"DVD");
1862 mediaType =
"httpstream";
1863 mediaTypeString = QObject::tr(
"HTTP Streaming");
1866 mediaType =
"rtspstream";
1867 mediaTypeString = QObject::tr(
"RTSP Streaming");
1870 mediaType =
"bluraydisc";
1871 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1875 mediaType =
"recording";
1876 mediaTypeString = QObject::tr(
"Recording",
1877 "Recorded file, object not action");
1879 progMap[
"mediatype"] = mediaType;
1880 progMap[
"mediatypestring"] = mediaTypeString;
1888 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1900 uint64_t last_frame = 0;
1909 if (!posMap.empty())
1911 frm_pos_map_t::const_iterator it = posMap.constEnd();
1913 last_frame = it.key();
1920 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1947 str +=
" startts(" +
1950 ") recendts(" +
m_recEndTs.toString() +
")\n";
1951 str +=
" title(" +
m_title +
")";
1959 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1964 str = QString(
"%1 at %2")
1968 str = QString(
"%1 @ %2")
1991 const uint _chanid,
const QDateTime &_recstartts)
1993 if (!_chanid || !_recstartts.isValid())
2002 "WHERE r.chanid = :CHANID AND "
2003 " r.starttime = :RECSTARTTS");
2005 query.
bindValue(
":RECSTARTTS", _recstartts);
2058 if (!query.
value(7).toString().isEmpty())
2072 QString new_basename = query.
value(14).toString();
2073 if ((
GetBasename() != new_basename) || !is_reload)
2077 LOG(VB_FILE, LOG_INFO,
LOC +
2078 QString(
"Updated pathname '%1':'%2' -> '%3'")
2214 if (index == oindex && (index < 0 ||
2273 if (index == oindex && (index < 0 ||
2368 QMap<QString, int> authMap;
2369 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2372 for (
const QString& table : tables)
2375 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2376 "FROM %1 WHERE programid <> ''").arg(table));
2381 while (query.
next())
2382 authMap[query.
value(0).toString()] = 1;
2386 int numAuths = authMap.count();
2387 LOG(VB_GENERAL, LOG_INFO,
2388 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2401 QString retval = QString(
"%1_%2.%3")
2402 .arg(QString::number(
m_chanId), starts, ext);
2408 uint chanid,
const QString &pathname,
bool use_remote)
2410 QString fn_lower = pathname.toLower();
2414 else if (fn_lower.startsWith(
"http:"))
2416 else if (fn_lower.startsWith(
"rtsp:"))
2422 if (fn_lower.startsWith(
"dvd:"))
2426 else if (fn_lower.startsWith(
"bd:"))
2430 else if (use_remote && fn_lower.startsWith(
"myth://"))
2432 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2433 QString tmpFileBD = pathname +
"/BDMV";
2461 LOG(VB_GUI, LOG_INFO,
2476 query.
prepare(
"UPDATE recorded "
2477 "SET basename = :BASENAME "
2478 "WHERE recordedid = :RECORDEDID;");
2488 query.
prepare(
"UPDATE recordedfile "
2489 "SET basename = :BASENAME "
2490 "WHERE recordedid = :RECORDEDID;");
2522 "FROM recordedfile "
2523 "WHERE recordedid = :RECORDEDID;");
2530 else if (query.
next())
2532 return query.
value(0).toString();
2536 LOG(VB_GENERAL, LOG_INFO,
2537 QString(
"QueryBasename found no entry for recording ID %1")
2552 bool checkMaster,
bool forceCheckLocal)
2559 if (basename.isEmpty())
2568 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2571 QUrl url = QUrl(fullpath);
2572 QString path = url.path();
2573 QString host = url.toString(QUrl::RemovePath).mid(7);
2574 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2578 list = host.split(
"@", Qt::SkipEmptyParts);
2580 if (!list.empty() && list.size() < 3)
2582 host = list.size() == 1 ? list[0] : list[1];
2583 group = list.size() == 1 ? QString() : list[0];
2586 if (!local.isEmpty() && sg.
FileExists(local))
2599 LOG(VB_FILE, LOG_DEBUG,
LOC +
2600 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2602 tmpURL = sgroup.
FindFile(basename);
2604 if (!tmpURL.isEmpty())
2606 LOG(VB_FILE, LOG_INFO,
LOC +
2607 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2612 LOG(VB_GENERAL, LOG_ERR,
LOC +
2613 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2614 "not be found.").arg(basename));
2617 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2623 if ((checkMaster) &&
2631 LOG(VB_FILE, LOG_INFO,
LOC +
2632 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2641 LOG(VB_FILE, LOG_INFO,
LOC +
2642 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2656 query.
prepare(
"SELECT mplexid FROM channel "
2657 "WHERE chanid = :CHANID");
2662 else if (query.
next())
2663 ret = query.
value(0).toUInt();
2666 ret = (32767 == ret) ? 0 : ret;
2678 bool is_valid = (frame > 0);
2699 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2700 " bookmark = :BOOKMARKFLAG "
2701 "WHERE recordedid = :RECORDEDID");
2703 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2715 bool isValid = frame > 0;
2740 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2741 " lastplay = :LASTPLAYFLAG "
2742 "WHERE recordedid = :RECORDEDID");
2744 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2775 "SELECT bookmarkupdate "
2777 "WHERE chanid = :CHANID AND"
2778 " starttime = :STARTTIME");
2786 else if (query.
next())
2806 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2816 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2833 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2850 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2858 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2865 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2872 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2879 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2883 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2893 const QString &serialid)
const
2895 QStringList fields = QStringList();
2900 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2901 " FROM dvdbookmark "
2902 " WHERE serialid = :SERIALID ");
2907 QString dvdstate = query.
value(0).toString();
2909 if (!dvdstate.isEmpty())
2911 fields.append(dvdstate);
2916 for(
int i = 1; i < 5; i++)
2917 fields.append(query.
value(i).toString());
2927 QStringList::const_iterator it = fields.begin();
2930 QString serialid = *(it);
2931 QString name = *(++it);
2933 if( fields.count() == 3 )
2936 QString state = *(++it);
2938 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2940 " VALUES ( :SERIALID, :NAME );");
2947 query.
prepare(
" UPDATE dvdbookmark "
2948 " SET dvdstate = :STATE , "
2949 " timestamp = NOW() "
2950 " WHERE serialid = :SERIALID");
2957 query.
prepare(
"DELETE FROM dvdbookmark "
2958 "WHERE serialid = :SERIALID");
2971 QStringList fields = QStringList();
2976 query.
prepare(
" SELECT bdstate FROM bdbookmark "
2977 " WHERE serialid = :SERIALID ");
2981 fields.append(query.
value(0).toString());
2989 QStringList::const_iterator it = fields.begin();
2992 QString serialid = *(it);
2993 QString name = *(++it);
2995 if( fields.count() == 3 )
2998 QString state = *(++it);
3000 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
3002 " VALUES ( :SERIALID, :NAME );");
3009 query.
prepare(
" UPDATE bdbookmark "
3010 " SET bdstate = :STATE , "
3011 " timestamp = NOW() "
3012 " WHERE serialid = :SERIALID");
3019 query.
prepare(
"DELETE FROM bdbookmark "
3020 "WHERE serialid = :SERIALID");
3039 query.
prepare(
" SELECT category_type "
3040 " FROM recordedprogram "
3041 " WHERE chanid = :CHANID "
3042 " AND starttime = :STARTTIME;");
3062 query.
prepare(
"UPDATE recorded"
3063 " SET watched = :WATCHEDFLAG"
3064 " WHERE chanid = :CHANID"
3065 " AND starttime = :STARTTIME ;");
3068 query.
bindValue(
":WATCHEDFLAG", watched);
3080 if (url.startsWith(
"myth://"))
3082 url = QUrl(url).path();
3087 query.
prepare(
"UPDATE videometadata"
3088 " SET watched = :WATCHEDFLAG"
3089 " WHERE title = :TITLE"
3090 " AND subtitle = :SUBTITLE"
3091 " AND filename = :FILENAME ;");
3095 query.
bindValue(
":WATCHEDFLAG", watched);
3114 query.
prepare(
"SELECT editing FROM recorded"
3115 " WHERE chanid = :CHANID"
3116 " AND starttime = :STARTTIME ;");
3121 editing = query.
value(0).toBool();
3138 query.
prepare(
"UPDATE recorded"
3139 " SET editing = :EDIT"
3140 " WHERE chanid = :CHANID"
3141 " AND starttime = :STARTTIME ;");
3163 query.
prepare(
"UPDATE recorded"
3164 " SET deletepending = :DELETEFLAG, "
3166 " WHERE chanid = :CHANID"
3167 " AND starttime = :STARTTIME ;");
3170 query.
bindValue(
":DELETEFLAG", deleteFlag);
3195 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3196 " WHERE chanid = :CHANID"
3197 " AND starttime = :STARTTIME "
3198 " AND lastupdatetime > :ONEHOURAGO ;");
3201 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3204 if (query.
exec() && query.
size() > 0)
3208 while (query.
next())
3210 usageStr = QObject::tr(
"Unknown");
3211 recusage = query.
value(1).toString();
3214 usageStr = QObject::tr(
"Playing");
3216 usageStr = QObject::tr(
"PIP");
3218 usageStr = QObject::tr(
"PBP");
3221 usageStr = QObject::tr(
"Recording");
3223 usageStr = QObject::tr(
"File transfer");
3225 usageStr = QObject::tr(
"Delete");
3227 usageStr = QObject::tr(
"Commercial Detection");
3229 usageStr = QObject::tr(
"Transcoding");
3231 usageStr = QObject::tr(
"Preview Generation");
3233 usageStr = QObject::tr(
"User Job");
3235 byWho.push_back(recusage);
3236 byWho.push_back(query.
value(0).toString());
3237 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3255 for (
int i = 0; i+2 < users.size(); i+=3)
3256 byWho += users[i+2] +
"\n";
3283 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3293 (one_playback_allowed && (play_cnt <= 1)));
3295 ok = ok && (ft_cnt == jq_cnt);
3306 query.
prepare(
"SELECT transcoded FROM recorded"
3307 " WHERE chanid = :CHANID"
3308 " AND starttime = :STARTTIME ;");
3328 "SET transcoded = :VALUE "
3329 "WHERE chanid = :CHANID AND"
3330 " starttime = :STARTTIME");
3349 query.
prepare(
"UPDATE recorded"
3350 " SET commflagged = :FLAG"
3351 " WHERE chanid = :CHANID"
3352 " AND starttime = :STARTTIME ;");
3375 query.
prepare(
"UPDATE recorded"
3376 " SET preserve = :PRESERVE"
3377 " WHERE chanid = :CHANID"
3378 " AND starttime = :STARTTIME ;");
3379 query.
bindValue(
":PRESERVE", preserveEpisode);
3402 query.
prepare(
"UPDATE recorded"
3403 " SET autoexpire = :AUTOEXPIRE"
3404 " WHERE chanid = :CHANID"
3405 " AND starttime = :STARTTIME ;");
3412 else if (updateDelete)
3431 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3432 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3435 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3436 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3437 "WHERE recordid = :RECORDID");
3439 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3443 query.
prepare(
"UPDATE record SET last_delete = NULL "
3444 "WHERE recordid = :RECORDID");
3457 query.
prepare(
"SELECT autoexpire FROM recorded"
3458 " WHERE chanid = :CHANID"
3459 " AND starttime = :STARTTIME ;");
3480 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3482 uint64_t frame = i.key();
3488 delMap[frame] =
mark;
3498 return !delMap.isEmpty();
3514 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3516 uint64_t frame = i.key();
3525 tmpDelMap[frame] =
mark;
3534 query.
prepare(
"UPDATE recorded"
3535 " SET cutlist = :CUTLIST"
3536 " WHERE chanid = :CHANID"
3537 " AND starttime = :STARTTIME ;");
3539 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3568 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3571 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3574 comp += QString(
" AND type = :TYPE ");
3578 query.
prepare(
"DELETE FROM filemarkup"
3579 " WHERE filename = :PATH "
3585 query.
prepare(
"DELETE FROM recordedmarkup"
3586 " WHERE chanid = :CHANID"
3587 " AND STARTTIME = :STARTTIME"
3604 int64_t min_frame, int64_t max_frame)
const
3616 query.
prepare(
"SELECT starttime FROM recorded"
3617 " WHERE chanid = :CHANID"
3618 " AND starttime = :STARTTIME ;");
3633 frm_dir_map_t::const_iterator it;
3634 for (it =
marks.begin(); it !=
marks.end(); ++it)
3636 uint64_t frame = it.key();
3638 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3641 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3648 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3649 " VALUES ( :PATH , :MARK , :TYPE );");
3654 query.
prepare(
"INSERT INTO recordedmarkup"
3655 " (chanid, starttime, mark, type)"
3656 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3660 query.
bindValue(
":MARK", (quint64)frame);
3686 const QString &video_pathname,
3695 query.
prepare(
"SELECT mark, type, `offset` "
3697 "WHERE filename = :PATH AND "
3700 query.
bindValue(
":PATH", video_pathname);
3709 while (query.
next())
3713 int entryType = query.
value(1).toInt();
3723 uint chanid,
const QDateTime &recstartts,
3731 query.
prepare(
"SELECT mark, type, data "
3732 "FROM recordedmarkup "
3733 "WHERE chanid = :CHANID AND "
3734 " starttime = :STARTTIME AND"
3738 query.
bindValue(
":STARTTIME", recstartts);
3747 while (query.
next())
3751 int entryType = query.
value(1).toInt();
3766 return flagMap.contains(0);
3794 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3795 " WHERE filename = :PATH"
3796 " AND type = :TYPE ;");
3801 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3802 " WHERE chanid = :CHANID"
3803 " AND starttime = :STARTTIME"
3804 " AND type = :TYPE ;");
3820 while (query.
next())
3821 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3837 query.
prepare(
"DELETE FROM filemarkup"
3838 " WHERE filename = :PATH"
3839 " AND type = :TYPE ;");
3844 query.
prepare(
"DELETE FROM recordedseek"
3845 " WHERE chanid = :CHANID"
3846 " AND starttime = :STARTTIME"
3847 " AND type = :TYPE ;");
3864 int64_t min_frame, int64_t max_frame)
const
3870 if ((min_frame >= 0) || (max_frame >= 0))
3878 uint64_t frame = it.key();
3879 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3881 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3883 new_map.insert(it.key(), *it);
3893 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3895 uint64_t frame = it.key();
3896 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3898 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3902 .insert(frame, *it);
3912 comp +=
" AND mark >= :MIN_FRAME ";
3914 comp +=
" AND mark <= :MAX_FRAME ";
3921 query.
prepare(
"DELETE FROM filemarkup"
3922 " WHERE filename = :PATH"
3929 query.
prepare(
"DELETE FROM recordedseek"
3930 " WHERE chanid = :CHANID"
3931 " AND starttime = :STARTTIME"
3944 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3946 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3951 if (posMap.isEmpty())
3955 QStringList q(
"INSERT INTO ");
3959 q <<
"filemarkup (filename, type, mark, `offset`)";
3960 qfields = QString(
"('%1',%2,") .
3967 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
3968 qfields = QString(
"(%1,'%2',%3,") .
3975 bool add_comma =
false;
3976 frm_pos_map_t::iterator it;
3977 for (it = posMap.begin(); it != posMap.end(); ++it)
3979 uint64_t frame = it.key();
3981 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3984 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3987 uint64_t offset = *it;
3997 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4009 if (posMap.isEmpty())
4016 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4023 QStringList q(
"INSERT INTO ");
4027 q <<
"filemarkup (filename, type, mark, `offset`)";
4028 qfields = QString(
"('%1',%2,") .
4035 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4036 qfields = QString(
"(%1,'%2',%3,") .
4047 bool add_comma =
false;
4048 frm_pos_map_t::iterator it;
4049 for (it = posMap.begin(); it != posMap.end(); ++it)
4051 uint64_t frame = it.key();
4052 uint64_t offset = *it;
4062 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4074 "SELECT mark, `offset` FROM filemarkup"
4075 " WHERE filename = :PATH"
4077 " AND mark >= :QUERY_ARG"
4078 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4080 "SELECT mark, `offset` FROM filemarkup"
4081 " WHERE filename = :PATH"
4083 " AND mark <= :QUERY_ARG"
4084 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4086 "SELECT mark, `offset` FROM recordedseek"
4087 " WHERE chanid = :CHANID"
4088 " AND starttime = :STARTTIME"
4090 " AND mark >= :QUERY_ARG"
4091 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4093 "SELECT mark, `offset` FROM recordedseek"
4094 " WHERE chanid = :CHANID"
4095 " AND starttime = :STARTTIME"
4097 " AND mark <= :QUERY_ARG"
4098 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4100 "SELECT `offset`,mark FROM filemarkup"
4101 " WHERE filename = :PATH"
4103 " AND `offset` >= :QUERY_ARG"
4104 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4106 "SELECT `offset`,mark FROM filemarkup"
4107 " WHERE filename = :PATH"
4109 " AND `offset` <= :QUERY_ARG"
4110 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4112 "SELECT `offset`,mark FROM recordedseek"
4113 " WHERE chanid = :CHANID"
4114 " AND starttime = :STARTTIME"
4116 " AND `offset` >= :QUERY_ARG"
4117 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4119 "SELECT `offset`,mark FROM recordedseek"
4120 " WHERE chanid = :CHANID"
4121 " AND starttime = :STARTTIME"
4123 " AND `offset` <= :QUERY_ARG"
4124 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4127 uint64_t position_or_keyframe,
4130 const char *from_filemarkup_asc,
4131 const char *from_filemarkup_desc,
4132 const char *from_recordedseek_asc,
4133 const char *from_recordedseek_desc)
const
4140 query.
prepare(from_filemarkup_desc);
4142 query.
prepare(from_filemarkup_asc);
4148 query.
prepare(from_recordedseek_desc);
4150 query.
prepare(from_recordedseek_asc);
4155 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4165 *result = query.
value(1).toULongLong();
4172 query.
prepare(from_filemarkup_asc);
4174 query.
prepare(from_filemarkup_desc);
4180 query.
prepare(from_recordedseek_asc);
4182 query.
prepare(from_recordedseek_desc);
4187 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4197 *result = query.
value(1).toULongLong();
4206 bool backwards)
const
4215 bool backwards)
const
4224 bool backwards)
const
4233 bool backwards)
const
4253 query.
prepare(
"INSERT INTO recordedmarkup"
4254 " (chanid, starttime, mark, type, data)"
4256 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4260 query.
bindValue(
":MARK", (quint64)frame);
4268 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4269 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4271 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4289 query.
prepare(
"INSERT INTO recordedmarkup"
4290 " (chanid, starttime, mark, type, data)"
4292 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4295 query.
bindValue(
":MARK", (quint64)frame);
4314 query.
prepare(
"INSERT INTO recordedmarkup"
4315 " (chanid, starttime, mark, type, data)"
4317 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4320 query.
bindValue(
":MARK", (quint64)frame);
4334 query.
prepare(
"DELETE FROM recordedmarkup "
4335 " WHERE chanid=:CHANID "
4336 " AND starttime=:STARTTIME "
4339 query.
bindValue(
":STARTTIME", recstartts);
4351 query.
prepare(
"DELETE FROM filemarkup"
4352 " WHERE filename = :PATH "
4353 " AND type = :TYPE ;");
4366 query.
prepare(
"INSERT INTO filemarkup"
4367 " (filename, mark, type, `offset`)"
4369 " ( :PATH , :MARK , :TYPE, :OFFSET );");
4384 query.
prepare(
"INSERT INTO recordedmarkup"
4385 " (chanid, starttime, mark, type, data)"
4387 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4389 query.
bindValue(
":STARTTIME", recstartts);
4441 query.
prepare(
"INSERT INTO recordedmarkup"
4442 " (chanid, starttime, mark, type, data)"
4444 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4447 query.
bindValue(
":MARK", (quint64)frame);
4454 query.
prepare(
"INSERT INTO recordedmarkup"
4455 " (chanid, starttime, mark, type, data)"
4457 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4460 query.
bindValue(
":MARK", (quint64)frame);
4471 QString qstr = QString(
4472 "SELECT recordedmarkup.data "
4473 "FROM recordedmarkup "
4474 "WHERE recordedmarkup.chanid = :CHANID AND "
4475 " recordedmarkup.starttime = :STARTTIME AND "
4476 " recordedmarkup.type = :TYPE "
4477 "GROUP BY recordedmarkup.data "
4478 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4479 " FROM recordedmarkup AS rm "
4480 " WHERE rm.chanid = recordedmarkup.chanid AND "
4481 " rm.starttime = recordedmarkup.starttime AND "
4482 " rm.type = recordedmarkup.type AND "
4483 " rm.mark > recordedmarkup.mark "
4484 " ORDER BY rm.mark ASC LIMIT 1 "
4485 " ) - recordedmarkup.mark "
4493 query.
bindValue(
":STARTTIME", recstartts);
4501 return (query.
next()) ? query.
value(0).toUInt() : 0;
4507 QString qstr = QString(
4508 "SELECT filemarkup.`offset` "
4510 "WHERE filemarkup.filename = :PATH AND "
4511 " filemarkup.type = :TYPE "
4512 "GROUP BY filemarkup.`offset` "
4513 "ORDER BY SUM( ( SELECT IFNULL(fm.mark, filemarkup.mark)"
4514 " FROM filemarkup AS fm "
4515 " WHERE fm.filename = filemarkup.filename AND "
4516 " fm.type = filemarkup.type AND "
4517 " fm.mark > filemarkup.mark "
4518 " ORDER BY fm.mark ASC LIMIT 1 "
4519 " ) - filemarkup.mark "
4534 return (query.
next()) ? query.
value(0).toUInt() : 0;
4568 query.
prepare(
"SELECT recordedmarkup.type "
4569 "FROM recordedmarkup "
4570 "WHERE recordedmarkup.chanid = :CHANID AND "
4571 " recordedmarkup.starttime = :STARTTIME AND "
4572 " recordedmarkup.type >= :ASPECTSTART AND "
4573 " recordedmarkup.type <= :ASPECTEND "
4574 "GROUP BY recordedmarkup.type "
4575 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4576 " SELECT MAX(rmmax.mark) "
4577 " FROM recordedmarkup AS rmmax "
4578 " WHERE rmmax.chanid = recordedmarkup.chanid "
4579 " AND rmmax.starttime = recordedmarkup.starttime "
4581 " FROM recordedmarkup AS rm "
4582 " WHERE rm.chanid = recordedmarkup.chanid AND "
4583 " rm.starttime = recordedmarkup.starttime AND "
4584 " rm.type >= :ASPECTSTART2 AND "
4585 " rm.type <= :ASPECTEND2 AND "
4586 " rm.mark > recordedmarkup.mark "
4587 " ORDER BY rm.mark ASC LIMIT 1 "
4588 " ) - recordedmarkup.mark "
4659 QVector<MarkupEntry> &mapSeek)
const
4665 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4666 " WHERE filename = :PATH"
4667 " AND type NOT IN (:KEYFRAME,:DURATION)"
4668 " ORDER BY mark, type;");
4675 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4676 " WHERE chanid = :CHANID"
4677 " AND STARTTIME = :STARTTIME"
4678 " ORDER BY mark, type");
4691 while (query.
next())
4694 uint64_t frame = query.
value(1).toLongLong();
4696 bool isDataNull = query.
value(2).isNull();
4698 data = query.
value(2).toLongLong();
4705 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4706 " WHERE filename = :PATH"
4707 " AND type IN (:KEYFRAME,:DURATION)"
4708 " ORDER BY mark, type;");
4715 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4716 " WHERE chanid = :CHANID"
4717 " AND STARTTIME = :STARTTIME"
4718 " ORDER BY mark, type");
4727 while (query.
next())
4730 uint64_t frame = query.
value(1).toLongLong();
4732 bool isDataNull = query.
value(2).isNull();
4734 data = query.
value(2).toLongLong();
4740 const QVector<MarkupEntry> &mapSeek)
const
4746 if (mapMark.isEmpty())
4748 LOG(VB_GENERAL, LOG_INFO,
4749 QString(
"No mark entries in input, "
4750 "not removing marks from DB"));
4754 query.
prepare(
"DELETE FROM filemarkup"
4755 " WHERE filename = :PATH"
4756 " AND type NOT IN (:KEYFRAME,:DURATION)");
4765 for (
const auto& entry : std::as_const(mapMark))
4769 if (entry.isDataNull)
4771 query.
prepare(
"INSERT INTO filemarkup"
4772 " (filename,type,mark)"
4773 " VALUES (:PATH,:TYPE,:MARK)");
4777 query.
prepare(
"INSERT INTO filemarkup"
4778 " (filename,type,mark,`offset`)"
4779 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4780 query.
bindValue(
":OFFSET", (quint64)entry.data);
4784 query.
bindValue(
":MARK", (quint64)entry.frame);
4792 if (mapSeek.isEmpty())
4794 LOG(VB_GENERAL, LOG_INFO,
4795 QString(
"No seek entries in input, "
4796 "not removing marks from DB"));
4800 query.
prepare(
"DELETE FROM filemarkup"
4801 " WHERE filename = :PATH"
4802 " AND type IN (:KEYFRAME,:DURATION)");
4811 for (
int i = 0; i < mapSeek.size(); ++i)
4813 if (i > 0 && (i % 1000 == 0))
4815 LOG(VB_GENERAL, LOG_INFO,
4816 QString(
"Inserted %1 of %2 records")
4817 .arg(i).arg(mapSeek.size()));
4820 query.
prepare(
"INSERT INTO filemarkup"
4821 " (filename,type,mark,`offset`)"
4822 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4837 if (mapMark.isEmpty())
4839 LOG(VB_GENERAL, LOG_INFO,
4840 QString(
"No mark entries in input, "
4841 "not removing marks from DB"));
4845 query.
prepare(
"DELETE FROM recordedmarkup"
4846 " WHERE chanid = :CHANID"
4847 " AND starttime = :STARTTIME");
4855 for (
const auto& entry : std::as_const(mapMark))
4857 if (entry.isDataNull)
4859 query.
prepare(
"INSERT INTO recordedmarkup"
4860 " (chanid,starttime,type,mark)"
4861 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4865 query.
prepare(
"INSERT INTO recordedmarkup"
4866 " (chanid,starttime,type,mark,data)"
4867 " VALUES (:CHANID,:STARTTIME,"
4868 " :TYPE,:MARK,:OFFSET)");
4869 query.
bindValue(
":OFFSET", (quint64)entry.data);
4874 query.
bindValue(
":MARK", (quint64)entry.frame);
4882 if (mapSeek.isEmpty())
4884 LOG(VB_GENERAL, LOG_INFO,
4885 QString(
"No seek entries in input, "
4886 "not removing marks from DB"));
4890 query.
prepare(
"DELETE FROM recordedseek"
4891 " WHERE chanid = :CHANID"
4892 " AND starttime = :STARTTIME");
4900 for (
int i = 0; i < mapSeek.size(); ++i)
4902 if (i > 0 && (i % 1000 == 0))
4904 LOG(VB_GENERAL, LOG_INFO,
4905 QString(
"Inserted %1 of %2 records")
4906 .arg(i).arg(mapSeek.size()));
4909 query.
prepare(
"INSERT INTO recordedseek"
4910 " (chanid,starttime,type,mark,`offset`)"
4911 " VALUES (:CHANID,:STARTTIME,"
4912 " :TYPE,:MARK,:OFFSET)");
4932 LOG(VB_RECORD, LOG_INFO,
4933 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4934 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
4937 "UPDATE recordedprogram "
4938 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
4939 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
4942 query.
bindValue(
":FLAGS", video_property_flags);
4952 videoproperties &= ~mask;
4953 videoproperties |= video_property_flags;
4971 QString chan(format);
4981 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
5001 "SET season = :SEASON, episode = :EPISODE "
5002 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5003 "AND recordid = :RECORDID");
5025 "SET inetref = :INETREF "
5026 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5027 "AND recordid = :RECORDID");
5066 query.
prepare(
"SELECT password FROM recgroups "
5067 "WHERE recgroup = :GROUP");
5071 result = query.
value(0).toString();
5081 query.
prepare(
"SELECT recgroup FROM recorded "
5082 "WHERE chanid = :CHANID AND "
5083 " starttime = :START");
5089 grp = query.
value(0).toString();
5097 query.
prepare(
"SELECT transcoder FROM recorded "
5098 "WHERE chanid = :CHANID AND "
5099 " starttime = :START");
5104 return query.
value(0).toUInt();
5122 if (path.startsWith(
"/"))
5124 QFileInfo testFile(path);
5125 return testFile.path();
5136 if (testFile.exists())
5138 if (testFile.isSymLink())
5141 if (testFile.isFile())
5142 return testFile.path();
5143 if (testFile.isDir())
5144 return testFile.filePath();
5148 testFile.setFile(testFile.absolutePath());
5149 if (testFile.exists())
5151 if (testFile.isSymLink())
5154 if (testFile.isDir())
5155 return testFile.filePath();
5174 bool notifyOfChange =
false;
5180 if (!usedFor.isEmpty())
5186 LOG(VB_GENERAL, LOG_INFO,
LOC +
5187 QString(
"MarkAsInUse(true, '%1'->'%2')")
5189 " -- use has changed");
5193 LOG(VB_GENERAL, LOG_INFO,
LOC +
5194 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5196 #endif // DEBUG_IN_USE
5203 .arg(QObject::tr(
"Unknown")).arg(getpid());
5204 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5206 " -- use was not explicitly set");
5209 notifyOfChange =
true;
5214 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5215 QString(
"MarkAsInUse(false, '%1'->'%2')")
5217 " -- use has changed since first setting as in use.");
5222 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5225 #endif // DEBUG_IN_USE
5232 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5233 "MarkAsInUse requires a key to delete in use mark");
5241 "DELETE FROM inuseprograms "
5242 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5243 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5268 "FROM inuseprograms "
5269 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5270 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5280 else if (!query.
next())
5282 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5284 else if (query.
value(0).toBool())
5287 "UPDATE inuseprograms "
5288 "SET lastupdatetime = :UPDATETIME "
5289 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5290 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5295 query.
bindValue(
":UPDATETIME", inUseTime);
5305 "INSERT INTO inuseprograms "
5306 " (chanid, starttime, recusage, hostname, "
5307 " lastupdatetime, rechost, recdir) "
5309 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5310 " :UPDATETIME, :RECHOST, :RECDIR)");
5315 query.
bindValue(
":UPDATETIME", inUseTime);
5327 if (!notifyOfChange)
5332 query.
prepare(
"SELECT DISTINCT recusage "
5333 "FROM inuseprograms "
5334 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5335 " chanid = :CHANID AND "
5336 " starttime = :STARTTIME");
5339 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5343 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5344 while (query.
next())
5346 QString inUseForWhat = query.
value(0).toString();
5368 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5369 "FROM channel, capturecard "
5370 "WHERE channel.chanid = :CHANID AND "
5371 " capturecard.sourceid = :SOURCEID AND "
5372 " capturecard.cardid = :INPUTID");
5379 channum = query.
value(0).toString();
5380 input = query.
value(1).toString();
5389 static bool s_done =
false;
5390 static QMutex s_initTrLock;
5391 QMutexLocker locker(&s_initTrLock);
5395 QString rec_profile_names =
5396 QObject::tr(
"Default",
"Recording Profile Default") +
5397 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5398 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5399 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5400 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5401 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5402 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5405 QString rec_profile_groups =
5406 QObject::tr(
"CRC IP Recorders",
5407 "Recording Profile Group Name") +
5408 QObject::tr(
"FireWire Input",
5409 "Recording Profile Group Name") +
5410 QObject::tr(
"Freebox Input",
5411 "Recording Profile Group Name") +
5412 QObject::tr(
"Hardware DVB Encoders",
5413 "Recording Profile Group Name") +
5414 QObject::tr(
"Hardware HDTV",
5415 "Recording Profile Group Name") +
5416 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5417 "Recording Profile Group Name") +
5418 QObject::tr(
"HD-PVR Recorders",
5419 "Recording Profile Group Name") +
5420 QObject::tr(
"HDHomeRun Recorders",
5421 "Recording Profile Group Name") +
5422 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5423 "Recording Profile Group Name") +
5424 QObject::tr(
"Software Encoders (V4L based)",
5425 "Recording Profile Group Name") +
5426 QObject::tr(
"Transcoders",
5427 "Recording Profile Group Name") +
5428 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5429 "Recording Profile Group Name") +
5430 QObject::tr(
"V4L2 Encoders",
5431 "Recording Profile Group Name");
5433 QString display_rec_groups =
5434 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5435 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5436 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5437 QObject::tr(
"Default",
"Recording Group Default") +
5438 QObject::tr(
"Deleted",
"Recording Group Deleted");
5440 QString special_program_groups =
5441 QObject::tr(
"All Programs - %1",
5442 "Show all programs from a specific recording group");
5444 QString storage_groups =
5445 QObject::tr(
"Default",
"Storage Group Name") +
5446 QObject::tr(
"Live TV",
"Storage Group Name") +
5447 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5448 QObject::tr(
"DB Backups",
"Storage Group Name");
5450 QString play_groups =
5451 QObject::tr(
"Default",
"Playback Group Name");
5454 return (rec_profile_names.length() +
5455 rec_profile_groups.length() +
5456 display_rec_groups.length() +
5457 special_program_groups.length() +
5458 storage_groups.length() +
5459 play_groups.length());
5474 QByteArray msg_arr = msg.toLatin1();
5475 QString msg_i18n = QObject::tr(msg_arr.constData());
5476 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5477 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5489 if (pburl.startsWith(
"myth://"))
5491 str.replace(QString(
"%DIR%"), pburl);
5495 QFileInfo dirInfo(pburl);
5496 str.replace(QString(
"%DIR%"), dirInfo.path());
5504 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5505 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5506 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5507 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5508 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5510 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5511 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5512 str.replace(QString(
"%CATEGORY%"),
m_category);
5513 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5515 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5516 str.replace(QString(
"%INETREF%"),
m_inetRef);
5517 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5518 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5519 str.replace(QString(
"%ORIGINALAIRDATE%"),
5521 static const std::array<const QString,4> s_timeStr
5522 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5523 const std::array<const QDateTime *,4> time_dtr
5525 for (
size_t i = 0; i < s_timeStr.size(); i++)
5527 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5528 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5529 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5531 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5532 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5533 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5536 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5541 QMap<QString, uint32_t> inUseMap;
5546 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5547 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5548 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5553 while (query.
next())
5556 query.
value(0).toUInt(),
5559 QString inUseForWhat = query.
value(2).toString();
5561 if (!inUseMap.contains(inUseKey))
5562 inUseMap[inUseKey] = 0;
5565 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5567 inUseMap[inUseKey] |= FL_INUSERECORDING;
5569 inUseMap[inUseKey] |= FL_INUSEOTHER;
5577 QMap<QString,bool> is_job_running;
5580 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5581 "WHERE type = :TYPE");
5584 return is_job_running;
5586 while (query.
next())
5590 int tmpStatus = query.
value(2).toInt();
5591 if ((tmpStatus != 0x0000) &&
5592 (tmpStatus != 0x0001) &&
5593 (!(tmpStatus & 0x0100)))
5600 return is_job_running;
5604 const QString &tmptable,
int recordid)
5609 if (
sched && tmptable.isEmpty())
5617 LOG(VB_GENERAL, LOG_ERR,
5618 "Called from master backend\n\t\t\t"
5619 "with recordid or tmptable, this is not currently supported");
5624 (tmptable.isEmpty()) ?
5625 QString(
"QUERY_GETALLPENDING") :
5626 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5630 LOG(VB_GENERAL, LOG_ALERT,
5631 "LoadFromScheduler(): Error querying master.");
5649 QString columns = QString(
5650 "program.chanid, program.starttime, program.endtime, "
5651 "program.title, program.subtitle, program.description, "
5652 "program.category, channel.channum, channel.callsign, "
5653 "channel.name, program.previouslyshown, channel.commmethod, "
5654 "channel.outputfilters, program.seriesid, program.programid, "
5655 "program.airdate, program.stars, program.originalairdate, "
5656 "program.category_type, oldrecstatus.recordid, "
5657 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5658 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5659 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5660 "program.partnumber, program.parttotal, "
5661 "program.season, program.episode, program.totalepisodes ");
5663 QString querystr = QString(
5666 "LEFT JOIN channel ON program.chanid = channel.chanid "
5667 "LEFT JOIN oldrecorded AS oldrecstatus ON "
5668 " oldrecstatus.future = 0 AND "
5669 " program.title = oldrecstatus.title AND "
5670 " channel.callsign = oldrecstatus.station AND "
5671 " program.starttime = oldrecstatus.starttime "
5677 querystr += QString(
"LIMIT %1 ").arg(limit);
5678 else if (!querystr.contains(
" LIMIT "))
5679 querystr +=
" LIMIT 20000 ";
5681 MSqlBindings::const_iterator it;
5698 if (start > 0 || limit > 0)
5700 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS program.chanid");
5702 for (it = bindings.begin(); it != bindings.end(); ++it)
5704 if (countStr.contains(it.key()))
5714 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5715 count = query.
value(0).toUInt();
5719 querystr += QString(
"OFFSET %1 ").arg(start);
5721 querystr = querystr.arg(columns);
5723 for (it = bindings.begin(); it != bindings.end(); ++it)
5725 if (querystr.contains(it.key()))
5739 const QString &groupBy,
const QString &orderBy,
5744 QString queryStr =
"";
5746 if (!where.isEmpty())
5747 queryStr.append(QString(
"WHERE %1 ").arg(where));
5749 if (!groupBy.isEmpty())
5750 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5752 if (!orderBy.isEmpty())
5753 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5757 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0, count);
5766 QString queryStr = sql;
5780 if (!queryStr.contains(
"WHERE"))
5781 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5789 if (!queryStr.contains(
"GROUP BY"))
5790 queryStr +=
" GROUP BY program.starttime, channel.channum, "
5791 " channel.callsign, program.title ";
5793 if (!queryStr.contains(
"ORDER BY"))
5795 queryStr +=
" ORDER BY program.starttime, ";
5798 if (chanorder !=
"channum")
5799 queryStr += chanorder +
" ";
5801 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5806 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0, count);
5814 destination.
clear();
5816 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5818 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5819 "clause, caller should be updated to use "
5820 "start parameter instead");
5823 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5825 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5826 "clause, caller should be updated to use "
5827 "limit parameter instead");
5836 count = query.
size();
5838 while (query.
next())
5842 query.
value(3).toString(),
5844 query.
value(4).toString(),
5846 query.
value(5).toString(),
5847 query.
value(26).toString(),
5848 query.
value(6).toString(),
5850 query.
value(0).toUInt(),
5851 query.
value(7).toString(),
5852 query.
value(8).toString(),
5853 query.
value(9).toString(),
5854 query.
value(12).toString(),
5861 query.
value(13).toString(),
5862 query.
value(14).toString(),
5865 query.
value(16).toFloat(),
5866 query.
value(15).toUInt(),
5867 query.
value(27).toUInt(),
5868 query.
value(28).toUInt(),
5869 query.
value(17).toDate(),
5871 query.
value(19).toUInt(),
5873 query.
value(22).toUInt(),
5876 query.
value(10).toBool(),
5877 query.
value(23).toInt(),
5878 query.
value(24).toInt(),
5879 query.
value(25).toInt(),
5880 query.
value(29).toUInt(),
5881 query.
value(30).toUInt(),
5882 query.
value(31).toUInt(),
5891 const QDateTime& starttime)
5898 QString sSQL =
"WHERE program.chanid = :ChanId "
5899 "AND program.starttime = :StartTime ";
5901 bindings[
":ChanId" ] = chanid;
5902 bindings[
":StartTime"] = starttime;
5907 bool hasConflicts =
false;
5916 if (progList.
empty())
5937 destination.
clear();
5943 "oldrecorded.chanid, starttime, endtime, "
5944 "title, subtitle, description, season, episode, category, seriesid, "
5945 "programid, inetref, channel.channum, channel.callsign, "
5946 "channel.name, findid, rectype, recstatus, recordid, duplicate ";
5951 "LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
5952 "WHERE oldrecorded.future = 0 "
5955 bool hasLimit = querystr.contains(
" LIMIT ",Qt::CaseInsensitive);
5959 if (!hasLimit && !querystr.contains(
" ORDER ",Qt::CaseInsensitive))
5960 querystr +=
" ORDER BY starttime DESC ";
5965 querystr += QString(
"LIMIT %1 ").arg(limit);
5971 nLimit = std::max(nLimit, 100);
5972 querystr += QString(
"LIMIT %1 ").arg(nLimit);
5975 MSqlBindings::const_iterator it;
5992 if (count > 0 && (start > 0 || limit > 0))
5994 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS oldrecorded.chanid");
5996 for (it = bindings.begin(); it != bindings.end(); ++it)
5998 if (countStr.contains(it.key()))
6008 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
6009 count = query.
value(0).toUInt();
6013 querystr += QString(
"OFFSET %1 ").arg(start);
6015 querystr = querystr.arg(columns);
6017 for (it = bindings.begin(); it != bindings.end(); ++it)
6019 if (querystr.contains(it.key()))
6029 while (query.
next())
6032 QString channum = QString(
"#%1").arg(chanid);
6033 QString chansign = channum;
6034 QString channame = channum;
6035 if (!query.
value(12).toString().isEmpty())
6037 channum = query.
value(12).toString();
6038 chansign = query.
value(13).toString();
6039 channame = query.
value(14).toString();
6043 query.
value(3).toString(),
6045 query.
value(4).toString(),
6047 query.
value(5).toString(),
6048 query.
value(6).toUInt(),
6049 query.
value(7).toUInt(),
6050 query.
value(8).toString(),
6052 chanid, channum, chansign, channame,
6054 query.
value(9).toString(), query.
value(10).toString(),
6055 query.
value(11).toString(),
6063 query.
value(18).toUInt(),
6065 query.
value(15).toUInt(),
6067 query.
value(19).toBool()));
6093 bool possiblyInProgressRecordingsOnly,
6094 const QMap<QString,uint32_t> &inUseMap,
6095 const QMap<QString,bool> &isJobRunning,
6096 const QMap<QString, ProgramInfo*> &recMap,
6098 const QString &sortBy,
6102 destination.
clear();
6110 if (possiblyInProgressRecordingsOnly || ignoreLiveTV || ignoreDeleted)
6112 thequery +=
"WHERE ";
6113 if (possiblyInProgressRecordingsOnly)
6115 thequery +=
"(r.endtime >= NOW() AND r.starttime <= NOW()) ";
6119 thequery += QString(
"%1 r.recgroup != 'LiveTV' ")
6120 .arg(possiblyInProgressRecordingsOnly ?
"AND" :
"");
6124 thequery += QString(
"%1 r.recgroup != 'Deleted' ")
6125 .arg((possiblyInProgressRecordingsOnly || ignoreLiveTV)
6130 if (sortBy.isEmpty())
6133 thequery +=
"ORDER BY r.starttime ";
6135 thequery +=
"DESC ";
6139 QStringList sortByFields;
6140 sortByFields <<
"starttime" <<
"title" <<
"subtitle" <<
"season" <<
"episode" <<
"category"
6141 <<
"watched" <<
"stars" <<
"originalairdate" <<
"recgroup" <<
"storagegroup"
6142 <<
"channum" <<
"callsign" <<
"name";
6146 QStringList fields = sortBy.split(
",");
6147 for (
const QString& oneField : std::as_const(fields))
6149 bool ascending =
true;
6150 QString field = oneField.simplified().toLower();
6152 if (field.endsWith(
"desc"))
6155 field = field.remove(
"desc");
6158 if (field.endsWith(
"asc"))
6161 field = field.remove(
"asc");
6164 field = field.simplified();
6166 if (field ==
"channelname")
6169 if (sortByFields.contains(field))
6172 if (field ==
"channum" || field ==
"callsign" || field ==
"name")
6177 if (sSortBy.isEmpty())
6178 sSortBy = QString(
"%1.%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6180 sSortBy += QString(
",%1.%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6184 LOG(VB_GENERAL, LOG_WARNING, QString(
"ProgramInfo::LoadFromRecorded() got an unknown sort field '%1' - ignoring").arg(oneField));
6188 thequery +=
"ORDER BY " + sSortBy;
6200 while (query.
next())
6202 const uint chanid = query.
value(6).toUInt();
6203 QString channum = QString(
"#%1").arg(chanid);
6204 QString chansign = channum;
6205 QString channame = channum;
6207 if (!query.
value(7).toString().isEmpty())
6209 channum = query.
value(7).toString();
6210 chansign = query.
value(8).toString();
6211 channame = query.
value(9).toString();
6212 chanfilt = query.
value(10).toString();
6224 recMap.contains(key))
6229 bool save_not_commflagged =
false;
6236 set_flag(flags, FL_COMMPROCESSING ,
6241 set_flag(flags, FL_DELETEPENDING, query.
value(35).toBool());
6245 set_flag(flags, FL_REALLYEDITING, query.
value(39).toBool());
6250 if (inUseMap.contains(key))
6251 flags |= inUseMap[key];
6253 if (((flags & FL_COMMPROCESSING) != 0U) &&
6254 (isJobRunning.find(key) == isJobRunning.end()))
6256 flags &= ~FL_COMMPROCESSING;
6257 save_not_commflagged =
true;
6261 ((flags & FL_REALLYEDITING) != 0U) ||
6267 season = query.
value(51).toUInt();
6272 episode = query.
value(52).toUInt();
6275 uint totalepisodes = query.
value(53).toUInt();
6279 query.
value(55).toUInt(),
6280 query.
value(0).toString(),
6282 query.
value(1).toString(),
6284 query.
value(2).toString(),
6288 query.
value(48).toString(),
6289 query.
value(5).toString(),
6291 chanid, channum, chansign, channame, chanfilt,
6293 query.
value(11).toString(), query.
value(12).toString(),
6295 query.
value(14).toString(),
6299 query.
value(17).toString(), query.
value(18).toString(),
6300 query.
value(19).toString(),
6303 query.
value(16).toInt(),
6305 query.
value(20).toULongLong(),
6312 query.
value(23).toFloat(),
6314 query.
value(26).toUInt(),
6315 query.
value(49).toUInt(),
6316 query.
value(50).toUInt(),
6317 query.
value(27).toDate(),
6322 query.
value(29).toUInt(),
6327 query.
value(45).toUInt(),
6330 query.
value(42).toUInt(),
6331 query.
value(43).toUInt(),
6332 query.
value(44).toUInt(),
6333 query.
value(56).toString(),
6337 if (save_not_commflagged)
6346 std::vector<ProgramInfo> *list)
6348 nextRecordingStart = QDateTime();
6351 bool *conflicts = (hasConflicts) ? hasConflicts : &dummy;
6358 for (
auto *prog : progList)
6362 (nextRecordingStart.isNull() ||
6363 nextRecordingStart > prog->GetRecordingStartTime()))
6365 nextRecordingStart = prog->GetRecordingStartTime();
6373 for (
auto & prog : progList)
6377 (prog->GetRecordingStartTime() == nextRecordingStart))
6379 list->push_back(*prog);
6417 "SET filesize = :FILESIZE "
6418 "WHERE chanid = :CHANID AND "
6419 " starttime = :STARTTIME");
6420 query.
bindValue(
":FILESIZE", (quint64)fsize);
6451 uint64_t db_filesize = 0;
6458 "WHERE chanid = :CHANID AND "
6459 " starttime = :STARTTIME");
6463 db_filesize = query.
value(0).toULongLong();
6466 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"RI Filesize=0, DB Filesize=%1")
6480 if (now < startTime)
6484 int current = startTime.secsTo(now);
6485 int duration = startTime.secsTo(endTime);
6490 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 recorded percent %2/%3 = %4%")
6519 total = rate1000 * duration / 1000;
6531 LOG(VB_GUI, LOG_DEBUG,
6532 QString(
"%1 %2 no frame count. Please rebuild seek table for this video.")
6537 LOG(VB_GUI, LOG_DEBUG,
6538 QString(
"%1 %2 no frame count. Please rebuild seek table for this recording.")
6546 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 %2 watched percent %3/%4 = %5%")