34 #define LOC QString("ProgramInfo(%1): ").arg(GetBasename())
49 #define DEFINE_FLAGS_NAMES
51 #undef DEFINE_FLAGS_NAMES
54 "SELECT r.title, r.subtitle, r.description, "
55 " r.season, r.episode, r.category, "
56 " r.chanid, c.channum, c.callsign, "
57 " c.name, c.outputfilters,r.recgroup, "
58 " r.playgroup, r.storagegroup, r.basename, "
59 " r.hostname, r.recpriority, r.seriesid, "
60 " r.programid, r.inetref, r.filesize, "
61 " r.progstart, r.progend, r.stars, "
62 " r.starttime, r.endtime, p.airdate+0, "
63 " r.originalairdate, r.lastmodified, r.recordid, "
64 " c.commmethod, r.commflagged, r.previouslyshown, "
65 " r.transcoder, r.transcoded, r.deletepending, "
66 " r.preserve, r.cutlist, r.autoexpire, "
67 " r.editing, r.bookmark, r.watched, "
68 " p.audioprop+0, p.videoprop+0, p.subtitletypes+0, "
69 " r.findid, rec.dupin, rec.dupmethod, "
70 " p.syndicatedepisodenumber, p.partnumber, p.parttotal, "
71 " p.season, p.episode, p.totalepisodes, "
72 " p.category_type, r.recordedid, r.inputname, "
73 " r.bookmarkupdate, r.lastplay "
75 "LEFT JOIN channel AS c "
76 "ON (r.chanid = c.chanid) "
77 "LEFT JOIN recordedprogram AS p "
78 "ON (r.chanid = p.chanid AND "
79 " r.progstart = p.starttime) "
80 "LEFT JOIN record AS rec "
81 "ON (r.recordid = rec.recordid) ";
83 static void set_flag(uint32_t &flags,
int flag_to_set,
bool is_set)
85 flags &= ~flag_to_set;
94 if (!url.startsWith(
"dvd:") && !url.startsWith(
"bd:"))
96 if(url.endsWith(
".img", Qt::CaseInsensitive) ||
97 url.endsWith(
".iso", Qt::CaseInsensitive))
102 result =
"bd:" + url;
106 result =
"dvd:" + url;
116 if (QDir(url +
"/BDMV").
exists())
117 result =
"bd:" + url;
118 else if (QDir(url +
"/VIDEO_TS").
exists())
119 result =
"dvd:" + url;
126 static const std::array<const QString,ProgramInfo::kNumCatTypes>
kCatName
127 {
"",
"movie",
"series",
"sports",
"tvshow" };
140 for (
size_t i = 1; i <
kCatName.size(); i++)
150 m_title(other.m_title),
151 m_sortTitle(other.m_sortTitle),
152 m_subtitle(other.m_subtitle),
153 m_sortSubtitle(other.m_sortSubtitle),
154 m_description(other.m_description),
155 m_season(other.m_season),
156 m_episode(other.m_episode),
157 m_totalEpisodes(other.m_totalEpisodes),
158 m_syndicatedEpisode(other.m_syndicatedEpisode),
159 m_category(other.m_category),
160 m_director(other.m_director),
162 m_recPriority(other.m_recPriority),
164 m_chanId(other.m_chanId),
165 m_chanStr(other.m_chanStr),
166 m_chanSign(other.m_chanSign),
167 m_chanName(other.m_chanName),
168 m_chanPlaybackFilters(other.m_chanPlaybackFilters),
170 m_recGroup(other.m_recGroup),
171 m_playGroup(other.m_playGroup),
173 m_pathname(other.m_pathname),
175 m_hostname(other.m_hostname),
176 m_storageGroup(other.m_storageGroup),
178 m_seriesId(other.m_seriesId),
179 m_programId(other.m_programId),
180 m_inetRef(other.m_inetRef),
181 m_catType(other.m_catType),
183 m_fileSize(other.m_fileSize),
185 m_startTs(other.m_startTs),
186 m_endTs(other.m_endTs),
187 m_recStartTs(other.m_recStartTs),
188 m_recEndTs(other.m_recEndTs),
190 m_stars(other.m_stars),
192 m_originalAirDate(other.m_originalAirDate),
193 m_lastModified(other.m_lastModified),
196 m_recPriority2(other.m_recPriority2),
197 m_recordId(other.m_recordId),
198 m_parentId(other.m_parentId),
200 m_sourceId(other.m_sourceId),
201 m_inputId(other.m_inputId),
203 m_findId(other.m_findId),
204 m_programFlags(other.m_programFlags),
205 m_videoProperties(other.m_videoProperties),
206 m_audioProperties(other.m_audioProperties),
207 m_subtitleProperties(other.m_subtitleProperties),
208 m_year(other.m_year),
209 m_partNumber(other.m_partNumber),
210 m_partTotal(other.m_partTotal),
212 m_recStatus(other.m_recStatus),
213 m_recType(other.m_recType),
214 m_dupIn(other.m_dupIn),
215 m_dupMethod(other.m_dupMethod),
217 m_recordedId(other.m_recordedId),
218 m_inputName(other.m_inputName),
219 m_bookmarkUpdate(other.m_bookmarkUpdate),
222 m_availableStatus(other.m_availableStatus),
223 m_spread(other.m_spread),
224 m_startCol(other.m_startCol),
227 m_positionMapDBReplacement(other.m_positionMapDBReplacement)
241 "SELECT chanid, starttime "
243 "WHERE recordedid = :RECORDEDID");
244 query.
bindValue(
":RECORDEDID", _recordedid);
254 LOG(VB_GENERAL, LOG_CRIT,
LOC +
255 QString(
"Failed to find recorded entry for %1.")
282 QString _sortSubtitle,
283 QString _description,
287 QString _syndicatedepisode,
294 QString _chanplaybackfilters,
299 const QString &_pathname,
302 QString _storagegroup,
315 QDateTime _recstartts,
323 QDate _originalAirDate,
324 QDateTime _lastmodified,
336 uint _audioproperties,
337 uint _videoproperties,
340 QDateTime _bookmarkupdate) :
341 m_title(std::move(_title)),
342 m_sortTitle(std::move(_sortTitle)),
343 m_subtitle(std::move(_subtitle)),
344 m_sortSubtitle(std::move(_sortSubtitle)),
345 m_description(std::move(_description)),
348 m_totalEpisodes(_totalepisodes),
349 m_syndicatedEpisode(std::move(_syndicatedepisode)),
350 m_category(std::move(_category)),
352 m_recPriority(_recpriority),
355 m_chanStr(std::move(_channum)),
356 m_chanSign(std::move(_chansign)),
357 m_chanName(std::move(_channame)),
358 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
360 m_recGroup(std::move(_recgroup)),
361 m_playGroup(std::move(_playgroup)),
363 m_pathname(_pathname),
365 m_hostname(std::move(_hostname)),
366 m_storageGroup(std::move(_storagegroup)),
368 m_seriesId(std::move(_seriesid)),
369 m_programId(std::move(_programid)),
370 m_inetRef(std::move(_inetref)),
373 m_fileSize(_filesize),
375 m_startTs(std::move(_startts)),
376 m_endTs(std::move(_endts)),
377 m_recStartTs(std::move(_recstartts)),
378 m_recEndTs(std::move(_recendts)),
380 m_stars(std::
clamp(_stars, 0.0F, 1.0F)),
382 m_originalAirDate(_originalAirDate),
383 m_lastModified(std::move(_lastmodified)),
386 m_recordId(_recordid),
389 m_programFlags(_programflags),
390 m_videoProperties(_videoproperties),
391 m_audioProperties(_audioproperties),
392 m_subtitleProperties(_subtitleType),
394 m_partNumber(_partnumber),
395 m_partTotal(_parttotal),
397 m_recStatus(_recstatus),
399 m_dupMethod(_dupmethod),
401 m_recordedId(_recordedid),
402 m_inputName(std::move(_inputname)),
403 m_bookmarkUpdate(std::move(_bookmarkupdate))
419 QString _sortSubtitle,
420 QString _description,
436 QDateTime _recstartts,
448 m_title(std::move(_title)),
449 m_sortTitle(std::move(_sortTitle)),
450 m_subtitle(std::move(_subtitle)),
451 m_sortSubtitle(std::move(_sortSubtitle)),
452 m_description(std::move(_description)),
455 m_category(std::move(_category)),
458 m_chanStr(std::move(_channum)),
459 m_chanSign(std::move(_chansign)),
460 m_chanName(std::move(_channame)),
462 m_seriesId(std::move(_seriesid)),
463 m_programId(std::move(_programid)),
464 m_inetRef(std::move(_inetref)),
466 m_startTs(std::move(_startts)),
467 m_endTs(std::move(_endts)),
468 m_recStartTs(std::move(_recstartts)),
469 m_recEndTs(std::move(_recendts)),
471 m_lastModified(m_startTs),
474 m_recordId(_recordid),
477 m_programFlags((duplicate) ? FL_DUPLICATE : FL_NONE),
479 m_recStatus(_recstatus),
494 QString _sortSubtitle,
495 QString _description,
496 QString _syndicatedepisode,
503 QString _chanplaybackfilters,
507 QDateTime _recstartts,
519 QDate _originalAirDate,
528 uint _videoproperties,
529 uint _audioproperties,
537 m_title(std::move(_title)),
538 m_sortTitle(std::move(_sortTitle)),
539 m_subtitle(std::move(_subtitle)),
540 m_sortSubtitle(std::move(_sortSubtitle)),
541 m_description(std::move(_description)),
544 m_totalEpisodes(_totalepisodes),
545 m_syndicatedEpisode(std::move(_syndicatedepisode)),
546 m_category(std::move(_category)),
549 m_chanStr(std::move(_channum)),
550 m_chanSign(std::move(_chansign)),
551 m_chanName(std::move(_channame)),
552 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
554 m_seriesId(std::move(_seriesid)),
555 m_programId(std::move(_programid)),
558 m_startTs(std::move(_startts)),
559 m_endTs(std::move(_endts)),
560 m_recStartTs(std::move(_recstartts)),
561 m_recEndTs(std::move(_recendts)),
563 m_stars(std::
clamp(_stars, 0.0F, 1.0F)),
565 m_originalAirDate(_originalAirDate),
566 m_lastModified(m_startTs),
567 m_lastInUseTime(m_startTs.addSecs(-kLastInUseOffset)),
569 m_recordId(_recordid),
572 m_videoProperties(_videoproperties),
573 m_audioProperties(_audioproperties),
574 m_subtitleProperties(_subtitleType),
576 m_partNumber(_partnumber),
577 m_partTotal(_parttotal),
579 m_recStatus(_recstatus),
588 for (
auto *it : schedList)
638 QString _sortSubtitle,
639 QString _description,
649 QString _chanplaybackfilters,
656 QDateTime _recstartts,
662 QString _inputname) :
663 m_title(std::move(_title)),
664 m_sortTitle(std::move(_sortTitle)),
665 m_subtitle(std::move(_subtitle)),
666 m_sortSubtitle(std::move(_sortSubtitle)),
667 m_description(std::move(_description)),
670 m_totalEpisodes(_totalepisodes),
671 m_category(std::move(_category)),
674 m_chanStr(std::move(_channum)),
675 m_chanSign(std::move(_chansign)),
676 m_chanName(std::move(_channame)),
677 m_chanPlaybackFilters(std::move(_chanplaybackfilters)),
679 m_recGroup(std::move(_recgroup)),
680 m_playGroup(std::move(_playgroup)),
682 m_seriesId(std::move(_seriesid)),
683 m_programId(std::move(_programid)),
684 m_inetRef(std::move(_inetref)),
686 m_startTs(std::move(_startts)),
687 m_endTs(std::move(_endts)),
688 m_recStartTs(std::move(_recstartts)),
689 m_recEndTs(std::move(_recendts)),
692 m_lastInUseTime(m_lastModified.addSecs(-kLastInUseOffset)),
694 m_inputName(std::move(_inputname))
705 if (_pathname.isEmpty())
711 QDateTime _recstartts;
725 QString basename = _pathname.section(
'/', -1);
726 if (_pathname == basename)
727 SetPathname(QDir::currentPath() +
'/' + _pathname);
728 else if (_pathname.contains(
"./") && !_pathname.contains(
":"))
729 SetPathname(QFileInfo(_pathname).absoluteFilePath());
739 const QString &_plot,
740 const QString &_title,
741 const QString &_sortTitle,
742 const QString &_subtitle,
743 const QString &_sortSubtitle,
744 const QString &_director,
745 int _season,
int _episode,
746 const QString &_inetref,
747 std::chrono::minutes length_in_minutes,
749 const QString &_programid)
769 int64_t minutes = length_in_minutes.count();
772 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
776 QTimeZone(QTimeZone::UTC));
780 QString pn = _pathname;
781 if (!_pathname.startsWith(
"myth://"))
792 const QDateTime &_startts,
793 const QDateTime &_endts)
799 "SELECT chanid, channum, callsign, name, outputfilters, commmethod "
801 "WHERE chanid=:CHANID");
820 QString channelFormat =
828 QString(
"%1 (%2)").arg(
m_title, QObject::tr(
"Manual Record"));
846 bool ignore_non_serialized_data)
874 if (!ignore_non_serialized_data || !is_same ||
930 if (!ignore_non_serialized_data)
1036 if (a.isEmpty() and (b ==
"Default"))
1038 if ((a ==
"Default") and b.isEmpty())
1178 uint chanid,
const QDateTime &recstartts)
1180 return QString(
"%1_%2").arg(chanid).arg(recstartts.toString(
Qt::ISODate));
1187 uint &chanid, QDateTime &recstartts)
1189 QStringList keyParts = uniquekey.split(
'_');
1190 if (keyParts.size() != 2)
1192 chanid = keyParts[0].toUInt();
1194 return (chanid != 0U) && recstartts.isValid();
1198 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1200 QString basename = pathname.section(
'/', -1);
1201 if (basename.isEmpty())
1204 QStringList lr = basename.split(
"_");
1207 chanid = lr[0].toUInt();
1208 QStringList ts = lr[1].split(
".");
1209 if (chanid && !ts.empty())
1212 return recstartts.isValid();
1220 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1222 QString basename = pathname.section(
'/', -1);
1223 if (basename.isEmpty())
1228 "SELECT chanid, starttime "
1230 "WHERE basename = :BASENAME");
1234 chanid = query.
value(0).toUInt();
1245 QString basename = pathname.section(
'/', -1);
1246 if (basename.isEmpty())
1251 "SELECT recordedid "
1253 "WHERE basename = :BASENAME");
1257 recordedid = query.
value(0).toUInt();
1266 return QString::number(x.toSecsSinceEpoch());
1281 list << QString::number(
m_season );
1305 list << QString::number(
m_dupIn);
1317 list << QString(
"%1").arg(
m_stars);
1327 list << QString::number(
m_year);
1341 #define NEXT_STR() do { if (it == listend) \
1343 LOG(VB_GENERAL, LOG_ERR, listerror); \
1347 ts = *it++; } while (false)
1358 if (str.isEmpty() || (str ==
"0000-00-00"))
1376 const QStringList::const_iterator& listend)
1378 QString listerror =
LOC +
"FromStringList, not enough items in list.";
1442 if (!origChanid || !origRecstartts.isValid() ||
1457 template <
typename T>
1462 return propNames[0];
1465 for (
uint i = 0; i <
sizeof(T)*8 - 1; ++i)
1468 if ((props & bit) == 0)
1470 if (propNames.contains(bit))
1472 result += propNames[bit];
1475 QString
tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1476 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1480 return result.join(
'|');
1483 template <
typename T>
1485 const QString& props)
1487 if (props.isEmpty())
1492 QStringList names = props.split(
'|');
1493 for (
const auto& n : std::as_const(names) )
1495 uint bit = propNames.key(n, 0);
1498 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1536 tmp_rec += QObject::tr(
"Re-Record");
1591 uint date_format)
const
1596 QString channelFormat =
1598 QString longChannelFormat =
1608 QString tempSubTitle =
m_title;
1612 tempSubTitle = QString(
"%1 - \"%2\"")
1614 tempSortSubtitle = QString(
"%1 - \"%2\"")
1618 progMap[
"titlesubtitle"] = tempSubTitle;
1619 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1621 progMap[
"description"] = progMap[
"description0"] =
m_description;
1628 progMap[
"s00e00"] = QString(
"s%1e%2")
1631 progMap[
"00x00"] = QString(
"%1x%2")
1637 progMap[
"season"] = progMap[
"episode"] =
"";
1638 progMap[
"totalepisodes"] =
"";
1639 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1647 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1651 progMap[
"starttime"] =
"";
1652 progMap[
"startdate"] =
"";
1653 progMap[
"endtime"] =
"";
1654 progMap[
"enddate"] =
"";
1655 progMap[
"recstarttime"] =
"";
1656 progMap[
"recstartdate"] =
"";
1657 progMap[
"recendtime"] =
"";
1658 progMap[
"recenddate"] =
"";
1662 progMap[
"startdate"] =
"";
1663 progMap[
"recstartdate"] =
"";
1667 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1668 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1675 progMap[
"startdate"] =
1685 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1686 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1687 if (timeNow.toLocalTime().date().year() !=
1689 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1690 if (timeNow.toLocalTime().date().year() !=
1691 m_endTs.toLocalTime().date().year())
1692 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1696 progMap[
"timedate"] =
1700 progMap[
"shorttimedate"] =
1704 progMap[
"starttimedate"] =
1707 progMap[
"shortstarttimedate"] =
1711 progMap[
"lastmodifieddate"] =
1713 progMap[
"lastmodified"] =
1720 progMap[
"chanid"] = QString::number(
m_chanId);
1723 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1725 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1726 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1728 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1731 int minutes = seconds / 60;
1733 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1735 progMap[
"lenmins"] = min_str;
1736 int hours = minutes / 60;
1737 minutes = minutes % 60;
1739 progMap[
"lentime"] = min_str;
1740 if (hours > 0 && minutes > 0)
1742 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1743 progMap[
"lentime"] = QString(
"%1 %2")
1744 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1748 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1751 progMap[
"recordedpercent"] =
1754 progMap[
"watchedpercent"] =
1772 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1777 progMap[
"storagegroup"] = QObject::tr(
"Default");
1783 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1807 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1808 progMap[
"longrepeat"] = progMap[
"repeat"];
1811 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1812 .arg(QObject::tr(
"Repeat"),
1820 progMap[
"repeat"] =
"";
1821 progMap[
"longrepeat"] =
"";
1829 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1834 QString star_str = (
m_stars != 0.0F) ?
1835 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1836 progMap[
"stars"] = star_str;
1837 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1840 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1842 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1844 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1846 progMap[
"yearstars"] =
"";
1851 progMap[
"originalairdate"] =
"";
1852 progMap[
"shortoriginalairdate"] =
"";
1866 QString mediaTypeString;
1870 mediaType =
"video";
1871 mediaTypeString = QObject::tr(
"Video");
1875 mediaTypeString = QObject::tr(
"DVD");
1878 mediaType =
"httpstream";
1879 mediaTypeString = QObject::tr(
"HTTP Streaming");
1882 mediaType =
"rtspstream";
1883 mediaTypeString = QObject::tr(
"RTSP Streaming");
1886 mediaType =
"bluraydisc";
1887 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1891 mediaType =
"recording";
1892 mediaTypeString = QObject::tr(
"Recording",
1893 "Recorded file, object not action");
1895 progMap[
"mediatype"] = mediaType;
1896 progMap[
"mediatypestring"] = mediaTypeString;
1904 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1916 uint64_t last_frame = 0;
1925 if (!posMap.empty())
1927 frm_pos_map_t::const_iterator it = posMap.constEnd();
1929 last_frame = it.key();
1936 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1963 str +=
" startts(" +
1966 ") recendts(" +
m_recEndTs.toString() +
")\n";
1967 str +=
" title(" +
m_title +
")";
1975 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1980 str = QString(
"%1 at %2")
1984 str = QString(
"%1 @ %2")
2007 const uint _chanid,
const QDateTime &_recstartts)
2009 if (!_chanid || !_recstartts.isValid())
2018 "WHERE r.chanid = :CHANID AND "
2019 " r.starttime = :RECSTARTTS");
2021 query.
bindValue(
":RECSTARTTS", _recstartts);
2074 if (!query.
value(7).toString().isEmpty())
2088 QString new_basename = query.
value(14).toString();
2089 if ((
GetBasename() != new_basename) || !is_reload)
2093 LOG(VB_FILE, LOG_INFO,
LOC +
2094 QString(
"Updated pathname '%1':'%2' -> '%3'")
2230 if (index == oindex && (index < 0 ||
2289 if (index == oindex && (index < 0 ||
2384 QMap<QString, int> authMap;
2385 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2388 for (
const QString& table : tables)
2391 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2392 "FROM %1 WHERE programid <> ''").arg(table));
2397 while (query.
next())
2398 authMap[query.
value(0).toString()] = 1;
2402 int numAuths = authMap.count();
2403 LOG(VB_GENERAL, LOG_INFO,
2404 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2417 QString retval = QString(
"%1_%2.%3")
2418 .arg(QString::number(
m_chanId), starts, ext);
2424 uint chanid,
const QString &pathname,
bool use_remote)
2426 QString fn_lower = pathname.toLower();
2430 else if (fn_lower.startsWith(
"http:"))
2432 else if (fn_lower.startsWith(
"rtsp:"))
2438 if (fn_lower.startsWith(
"dvd:"))
2442 else if (fn_lower.startsWith(
"bd:"))
2446 else if (use_remote && fn_lower.startsWith(
"myth://"))
2448 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2449 QString tmpFileBD = pathname +
"/BDMV";
2477 LOG(VB_GUI, LOG_INFO,
2492 query.
prepare(
"UPDATE recorded "
2493 "SET basename = :BASENAME "
2494 "WHERE recordedid = :RECORDEDID;");
2504 query.
prepare(
"UPDATE recordedfile "
2505 "SET basename = :BASENAME "
2506 "WHERE recordedid = :RECORDEDID;");
2538 "FROM recordedfile "
2539 "WHERE recordedid = :RECORDEDID;");
2546 else if (query.
next())
2548 return query.
value(0).toString();
2552 LOG(VB_GENERAL, LOG_INFO,
2553 QString(
"QueryBasename found no entry for recording ID %1")
2568 bool checkMaster,
bool forceCheckLocal)
2575 if (basename.isEmpty())
2584 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2587 QUrl url = QUrl(fullpath);
2588 QString path = url.path();
2589 QString host = url.toString(QUrl::RemovePath).mid(7);
2590 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2594 list = host.split(
"@", Qt::SkipEmptyParts);
2596 if (!list.empty() && list.size() < 3)
2598 host = list.size() == 1 ? list[0] : list[1];
2599 group = list.size() == 1 ? QString() : list[0];
2602 if (!local.isEmpty() && sg.
FileExists(local))
2615 LOG(VB_FILE, LOG_DEBUG,
LOC +
2616 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2618 tmpURL = sgroup.
FindFile(basename);
2620 if (!tmpURL.isEmpty())
2622 LOG(VB_FILE, LOG_INFO,
LOC +
2623 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2628 LOG(VB_GENERAL, LOG_ERR,
LOC +
2629 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2630 "not be found.").arg(basename));
2633 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2639 if ((checkMaster) &&
2647 LOG(VB_FILE, LOG_INFO,
LOC +
2648 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2657 LOG(VB_FILE, LOG_INFO,
LOC +
2658 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2672 query.
prepare(
"SELECT mplexid FROM channel "
2673 "WHERE chanid = :CHANID");
2678 else if (query.
next())
2679 ret = query.
value(0).toUInt();
2682 ret = (32767 == ret) ? 0 : ret;
2694 bool is_valid = (frame > 0);
2715 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2716 " bookmark = :BOOKMARKFLAG "
2717 "WHERE recordedid = :RECORDEDID");
2719 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2731 bool isValid = frame > 0;
2756 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2757 " lastplay = :LASTPLAYFLAG "
2758 "WHERE recordedid = :RECORDEDID");
2760 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2791 "SELECT bookmarkupdate "
2793 "WHERE chanid = :CHANID AND"
2794 " starttime = :STARTTIME");
2802 else if (query.
next())
2822 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2832 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2849 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2866 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2874 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2881 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2888 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2895 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2899 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2909 const QString &serialid)
const
2911 QStringList fields = QStringList();
2916 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2917 " FROM dvdbookmark "
2918 " WHERE serialid = :SERIALID ");
2923 QString dvdstate = query.
value(0).toString();
2925 if (!dvdstate.isEmpty())
2927 fields.append(dvdstate);
2932 for(
int i = 1; i < 5; i++)
2933 fields.append(query.
value(i).toString());
2943 QStringList::const_iterator it = fields.begin();
2946 QString serialid = *(it);
2947 QString name = *(++it);
2949 if( fields.count() == 3 )
2952 QString state = *(++it);
2954 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2956 " VALUES ( :SERIALID, :NAME );");
2963 query.
prepare(
" UPDATE dvdbookmark "
2964 " SET dvdstate = :STATE , "
2965 " timestamp = NOW() "
2966 " WHERE serialid = :SERIALID");
2973 query.
prepare(
"DELETE FROM dvdbookmark "
2974 "WHERE serialid = :SERIALID");
2987 QStringList fields = QStringList();
2992 query.
prepare(
" SELECT bdstate FROM bdbookmark "
2993 " WHERE serialid = :SERIALID ");
2997 fields.append(query.
value(0).toString());
3005 QStringList::const_iterator it = fields.begin();
3008 QString serialid = *(it);
3009 QString name = *(++it);
3011 if( fields.count() == 3 )
3014 QString state = *(++it);
3016 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
3018 " VALUES ( :SERIALID, :NAME );");
3025 query.
prepare(
" UPDATE bdbookmark "
3026 " SET bdstate = :STATE , "
3027 " timestamp = NOW() "
3028 " WHERE serialid = :SERIALID");
3035 query.
prepare(
"DELETE FROM bdbookmark "
3036 "WHERE serialid = :SERIALID");
3055 query.
prepare(
" SELECT category_type "
3056 " FROM recordedprogram "
3057 " WHERE chanid = :CHANID "
3058 " AND starttime = :STARTTIME;");
3078 query.
prepare(
"UPDATE recorded"
3079 " SET watched = :WATCHEDFLAG"
3080 " WHERE chanid = :CHANID"
3081 " AND starttime = :STARTTIME ;");
3084 query.
bindValue(
":WATCHEDFLAG", watched);
3096 if (url.startsWith(
"myth://"))
3098 url = QUrl(url).path();
3103 query.
prepare(
"UPDATE videometadata"
3104 " SET watched = :WATCHEDFLAG"
3105 " WHERE title = :TITLE"
3106 " AND subtitle = :SUBTITLE"
3107 " AND filename = :FILENAME ;");
3111 query.
bindValue(
":WATCHEDFLAG", watched);
3130 query.
prepare(
"SELECT editing FROM recorded"
3131 " WHERE chanid = :CHANID"
3132 " AND starttime = :STARTTIME ;");
3137 editing = query.
value(0).toBool();
3154 query.
prepare(
"UPDATE recorded"
3155 " SET editing = :EDIT"
3156 " WHERE chanid = :CHANID"
3157 " AND starttime = :STARTTIME ;");
3179 query.
prepare(
"UPDATE recorded"
3180 " SET deletepending = :DELETEFLAG, "
3182 " WHERE chanid = :CHANID"
3183 " AND starttime = :STARTTIME ;");
3186 query.
bindValue(
":DELETEFLAG", deleteFlag);
3211 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3212 " WHERE chanid = :CHANID"
3213 " AND starttime = :STARTTIME "
3214 " AND lastupdatetime > :ONEHOURAGO ;");
3217 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3220 if (query.
exec() && query.
size() > 0)
3224 while (query.
next())
3226 usageStr = QObject::tr(
"Unknown");
3227 recusage = query.
value(1).toString();
3230 usageStr = QObject::tr(
"Playing");
3232 usageStr = QObject::tr(
"PIP");
3234 usageStr = QObject::tr(
"PBP");
3237 usageStr = QObject::tr(
"Recording");
3239 usageStr = QObject::tr(
"File transfer");
3241 usageStr = QObject::tr(
"Delete");
3243 usageStr = QObject::tr(
"Commercial Detection");
3245 usageStr = QObject::tr(
"Transcoding");
3247 usageStr = QObject::tr(
"Preview Generation");
3249 usageStr = QObject::tr(
"User Job");
3251 byWho.push_back(recusage);
3252 byWho.push_back(query.
value(0).toString());
3253 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3271 for (
int i = 0; i+2 < users.size(); i+=3)
3272 byWho += users[i+2] +
"\n";
3299 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3309 (one_playback_allowed && (play_cnt <= 1)));
3311 ok = ok && (ft_cnt == jq_cnt);
3322 query.
prepare(
"SELECT transcoded FROM recorded"
3323 " WHERE chanid = :CHANID"
3324 " AND starttime = :STARTTIME ;");
3344 "SET transcoded = :VALUE "
3345 "WHERE chanid = :CHANID AND"
3346 " starttime = :STARTTIME");
3365 query.
prepare(
"UPDATE recorded"
3366 " SET commflagged = :FLAG"
3367 " WHERE chanid = :CHANID"
3368 " AND starttime = :STARTTIME ;");
3391 query.
prepare(
"UPDATE recorded"
3392 " SET preserve = :PRESERVE"
3393 " WHERE chanid = :CHANID"
3394 " AND starttime = :STARTTIME ;");
3395 query.
bindValue(
":PRESERVE", preserveEpisode);
3418 query.
prepare(
"UPDATE recorded"
3419 " SET autoexpire = :AUTOEXPIRE"
3420 " WHERE chanid = :CHANID"
3421 " AND starttime = :STARTTIME ;");
3428 else if (updateDelete)
3447 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3448 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3451 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3452 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3453 "WHERE recordid = :RECORDID");
3455 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3459 query.
prepare(
"UPDATE record SET last_delete = NULL "
3460 "WHERE recordid = :RECORDID");
3473 query.
prepare(
"SELECT autoexpire FROM recorded"
3474 " WHERE chanid = :CHANID"
3475 " AND starttime = :STARTTIME ;");
3496 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3498 uint64_t frame = i.key();
3504 delMap[frame] = mark;
3514 return !delMap.isEmpty();
3530 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3532 uint64_t frame = i.key();
3541 tmpDelMap[frame] = mark;
3550 query.
prepare(
"UPDATE recorded"
3551 " SET cutlist = :CUTLIST"
3552 " WHERE chanid = :CHANID"
3553 " AND starttime = :STARTTIME ;");
3555 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3584 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3587 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3590 comp += QString(
" AND type = :TYPE ");
3594 query.
prepare(
"DELETE FROM filemarkup"
3595 " WHERE filename = :PATH "
3601 query.
prepare(
"DELETE FROM recordedmarkup"
3602 " WHERE chanid = :CHANID"
3603 " AND STARTTIME = :STARTTIME"
3620 int64_t min_frame, int64_t max_frame)
const
3632 query.
prepare(
"SELECT starttime FROM recorded"
3633 " WHERE chanid = :CHANID"
3634 " AND starttime = :STARTTIME ;");
3649 frm_dir_map_t::const_iterator it;
3650 for (it = marks.begin(); it != marks.end(); ++it)
3652 uint64_t frame = it.key();
3654 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3657 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3664 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3665 " VALUES ( :PATH , :MARK , :TYPE );");
3670 query.
prepare(
"INSERT INTO recordedmarkup"
3671 " (chanid, starttime, mark, type)"
3672 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3676 query.
bindValue(
":MARK", (quint64)frame);
3693 marks,
type, merge);
3702 const QString &video_pathname,
3711 query.
prepare(
"SELECT mark, type, `offset` "
3713 "WHERE filename = :PATH AND "
3716 query.
bindValue(
":PATH", video_pathname);
3725 while (query.
next())
3729 int entryType = query.
value(1).toInt();
3739 uint chanid,
const QDateTime &recstartts,
3747 query.
prepare(
"SELECT mark, type, data "
3748 "FROM recordedmarkup "
3749 "WHERE chanid = :CHANID AND "
3750 " starttime = :STARTTIME AND"
3754 query.
bindValue(
":STARTTIME", recstartts);
3763 while (query.
next())
3767 int entryType = query.
value(1).toInt();
3782 return flagMap.contains(0);
3810 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3811 " WHERE filename = :PATH"
3812 " AND type = :TYPE ;");
3817 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3818 " WHERE chanid = :CHANID"
3819 " AND starttime = :STARTTIME"
3820 " AND type = :TYPE ;");
3836 while (query.
next())
3837 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3853 query.
prepare(
"DELETE FROM filemarkup"
3854 " WHERE filename = :PATH"
3855 " AND type = :TYPE ;");
3860 query.
prepare(
"DELETE FROM recordedseek"
3861 " WHERE chanid = :CHANID"
3862 " AND starttime = :STARTTIME"
3863 " AND type = :TYPE ;");
3880 int64_t min_frame, int64_t max_frame)
const
3886 if ((min_frame >= 0) || (max_frame >= 0))
3894 uint64_t frame = it.key();
3895 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3897 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3899 new_map.insert(it.key(), *it);
3909 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3911 uint64_t frame = it.key();
3912 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3914 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3918 .insert(frame, *it);
3928 comp +=
" AND mark >= :MIN_FRAME ";
3930 comp +=
" AND mark <= :MAX_FRAME ";
3937 query.
prepare(
"DELETE FROM filemarkup"
3938 " WHERE filename = :PATH"
3945 query.
prepare(
"DELETE FROM recordedseek"
3946 " WHERE chanid = :CHANID"
3947 " AND starttime = :STARTTIME"
3960 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3962 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3967 if (posMap.isEmpty())
3971 QStringList q(
"INSERT INTO ");
3975 q <<
"filemarkup (filename, type, mark, `offset`)";
3976 qfields = QString(
"('%1',%2,") .
3983 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
3984 qfields = QString(
"(%1,'%2',%3,") .
3991 bool add_comma =
false;
3992 frm_pos_map_t::iterator it;
3993 for (it = posMap.begin(); it != posMap.end(); ++it)
3995 uint64_t frame = it.key();
3997 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
4000 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
4003 uint64_t offset = *it;
4013 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4025 if (posMap.isEmpty())
4032 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4039 QStringList q(
"INSERT INTO ");
4043 q <<
"filemarkup (filename, type, mark, `offset`)";
4044 qfields = QString(
"('%1',%2,") .
4051 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4052 qfields = QString(
"(%1,'%2',%3,") .
4063 bool add_comma =
false;
4064 frm_pos_map_t::iterator it;
4065 for (it = posMap.begin(); it != posMap.end(); ++it)
4067 uint64_t frame = it.key();
4068 uint64_t offset = *it;
4078 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4090 "SELECT mark, `offset` FROM filemarkup"
4091 " WHERE filename = :PATH"
4093 " AND mark >= :QUERY_ARG"
4094 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4096 "SELECT mark, `offset` FROM filemarkup"
4097 " WHERE filename = :PATH"
4099 " AND mark <= :QUERY_ARG"
4100 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4102 "SELECT mark, `offset` FROM recordedseek"
4103 " WHERE chanid = :CHANID"
4104 " AND starttime = :STARTTIME"
4106 " AND mark >= :QUERY_ARG"
4107 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4109 "SELECT mark, `offset` FROM recordedseek"
4110 " WHERE chanid = :CHANID"
4111 " AND starttime = :STARTTIME"
4113 " AND mark <= :QUERY_ARG"
4114 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4116 "SELECT `offset`,mark FROM filemarkup"
4117 " WHERE filename = :PATH"
4119 " AND `offset` >= :QUERY_ARG"
4120 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4122 "SELECT `offset`,mark FROM filemarkup"
4123 " WHERE filename = :PATH"
4125 " AND `offset` <= :QUERY_ARG"
4126 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4128 "SELECT `offset`,mark FROM recordedseek"
4129 " WHERE chanid = :CHANID"
4130 " AND starttime = :STARTTIME"
4132 " AND `offset` >= :QUERY_ARG"
4133 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4135 "SELECT `offset`,mark FROM recordedseek"
4136 " WHERE chanid = :CHANID"
4137 " AND starttime = :STARTTIME"
4139 " AND `offset` <= :QUERY_ARG"
4140 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4143 uint64_t position_or_keyframe,
4146 const char *from_filemarkup_asc,
4147 const char *from_filemarkup_desc,
4148 const char *from_recordedseek_asc,
4149 const char *from_recordedseek_desc)
const
4156 query.
prepare(from_filemarkup_desc);
4158 query.
prepare(from_filemarkup_asc);
4164 query.
prepare(from_recordedseek_desc);
4166 query.
prepare(from_recordedseek_asc);
4171 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4181 *result = query.
value(1).toULongLong();
4188 query.
prepare(from_filemarkup_asc);
4190 query.
prepare(from_filemarkup_desc);
4196 query.
prepare(from_recordedseek_asc);
4198 query.
prepare(from_recordedseek_desc);
4203 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4213 *result = query.
value(1).toULongLong();
4222 bool backwards)
const
4231 bool backwards)
const
4240 bool backwards)
const
4249 bool backwards)
const
4269 query.
prepare(
"INSERT INTO recordedmarkup"
4270 " (chanid, starttime, mark, type, data)"
4272 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4276 query.
bindValue(
":MARK", (quint64)frame);
4284 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4285 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4287 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4305 query.
prepare(
"INSERT INTO recordedmarkup"
4306 " (chanid, starttime, mark, type, data)"
4308 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4311 query.
bindValue(
":MARK", (quint64)frame);
4330 query.
prepare(
"INSERT INTO recordedmarkup"
4331 " (chanid, starttime, mark, type, data)"
4333 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4336 query.
bindValue(
":MARK", (quint64)frame);
4350 query.
prepare(
"DELETE FROM recordedmarkup "
4351 " WHERE chanid=:CHANID "
4352 " AND starttime=:STARTTIME "
4355 query.
bindValue(
":STARTTIME", recstartts);
4367 query.
prepare(
"DELETE FROM filemarkup"
4368 " WHERE filename = :PATH "
4369 " AND type = :TYPE ;");
4382 query.
prepare(
"INSERT INTO filemarkup"
4383 " (filename, mark, type, `offset`)"
4385 " ( :PATH , :MARK , :TYPE, :OFFSET );");
4400 query.
prepare(
"INSERT INTO recordedmarkup"
4401 " (chanid, starttime, mark, type, data)"
4403 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4405 query.
bindValue(
":STARTTIME", recstartts);
4457 query.
prepare(
"INSERT INTO recordedmarkup"
4458 " (chanid, starttime, mark, type, data)"
4460 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4463 query.
bindValue(
":MARK", (quint64)frame);
4470 query.
prepare(
"INSERT INTO recordedmarkup"
4471 " (chanid, starttime, mark, type, data)"
4473 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4476 query.
bindValue(
":MARK", (quint64)frame);
4487 QString qstr = QString(
4488 "SELECT recordedmarkup.data "
4489 "FROM recordedmarkup "
4490 "WHERE recordedmarkup.chanid = :CHANID AND "
4491 " recordedmarkup.starttime = :STARTTIME AND "
4492 " recordedmarkup.type = :TYPE "
4493 "GROUP BY recordedmarkup.data "
4494 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4495 " FROM recordedmarkup AS rm "
4496 " WHERE rm.chanid = recordedmarkup.chanid AND "
4497 " rm.starttime = recordedmarkup.starttime AND "
4498 " rm.type = recordedmarkup.type AND "
4499 " rm.mark > recordedmarkup.mark "
4500 " ORDER BY rm.mark ASC LIMIT 1 "
4501 " ) - recordedmarkup.mark "
4509 query.
bindValue(
":STARTTIME", recstartts);
4517 return (query.
next()) ? query.
value(0).toUInt() : 0;
4523 QString qstr = QString(
4524 "SELECT filemarkup.`offset` "
4526 "WHERE filemarkup.filename = :PATH AND "
4527 " filemarkup.type = :TYPE "
4528 "GROUP BY filemarkup.`offset` "
4529 "ORDER BY SUM( ( SELECT IFNULL(fm.mark, filemarkup.mark)"
4530 " FROM filemarkup AS fm "
4531 " WHERE fm.filename = filemarkup.filename AND "
4532 " fm.type = filemarkup.type AND "
4533 " fm.mark > filemarkup.mark "
4534 " ORDER BY fm.mark ASC LIMIT 1 "
4535 " ) - filemarkup.mark "
4550 return (query.
next()) ? query.
value(0).toUInt() : 0;
4584 query.
prepare(
"SELECT recordedmarkup.type "
4585 "FROM recordedmarkup "
4586 "WHERE recordedmarkup.chanid = :CHANID AND "
4587 " recordedmarkup.starttime = :STARTTIME AND "
4588 " recordedmarkup.type >= :ASPECTSTART AND "
4589 " recordedmarkup.type <= :ASPECTEND "
4590 "GROUP BY recordedmarkup.type "
4591 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4592 " SELECT MAX(rmmax.mark) "
4593 " FROM recordedmarkup AS rmmax "
4594 " WHERE rmmax.chanid = recordedmarkup.chanid "
4595 " AND rmmax.starttime = recordedmarkup.starttime "
4597 " FROM recordedmarkup AS rm "
4598 " WHERE rm.chanid = recordedmarkup.chanid AND "
4599 " rm.starttime = recordedmarkup.starttime AND "
4600 " rm.type >= :ASPECTSTART2 AND "
4601 " rm.type <= :ASPECTEND2 AND "
4602 " rm.mark > recordedmarkup.mark "
4603 " ORDER BY rm.mark ASC LIMIT 1 "
4604 " ) - recordedmarkup.mark "
4675 QVector<MarkupEntry> &mapSeek)
const
4681 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4682 " WHERE filename = :PATH"
4683 " AND type NOT IN (:KEYFRAME,:DURATION)"
4684 " ORDER BY mark, type;");
4691 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4692 " WHERE chanid = :CHANID"
4693 " AND STARTTIME = :STARTTIME"
4694 " ORDER BY mark, type");
4707 while (query.
next())
4710 uint64_t frame = query.
value(1).toLongLong();
4712 bool isDataNull = query.
value(2).isNull();
4714 data = query.
value(2).toLongLong();
4721 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4722 " WHERE filename = :PATH"
4723 " AND type IN (:KEYFRAME,:DURATION)"
4724 " ORDER BY mark, type;");
4731 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4732 " WHERE chanid = :CHANID"
4733 " AND STARTTIME = :STARTTIME"
4734 " ORDER BY mark, type");
4743 while (query.
next())
4746 uint64_t frame = query.
value(1).toLongLong();
4748 bool isDataNull = query.
value(2).isNull();
4750 data = query.
value(2).toLongLong();
4756 const QVector<MarkupEntry> &mapSeek)
const
4762 if (mapMark.isEmpty())
4764 LOG(VB_GENERAL, LOG_INFO,
4765 QString(
"No mark entries in input, "
4766 "not removing marks from DB"));
4770 query.
prepare(
"DELETE FROM filemarkup"
4771 " WHERE filename = :PATH"
4772 " AND type NOT IN (:KEYFRAME,:DURATION)");
4781 for (
const auto& entry : std::as_const(mapMark))
4785 if (entry.isDataNull)
4787 query.
prepare(
"INSERT INTO filemarkup"
4788 " (filename,type,mark)"
4789 " VALUES (:PATH,:TYPE,:MARK)");
4793 query.
prepare(
"INSERT INTO filemarkup"
4794 " (filename,type,mark,`offset`)"
4795 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4796 query.
bindValue(
":OFFSET", (quint64)entry.data);
4800 query.
bindValue(
":MARK", (quint64)entry.frame);
4808 if (mapSeek.isEmpty())
4810 LOG(VB_GENERAL, LOG_INFO,
4811 QString(
"No seek entries in input, "
4812 "not removing marks from DB"));
4816 query.
prepare(
"DELETE FROM filemarkup"
4817 " WHERE filename = :PATH"
4818 " AND type IN (:KEYFRAME,:DURATION)");
4827 for (
int i = 0; i < mapSeek.size(); ++i)
4829 if (i > 0 && (i % 1000 == 0))
4831 LOG(VB_GENERAL, LOG_INFO,
4832 QString(
"Inserted %1 of %2 records")
4833 .arg(i).arg(mapSeek.size()));
4836 query.
prepare(
"INSERT INTO filemarkup"
4837 " (filename,type,mark,`offset`)"
4838 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4853 if (mapMark.isEmpty())
4855 LOG(VB_GENERAL, LOG_INFO,
4856 QString(
"No mark entries in input, "
4857 "not removing marks from DB"));
4861 query.
prepare(
"DELETE FROM recordedmarkup"
4862 " WHERE chanid = :CHANID"
4863 " AND starttime = :STARTTIME");
4871 for (
const auto& entry : std::as_const(mapMark))
4873 if (entry.isDataNull)
4875 query.
prepare(
"INSERT INTO recordedmarkup"
4876 " (chanid,starttime,type,mark)"
4877 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4881 query.
prepare(
"INSERT INTO recordedmarkup"
4882 " (chanid,starttime,type,mark,data)"
4883 " VALUES (:CHANID,:STARTTIME,"
4884 " :TYPE,:MARK,:OFFSET)");
4885 query.
bindValue(
":OFFSET", (quint64)entry.data);
4890 query.
bindValue(
":MARK", (quint64)entry.frame);
4898 if (mapSeek.isEmpty())
4900 LOG(VB_GENERAL, LOG_INFO,
4901 QString(
"No seek entries in input, "
4902 "not removing marks from DB"));
4906 query.
prepare(
"DELETE FROM recordedseek"
4907 " WHERE chanid = :CHANID"
4908 " AND starttime = :STARTTIME");
4916 for (
int i = 0; i < mapSeek.size(); ++i)
4918 if (i > 0 && (i % 1000 == 0))
4920 LOG(VB_GENERAL, LOG_INFO,
4921 QString(
"Inserted %1 of %2 records")
4922 .arg(i).arg(mapSeek.size()));
4925 query.
prepare(
"INSERT INTO recordedseek"
4926 " (chanid,starttime,type,mark,`offset`)"
4927 " VALUES (:CHANID,:STARTTIME,"
4928 " :TYPE,:MARK,:OFFSET)");
4948 LOG(VB_RECORD, LOG_INFO,
4949 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4950 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
4953 "UPDATE recordedprogram "
4954 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
4955 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
4958 query.
bindValue(
":FLAGS", video_property_flags);
4968 videoproperties &= ~mask;
4969 videoproperties |= video_property_flags;
4987 QString chan(format);
4997 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
5017 "SET season = :SEASON, episode = :EPISODE "
5018 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5019 "AND recordid = :RECORDID");
5041 "SET inetref = :INETREF "
5042 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
5043 "AND recordid = :RECORDID");
5082 query.
prepare(
"SELECT password FROM recgroups "
5083 "WHERE recgroup = :GROUP");
5087 result = query.
value(0).toString();
5097 query.
prepare(
"SELECT recgroup FROM recorded "
5098 "WHERE chanid = :CHANID AND "
5099 " starttime = :START");
5105 grp = query.
value(0).toString();
5113 query.
prepare(
"SELECT transcoder FROM recorded "
5114 "WHERE chanid = :CHANID AND "
5115 " starttime = :START");
5120 return query.
value(0).toUInt();
5138 if (path.startsWith(
"/"))
5140 QFileInfo testFile(path);
5141 return testFile.path();
5152 if (testFile.exists())
5154 if (testFile.isSymLink())
5157 if (testFile.isFile())
5158 return testFile.path();
5159 if (testFile.isDir())
5160 return testFile.filePath();
5164 testFile.setFile(testFile.absolutePath());
5165 if (testFile.exists())
5167 if (testFile.isSymLink())
5170 if (testFile.isDir())
5171 return testFile.filePath();
5190 bool notifyOfChange =
false;
5196 if (!usedFor.isEmpty())
5202 LOG(VB_GENERAL, LOG_INFO,
LOC +
5203 QString(
"MarkAsInUse(true, '%1'->'%2')")
5205 " -- use has changed");
5209 LOG(VB_GENERAL, LOG_INFO,
LOC +
5210 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5212 #endif // DEBUG_IN_USE
5219 .arg(QObject::tr(
"Unknown")).arg(getpid());
5220 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5222 " -- use was not explicitly set");
5225 notifyOfChange =
true;
5230 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5231 QString(
"MarkAsInUse(false, '%1'->'%2')")
5233 " -- use has changed since first setting as in use.");
5238 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5241 #endif // DEBUG_IN_USE
5248 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5249 "MarkAsInUse requires a key to delete in use mark");
5257 "DELETE FROM inuseprograms "
5258 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5259 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5284 "FROM inuseprograms "
5285 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5286 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5296 else if (!query.
next())
5298 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5300 else if (query.
value(0).toBool())
5303 "UPDATE inuseprograms "
5304 "SET lastupdatetime = :UPDATETIME "
5305 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5306 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5311 query.
bindValue(
":UPDATETIME", inUseTime);
5321 "INSERT INTO inuseprograms "
5322 " (chanid, starttime, recusage, hostname, "
5323 " lastupdatetime, rechost, recdir) "
5325 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5326 " :UPDATETIME, :RECHOST, :RECDIR)");
5331 query.
bindValue(
":UPDATETIME", inUseTime);
5343 if (!notifyOfChange)
5348 query.
prepare(
"SELECT DISTINCT recusage "
5349 "FROM inuseprograms "
5350 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5351 " chanid = :CHANID AND "
5352 " starttime = :STARTTIME");
5355 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5359 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5360 while (query.
next())
5362 QString inUseForWhat = query.
value(0).toString();
5384 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5385 "FROM channel, capturecard "
5386 "WHERE channel.chanid = :CHANID AND "
5387 " capturecard.sourceid = :SOURCEID AND "
5388 " capturecard.cardid = :INPUTID");
5395 channum = query.
value(0).toString();
5396 input = query.
value(1).toString();
5405 static bool s_done =
false;
5406 static QMutex s_initTrLock;
5407 QMutexLocker locker(&s_initTrLock);
5411 QString rec_profile_names =
5412 QObject::tr(
"Default",
"Recording Profile Default") +
5413 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5414 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5415 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5416 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5417 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5418 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5421 QString rec_profile_groups =
5422 QObject::tr(
"CRC IP Recorders",
5423 "Recording Profile Group Name") +
5424 QObject::tr(
"FireWire Input",
5425 "Recording Profile Group Name") +
5426 QObject::tr(
"Freebox Input",
5427 "Recording Profile Group Name") +
5428 QObject::tr(
"Hardware DVB Encoders",
5429 "Recording Profile Group Name") +
5430 QObject::tr(
"Hardware HDTV",
5431 "Recording Profile Group Name") +
5432 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5433 "Recording Profile Group Name") +
5434 QObject::tr(
"HD-PVR Recorders",
5435 "Recording Profile Group Name") +
5436 QObject::tr(
"HDHomeRun Recorders",
5437 "Recording Profile Group Name") +
5438 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5439 "Recording Profile Group Name") +
5440 QObject::tr(
"Software Encoders (V4L based)",
5441 "Recording Profile Group Name") +
5442 QObject::tr(
"Transcoders",
5443 "Recording Profile Group Name") +
5444 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5445 "Recording Profile Group Name") +
5446 QObject::tr(
"V4L2 Encoders",
5447 "Recording Profile Group Name");
5449 QString display_rec_groups =
5450 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5451 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5452 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5453 QObject::tr(
"Default",
"Recording Group Default") +
5454 QObject::tr(
"Deleted",
"Recording Group Deleted");
5456 QString special_program_groups =
5457 QObject::tr(
"All Programs - %1",
5458 "Show all programs from a specific recording group");
5460 QString storage_groups =
5461 QObject::tr(
"Default",
"Storage Group Name") +
5462 QObject::tr(
"Live TV",
"Storage Group Name") +
5463 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5464 QObject::tr(
"DB Backups",
"Storage Group Name");
5466 QString play_groups =
5467 QObject::tr(
"Default",
"Playback Group Name");
5470 return (rec_profile_names.length() +
5471 rec_profile_groups.length() +
5472 display_rec_groups.length() +
5473 special_program_groups.length() +
5474 storage_groups.length() +
5475 play_groups.length());
5490 QByteArray msg_arr = msg.toLatin1();
5491 QString msg_i18n = QObject::tr(msg_arr.constData());
5492 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5493 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5505 if (pburl.startsWith(
"myth://"))
5507 str.replace(QString(
"%DIR%"), pburl);
5511 QFileInfo dirInfo(pburl);
5512 str.replace(QString(
"%DIR%"), dirInfo.path());
5520 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5521 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5522 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5523 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5524 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5526 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5527 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5528 str.replace(QString(
"%CATEGORY%"),
m_category);
5529 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5531 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5532 str.replace(QString(
"%INETREF%"),
m_inetRef);
5533 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5534 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5535 str.replace(QString(
"%ORIGINALAIRDATE%"),
5537 static const std::array<const QString,4> s_timeStr
5538 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5539 const std::array<const QDateTime *,4> time_dtr
5541 for (
size_t i = 0; i < s_timeStr.size(); i++)
5543 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5544 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5545 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5547 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5548 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5549 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5552 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5557 QMap<QString, uint32_t> inUseMap;
5562 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5563 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5564 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5569 while (query.
next())
5572 query.
value(0).toUInt(),
5575 QString inUseForWhat = query.
value(2).toString();
5577 if (!inUseMap.contains(inUseKey))
5578 inUseMap[inUseKey] = 0;
5581 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5583 inUseMap[inUseKey] |= FL_INUSERECORDING;
5585 inUseMap[inUseKey] |= FL_INUSEOTHER;
5593 QMap<QString,bool> is_job_running;
5596 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5597 "WHERE type = :TYPE");
5600 return is_job_running;
5602 while (query.
next())
5606 int tmpStatus = query.
value(2).toInt();
5607 if ((tmpStatus != 0x0000) &&
5608 (tmpStatus != 0x0001) &&
5609 (!(tmpStatus & 0x0100)))
5616 return is_job_running;
5620 const QString &tmptable,
int recordid)
5625 if (
sched && tmptable.isEmpty())
5633 LOG(VB_GENERAL, LOG_ERR,
5634 "Called from master backend\n\t\t\t"
5635 "with recordid or tmptable, this is not currently supported");
5640 (tmptable.isEmpty()) ?
5641 QString(
"QUERY_GETALLPENDING") :
5642 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5646 LOG(VB_GENERAL, LOG_ALERT,
5647 "LoadFromScheduler(): Error querying master.");
5666 QString columns = QString(
5667 "program.chanid, program.starttime, program.endtime, "
5668 "program.title, program.subtitle, program.description, "
5669 "program.category, channel.channum, channel.callsign, "
5670 "channel.name, program.previouslyshown, channel.commmethod, "
5671 "channel.outputfilters, program.seriesid, program.programid, "
5672 "program.airdate, program.stars, program.originalairdate, "
5673 "program.category_type, oldrecstatus.recordid, "
5674 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5675 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5676 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5677 "program.partnumber, program.parttotal, "
5678 "program.season, program.episode, program.totalepisodes ");
5680 QString querystr = QString(
5684 " LEFT JOIN channel ON program.chanid = channel.chanid "
5685 " LEFT JOIN oldrecorded AS oldrecstatus ON "
5686 " oldrecstatus.future = 0 AND "
5687 " program.title = oldrecstatus.title AND "
5688 " channel.callsign = oldrecstatus.station AND "
5689 " program.starttime = oldrecstatus.starttime "
5700 ", row_number() over ( "
5703 columns +=
"channel.channum, "
5704 " channel.callsign, ";
5706 columns +=
"channel.callsign, ";
5708 columns +=
"program.programid, ";
5711 " program.starttime "
5712 " order by channel.recpriority desc, "
5713 " channel.sourceid, "
5714 " channel.channum+0 "
5716 querystr +=
"WHERE grouprn = 1 ";
5722 querystr += QString(
"LIMIT %1 ").arg(limit);
5723 else if (!querystr.contains(
" LIMIT "))
5724 querystr +=
" LIMIT 20000 ";
5726 MSqlBindings::const_iterator it;
5743 if (start > 0 || limit > 0)
5745 QString countStr = querystr
5746 .arg(
"SQL_CALC_FOUND_ROWS chanid", columns);
5748 for (it = bindings.begin(); it != bindings.end(); ++it)
5750 if (countStr.contains(it.key()))
5760 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5761 count = query.
value(0).toUInt();
5765 querystr += QString(
"OFFSET %1 ").arg(start);
5767 querystr = querystr.arg(
"*", columns);
5769 for (it = bindings.begin(); it != bindings.end(); ++it)
5771 if (querystr.contains(it.key()))
5785 const QString &groupBy,
const QString &orderBy,
5790 QString queryStr =
"";
5792 if (!where.isEmpty())
5793 queryStr.append(QString(
"WHERE %1 ").arg(where));
5795 if (!groupBy.isEmpty())
5796 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5798 if (!orderBy.isEmpty())
5799 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5803 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5813 QString queryStr = sql;
5827 if (!queryStr.contains(
"WHERE"))
5828 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5830 if (!queryStr.contains(
"ORDER BY"))
5832 queryStr +=
" ORDER BY program.starttime, ";
5835 if (chanorder !=
"channum")
5836 queryStr += chanorder +
" ";
5838 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5843 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0,
5853 destination.
clear();
5855 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5857 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5858 "clause, caller should be updated to use "
5859 "start parameter instead");
5862 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5864 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5865 "clause, caller should be updated to use "
5866 "limit parameter instead");
5875 count = query.
size();
5877 while (query.
next())
5881 query.
value(3).toString(),
5883 query.
value(4).toString(),
5885 query.
value(5).toString(),
5886 query.
value(26).toString(),
5887 query.
value(6).toString(),
5889 query.
value(0).toUInt(),
5890 query.
value(7).toString(),
5891 query.
value(8).toString(),
5892 query.
value(9).toString(),
5893 query.
value(12).toString(),
5900 query.
value(13).toString(),
5901 query.
value(14).toString(),
5904 query.
value(16).toFloat(),
5905 query.
value(15).toUInt(),
5906 query.
value(27).toUInt(),
5907 query.
value(28).toUInt(),
5908 query.
value(17).toDate(),
5910 query.
value(19).toUInt(),
5912 query.
value(22).toUInt(),
5915 query.
value(10).toBool(),
5916 query.
value(23).toInt(),
5917 query.
value(24).toInt(),
5918 query.
value(25).toInt(),
5919 query.
value(29).toUInt(),
5920 query.
value(30).toUInt(),
5921 query.
value(31).toUInt(),
5930 const QDateTime& starttime)
5937 QString sSQL =
"WHERE program.chanid = :ChanId "
5938 "AND program.starttime = :StartTime ";
5940 bindings[
":ChanId" ] = chanid;
5941 bindings[
":StartTime"] = starttime;
5946 bool hasConflicts =
false;
5955 if (progList.
empty())
5976 destination.
clear();
5982 "oldrecorded.chanid, starttime, endtime, "
5983 "title, subtitle, description, season, episode, category, seriesid, "
5984 "programid, inetref, channel.channum, channel.callsign, "
5985 "channel.name, findid, rectype, recstatus, recordid, duplicate ";
5990 "LEFT JOIN channel ON oldrecorded.chanid = channel.chanid "
5991 "WHERE oldrecorded.future = 0 "
5994 bool hasLimit = querystr.contains(
" LIMIT ",Qt::CaseInsensitive);
5998 if (!hasLimit && !querystr.contains(
" ORDER ",Qt::CaseInsensitive))
5999 querystr +=
" ORDER BY starttime DESC ";
6004 querystr += QString(
"LIMIT %1 ").arg(limit);
6010 nLimit = std::max(nLimit, 100);
6011 querystr += QString(
"LIMIT %1 ").arg(nLimit);
6014 MSqlBindings::const_iterator it;
6031 if (count > 0 && (start > 0 || limit > 0))
6033 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS oldrecorded.chanid");
6035 for (it = bindings.begin(); it != bindings.end(); ++it)
6037 if (countStr.contains(it.key()))
6047 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
6048 count = query.
value(0).toUInt();
6052 querystr += QString(
"OFFSET %1 ").arg(start);
6054 querystr = querystr.arg(columns);
6056 for (it = bindings.begin(); it != bindings.end(); ++it)
6058 if (querystr.contains(it.key()))
6068 while (query.
next())
6071 QString channum = QString(
"#%1").arg(chanid);
6072 QString chansign = channum;
6073 QString channame = channum;
6074 if (!query.
value(12).toString().isEmpty())
6076 channum = query.
value(12).toString();
6077 chansign = query.
value(13).toString();
6078 channame = query.
value(14).toString();
6082 query.
value(3).toString(),
6084 query.
value(4).toString(),
6086 query.
value(5).toString(),
6087 query.
value(6).toUInt(),
6088 query.
value(7).toUInt(),
6089 query.
value(8).toString(),
6091 chanid, channum, chansign, channame,
6093 query.
value(9).toString(), query.
value(10).toString(),
6094 query.
value(11).toString(),
6102 query.
value(18).toUInt(),
6104 query.
value(15).toUInt(),
6106 query.
value(19).toBool()));
6132 bool possiblyInProgressRecordingsOnly,
6133 const QMap<QString,uint32_t> &inUseMap,
6134 const QMap<QString,bool> &isJobRunning,
6135 const QMap<QString, ProgramInfo*> &recMap,
6137 const QString &sortBy,
6141 destination.
clear();
6149 if (possiblyInProgressRecordingsOnly || ignoreLiveTV || ignoreDeleted)
6151 thequery +=
"WHERE ";
6152 if (possiblyInProgressRecordingsOnly)
6154 thequery +=
"(r.endtime >= NOW() AND r.starttime <= NOW()) ";
6158 thequery += QString(
"%1 r.recgroup != 'LiveTV' ")
6159 .arg(possiblyInProgressRecordingsOnly ?
"AND" :
"");
6163 thequery += QString(
"%1 r.recgroup != 'Deleted' ")
6164 .arg((possiblyInProgressRecordingsOnly || ignoreLiveTV)
6169 if (sortBy.isEmpty())
6172 thequery +=
"ORDER BY r.starttime ";
6174 thequery +=
"DESC ";
6178 QStringList sortByFields;
6179 sortByFields <<
"starttime" <<
"title" <<
"subtitle" <<
"season" <<
"episode" <<
"category"
6180 <<
"watched" <<
"stars" <<
"originalairdate" <<
"recgroup" <<
"storagegroup"
6181 <<
"channum" <<
"callsign" <<
"name";
6185 QStringList fields = sortBy.split(
",");
6186 for (
const QString& oneField : std::as_const(fields))
6188 bool ascending =
true;
6189 QString field = oneField.simplified().toLower();
6191 if (field.endsWith(
"desc"))
6194 field = field.remove(
"desc");
6197 if (field.endsWith(
"asc"))
6200 field = field.remove(
"asc");
6203 field = field.simplified();
6205 if (field ==
"channelname")
6208 if (sortByFields.contains(field))
6211 if (field ==
"channum" || field ==
"callsign" || field ==
"name")
6216 if (sSortBy.isEmpty())
6217 sSortBy = QString(
"%1.%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6219 sSortBy += QString(
",%1.%2 %3").arg(table, field, ascending ?
"ASC" :
"DESC");
6223 LOG(VB_GENERAL, LOG_WARNING, QString(
"ProgramInfo::LoadFromRecorded() got an unknown sort field '%1' - ignoring").arg(oneField));
6227 thequery +=
"ORDER BY " + sSortBy;
6239 while (query.
next())
6241 const uint chanid = query.
value(6).toUInt();
6242 QString channum = QString(
"#%1").arg(chanid);
6243 QString chansign = channum;
6244 QString channame = channum;
6246 if (!query.
value(7).toString().isEmpty())
6248 channum = query.
value(7).toString();
6249 chansign = query.
value(8).toString();
6250 channame = query.
value(9).toString();
6251 chanfilt = query.
value(10).toString();
6263 recMap.contains(key))
6268 bool save_not_commflagged =
false;
6275 set_flag(flags, FL_COMMPROCESSING ,
6280 set_flag(flags, FL_DELETEPENDING, query.
value(35).toBool());
6284 set_flag(flags, FL_REALLYEDITING, query.
value(39).toBool());
6289 if (inUseMap.contains(key))
6290 flags |= inUseMap[key];
6292 if (((flags & FL_COMMPROCESSING) != 0U) &&
6293 (isJobRunning.find(key) == isJobRunning.end()))
6295 flags &= ~FL_COMMPROCESSING;
6296 save_not_commflagged =
true;
6300 ((flags & FL_REALLYEDITING) != 0U) ||
6306 season = query.
value(51).toUInt();
6311 episode = query.
value(52).toUInt();
6314 uint totalepisodes = query.
value(53).toUInt();
6318 query.
value(55).toUInt(),
6319 query.
value(0).toString(),
6321 query.
value(1).toString(),
6323 query.
value(2).toString(),
6327 query.
value(48).toString(),
6328 query.
value(5).toString(),
6330 chanid, channum, chansign, channame, chanfilt,
6332 query.
value(11).toString(), query.
value(12).toString(),
6334 query.
value(14).toString(),
6338 query.
value(17).toString(), query.
value(18).toString(),
6339 query.
value(19).toString(),
6342 query.
value(16).toInt(),
6344 query.
value(20).toULongLong(),
6351 query.
value(23).toFloat(),
6353 query.
value(26).toUInt(),
6354 query.
value(49).toUInt(),
6355 query.
value(50).toUInt(),
6356 query.
value(27).toDate(),
6361 query.
value(29).toUInt(),
6366 query.
value(45).toUInt(),
6369 query.
value(42).toUInt(),
6370 query.
value(43).toUInt(),
6371 query.
value(44).toUInt(),
6372 query.
value(56).toString(),
6376 if (save_not_commflagged)
6385 std::vector<ProgramInfo> *list)
6387 nextRecordingStart = QDateTime();
6390 bool *conflicts = (hasConflicts) ? hasConflicts : &dummy;
6397 for (
auto *prog : progList)
6401 (nextRecordingStart.isNull() ||
6402 nextRecordingStart > prog->GetRecordingStartTime()))
6404 nextRecordingStart = prog->GetRecordingStartTime();
6412 for (
auto & prog : progList)
6416 (prog->GetRecordingStartTime() == nextRecordingStart))
6418 list->push_back(*prog);
6456 "SET filesize = :FILESIZE "
6457 "WHERE chanid = :CHANID AND "
6458 " starttime = :STARTTIME");
6459 query.
bindValue(
":FILESIZE", (quint64)fsize);
6490 uint64_t db_filesize = 0;
6497 "WHERE chanid = :CHANID AND "
6498 " starttime = :STARTTIME");
6502 db_filesize = query.
value(0).toULongLong();
6505 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"RI Filesize=0, DB Filesize=%1")
6519 if (now < startTime)
6523 int current = startTime.secsTo(now);
6524 int duration = startTime.secsTo(endTime);
6529 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 recorded percent %2/%3 = %4%")
6558 total = rate1000 * duration / 1000;
6570 LOG(VB_GUI, LOG_DEBUG,
6571 QString(
"%1 %2 no frame count. Please rebuild seek table for this video.")
6576 LOG(VB_GUI, LOG_DEBUG,
6577 QString(
"%1 %2 no frame count. Please rebuild seek table for this recording.")
6585 LOG(VB_GUI, LOG_DEBUG, QString(
"%1 %2 watched percent %3/%4 = %5%")
6603 return tr(
"Channel Number");
6605 return tr(
"CallSign");
6607 return tr(
"ProgramId");
6609 return tr(
"Unknown");