33 #define LOC QString("ProgramInfo(%1): ").arg(GetBasename())
48 #define DEFINE_FLAGS_NAMES
50 #undef DEFINE_FLAGS_NAMES
53 "SELECT r.title, r.subtitle, r.description, "
54 " r.season, r.episode, r.category, "
55 " r.chanid, c.channum, c.callsign, "
56 " c.name, c.outputfilters,r.recgroup, "
57 " r.playgroup, r.storagegroup, r.basename, "
58 " r.hostname, r.recpriority, r.seriesid, "
59 " r.programid, r.inetref, r.filesize, "
60 " r.progstart, r.progend, r.stars, "
61 " r.starttime, r.endtime, p.airdate+0, "
62 " r.originalairdate, r.lastmodified, r.recordid, "
63 " c.commmethod, r.commflagged, r.previouslyshown, "
64 " r.transcoder, r.transcoded, r.deletepending, "
65 " r.preserve, r.cutlist, r.autoexpire, "
66 " r.editing, r.bookmark, r.watched, "
67 " p.audioprop+0, p.videoprop+0, p.subtitletypes+0, "
68 " r.findid, rec.dupin, rec.dupmethod, "
69 " p.syndicatedepisodenumber, p.partnumber, p.parttotal, "
70 " p.season, p.episode, p.totalepisodes, "
71 " p.category_type, r.recordedid, r.inputname, "
72 " r.bookmarkupdate, r.lastplay "
74 "LEFT JOIN channel AS c "
75 "ON (r.chanid = c.chanid) "
76 "LEFT JOIN recordedprogram AS p "
77 "ON (r.chanid = p.chanid AND "
78 " r.progstart = p.starttime) "
79 "LEFT JOIN record AS rec "
80 "ON (r.recordid = rec.recordid) ";
82 static void set_flag(uint32_t &flags,
int flag_to_set,
bool is_set)
84 flags &= ~flag_to_set;
93 if (!url.startsWith(
"dvd:") && !url.startsWith(
"bd:"))
95 if(url.endsWith(
".img", Qt::CaseInsensitive) ||
96 url.endsWith(
".iso", Qt::CaseInsensitive))
101 result =
"bd:" + url;
105 result =
"dvd:" + url;
115 if (QDir(url +
"/BDMV").exists())
116 result =
"bd:" + url;
117 else if (QDir(url +
"/VIDEO_TS").exists())
118 result =
"dvd:" + url;
125 static const std::array<const QString,ProgramInfo::kNumCatTypes>
kCatName
126 {
"",
"movie",
"series",
"sports",
"tvshow" };
139 for (
size_t i = 1; i <
kCatName.size(); i++)
149 m_title(other.m_title),
150 m_sortTitle(other.m_sortTitle),
151 m_subtitle(other.m_subtitle),
152 m_sortSubtitle(other.m_sortSubtitle),
153 m_description(other.m_description),
154 m_season(other.m_season),
155 m_episode(other.m_episode),
156 m_totalEpisodes(other.m_totalEpisodes),
157 m_syndicatedEpisode(other.m_syndicatedEpisode),
158 m_category(other.m_category),
159 m_director(other.m_director),
161 m_recPriority(other.m_recPriority),
163 m_chanId(other.m_chanId),
164 m_chanStr(other.m_chanStr),
165 m_chanSign(other.m_chanSign),
166 m_chanName(other.m_chanName),
167 m_chanPlaybackFilters(other.m_chanPlaybackFilters),
169 m_recGroup(other.m_recGroup),
170 m_playGroup(other.m_playGroup),
172 m_pathname(other.m_pathname),
174 m_hostname(other.m_hostname),
175 m_storageGroup(other.m_storageGroup),
177 m_seriesId(other.m_seriesId),
178 m_programId(other.m_programId),
179 m_inetRef(other.m_inetRef),
180 m_catType(other.m_catType),
182 m_fileSize(other.m_fileSize),
184 m_startTs(other.m_startTs),
185 m_endTs(other.m_endTs),
186 m_recStartTs(other.m_recStartTs),
187 m_recEndTs(other.m_recEndTs),
189 m_stars(other.m_stars),
191 m_originalAirDate(other.m_originalAirDate),
192 m_lastModified(other.m_lastModified),
195 m_recPriority2(other.m_recPriority2),
196 m_recordId(other.m_recordId),
197 m_parentId(other.m_parentId),
199 m_sourceId(other.m_sourceId),
200 m_inputId(other.m_inputId),
202 m_findId(other.m_findId),
203 m_programFlags(other.m_programFlags),
204 m_videoProperties(other.m_videoProperties),
205 m_audioProperties(other.m_audioProperties),
206 m_subtitleProperties(other.m_subtitleProperties),
207 m_year(other.m_year),
208 m_partNumber(other.m_partNumber),
209 m_partTotal(other.m_partTotal),
211 m_recStatus(other.m_recStatus),
212 m_recType(other.m_recType),
213 m_dupIn(other.m_dupIn),
214 m_dupMethod(other.m_dupMethod),
216 m_recordedId(other.m_recordedId),
217 m_inputName(other.m_inputName),
218 m_bookmarkUpdate(other.m_bookmarkUpdate),
221 m_availableStatus(other.m_availableStatus),
222 m_spread(other.m_spread),
223 m_startCol(other.m_startCol),
226 m_positionMapDBReplacement(other.m_positionMapDBReplacement)
240 "SELECT chanid, starttime "
242 "WHERE recordedid = :RECORDEDID");
243 query.
bindValue(
":RECORDEDID", _recordedid);
253 LOG(VB_GENERAL, LOG_CRIT,
LOC +
254 QString(
"Failed to find recorded entry for %1.")
281 QString _sortSubtitle,
282 QString _description,
286 QString _syndicatedepisode,
293 QString _chanplaybackfilters,
298 const QString &_pathname,
301 QString _storagegroup,
314 QDateTime _recstartts,
322 QDate _originalAirDate,
323 QDateTime _lastmodified,
335 uint _audioproperties,
336 uint _videoproperties,
339 QDateTime _bookmarkupdate) :
340 m_title(
std::move(_title)),
341 m_sortTitle(
std::move(_sortTitle)),
342 m_subtitle(
std::move(_subtitle)),
343 m_sortSubtitle(
std::move(_sortSubtitle)),
344 m_description(
std::move(_description)),
347 m_totalEpisodes(_totalepisodes),
348 m_syndicatedEpisode(
std::move(_syndicatedepisode)),
349 m_category(
std::move(_category)),
351 m_recPriority(_recpriority),
354 m_chanStr(
std::move(_channum)),
355 m_chanSign(
std::move(_chansign)),
356 m_chanName(
std::move(_channame)),
357 m_chanPlaybackFilters(
std::move(_chanplaybackfilters)),
359 m_recGroup(
std::move(_recgroup)),
360 m_playGroup(
std::move(_playgroup)),
362 m_pathname(_pathname),
364 m_hostname(
std::move(_hostname)),
365 m_storageGroup(
std::move(_storagegroup)),
367 m_seriesId(
std::move(_seriesid)),
368 m_programId(
std::move(_programid)),
369 m_inetRef(
std::move(_inetref)),
372 m_fileSize(_filesize),
374 m_startTs(
std::move(_startts)),
375 m_endTs(
std::move(_endts)),
376 m_recStartTs(
std::move(_recstartts)),
377 m_recEndTs(
std::move(_recendts)),
379 m_stars(
std::clamp(_stars, 0.0F, 1.0F)),
381 m_originalAirDate(_originalAirDate),
382 m_lastModified(
std::move(_lastmodified)),
385 m_recordId(_recordid),
388 m_programFlags(_programflags),
389 m_videoProperties(_videoproperties),
390 m_audioProperties(_audioproperties),
391 m_subtitleProperties(_subtitleType),
393 m_partNumber(_partnumber),
394 m_partTotal(_parttotal),
396 m_recStatus(_recstatus),
398 m_dupMethod(_dupmethod),
400 m_recordedId(_recordedid),
401 m_inputName(
std::move(_inputname)),
402 m_bookmarkUpdate(
std::move(_bookmarkupdate))
418 QString _sortSubtitle,
419 QString _description,
435 QDateTime _recstartts,
447 m_title(
std::move(_title)),
448 m_sortTitle(
std::move(_sortTitle)),
449 m_subtitle(
std::move(_subtitle)),
450 m_sortSubtitle(
std::move(_sortSubtitle)),
451 m_description(
std::move(_description)),
454 m_category(
std::move(_category)),
457 m_chanStr(
std::move(_channum)),
458 m_chanSign(
std::move(_chansign)),
459 m_chanName(
std::move(_channame)),
461 m_seriesId(
std::move(_seriesid)),
462 m_programId(
std::move(_programid)),
463 m_inetRef(
std::move(_inetref)),
465 m_startTs(
std::move(_startts)),
466 m_endTs(
std::move(_endts)),
467 m_recStartTs(
std::move(_recstartts)),
468 m_recEndTs(
std::move(_recendts)),
470 m_lastModified(m_startTs),
473 m_recordId(_recordid),
476 m_programFlags((duplicate) ? FL_DUPLICATE : 0),
478 m_recStatus(_recstatus),
493 QString _sortSubtitle,
494 QString _description,
495 QString _syndicatedepisode,
502 QString _chanplaybackfilters,
506 QDateTime _recstartts,
518 QDate _originalAirDate,
527 uint _videoproperties,
528 uint _audioproperties,
536 m_title(
std::move(_title)),
537 m_sortTitle(
std::move(_sortTitle)),
538 m_subtitle(
std::move(_subtitle)),
539 m_sortSubtitle(
std::move(_sortSubtitle)),
540 m_description(
std::move(_description)),
543 m_totalEpisodes(_totalepisodes),
544 m_syndicatedEpisode(
std::move(_syndicatedepisode)),
545 m_category(
std::move(_category)),
548 m_chanStr(
std::move(_channum)),
549 m_chanSign(
std::move(_chansign)),
550 m_chanName(
std::move(_channame)),
551 m_chanPlaybackFilters(
std::move(_chanplaybackfilters)),
553 m_seriesId(
std::move(_seriesid)),
554 m_programId(
std::move(_programid)),
557 m_startTs(
std::move(_startts)),
558 m_endTs(
std::move(_endts)),
559 m_recStartTs(
std::move(_recstartts)),
560 m_recEndTs(
std::move(_recendts)),
562 m_stars(
std::clamp(_stars, 0.0F, 1.0F)),
564 m_originalAirDate(_originalAirDate),
565 m_lastModified(m_startTs),
566 m_lastInUseTime(m_startTs.addSecs(-kLastInUseOffset)),
568 m_recordId(_recordid),
571 m_videoProperties(_videoproperties),
572 m_audioProperties(_audioproperties),
573 m_subtitleProperties(_subtitleType),
575 m_partNumber(_partnumber),
576 m_partTotal(_parttotal),
578 m_recStatus(_recstatus),
587 for (
auto *it : schedList)
637 QString _sortSubtitle,
638 QString _description,
648 QString _chanplaybackfilters,
655 QDateTime _recstartts,
661 QString _inputname) :
662 m_title(
std::move(_title)),
663 m_sortTitle(
std::move(_sortTitle)),
664 m_subtitle(
std::move(_subtitle)),
665 m_sortSubtitle(
std::move(_sortSubtitle)),
666 m_description(
std::move(_description)),
669 m_totalEpisodes(_totalepisodes),
670 m_category(
std::move(_category)),
673 m_chanStr(
std::move(_channum)),
674 m_chanSign(
std::move(_chansign)),
675 m_chanName(
std::move(_channame)),
676 m_chanPlaybackFilters(
std::move(_chanplaybackfilters)),
678 m_recGroup(
std::move(_recgroup)),
679 m_playGroup(
std::move(_playgroup)),
681 m_seriesId(
std::move(_seriesid)),
682 m_programId(
std::move(_programid)),
683 m_inetRef(
std::move(_inetref)),
685 m_startTs(
std::move(_startts)),
686 m_endTs(
std::move(_endts)),
687 m_recStartTs(
std::move(_recstartts)),
688 m_recEndTs(
std::move(_recendts)),
691 m_lastInUseTime(m_lastModified.addSecs(-kLastInUseOffset)),
693 m_inputName(
std::move(_inputname))
704 if (_pathname.isEmpty())
710 QDateTime _recstartts;
724 QString basename = _pathname.section(
'/', -1);
725 if (_pathname == basename)
726 SetPathname(QDir::currentPath() +
'/' + _pathname);
727 else if (_pathname.contains(
"./") && !_pathname.contains(
":"))
728 SetPathname(QFileInfo(_pathname).absoluteFilePath());
738 const QString &_plot,
739 const QString &_title,
740 const QString &_sortTitle,
741 const QString &_subtitle,
742 const QString &_sortSubtitle,
743 const QString &_director,
744 int _season,
int _episode,
745 const QString &_inetref,
746 std::chrono::minutes length_in_minutes,
748 const QString &_programid)
765 int64_t minutes = length_in_minutes.count();
771 QString pn = _pathname;
772 if (!_pathname.startsWith(
"myth://"))
783 const QDateTime &_startts,
784 const QDateTime &_endts)
790 "SELECT chanid, channum, callsign, name, outputfilters, commmethod "
792 "WHERE chanid=:CHANID");
811 QString channelFormat =
819 QString(
"%1 (%2)").arg(
m_title, QObject::tr(
"Manual Record"));
837 bool ignore_non_serialized_data)
865 if (!ignore_non_serialized_data || !is_same ||
921 if (!ignore_non_serialized_data)
1027 if (a.isEmpty() and (b ==
"Default"))
1029 if ((a ==
"Default") and b.isEmpty())
1169 uint chanid,
const QDateTime &recstartts)
1171 return QString(
"%1_%2").arg(chanid).arg(recstartts.toString(
Qt::ISODate));
1178 uint &chanid, QDateTime &recstartts)
1180 QStringList keyParts = uniquekey.split(
'_');
1181 if (keyParts.size() != 2)
1183 chanid = keyParts[0].toUInt();
1185 return (chanid != 0U) && recstartts.isValid();
1189 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1191 QString basename = pathname.section(
'/', -1);
1192 if (basename.isEmpty())
1195 QStringList lr = basename.split(
"_");
1198 chanid = lr[0].toUInt();
1199 QStringList ts = lr[1].split(
".");
1200 if (chanid && !ts.empty())
1203 return recstartts.isValid();
1211 const QString &pathname,
uint &chanid, QDateTime &recstartts)
1213 QString basename = pathname.section(
'/', -1);
1214 if (basename.isEmpty())
1219 "SELECT chanid, starttime "
1221 "WHERE basename = :BASENAME");
1225 chanid = query.
value(0).toUInt();
1236 QString basename = pathname.section(
'/', -1);
1237 if (basename.isEmpty())
1242 "SELECT recordedid "
1244 "WHERE basename = :BASENAME");
1248 recordedid = query.
value(0).toUInt();
1257 return QString::number(x.toSecsSinceEpoch());
1272 list << QString::number(
m_season );
1296 list << QString::number(
m_dupIn);
1308 list << QString(
"%1").arg(
m_stars);
1318 list << QString::number(
m_year);
1332 #define NEXT_STR() do { if (it == listend) \
1334 LOG(VB_GENERAL, LOG_ERR, listerror); \
1338 ts = *it++; } while (false)
1349 if (str.isEmpty() || (str ==
"0000-00-00"))
1367 const QStringList::const_iterator& listend)
1369 QString listerror =
LOC +
"FromStringList, not enough items in list.";
1433 if (!origChanid || !origRecstartts.isValid() ||
1448 template <
typename T>
1453 return propNames[0];
1456 for (
uint i = 0; i <
sizeof(T)*8 - 1; ++i)
1459 if ((props & bit) == 0)
1461 if (propNames.contains(bit))
1463 result += propNames[bit];
1466 QString
tmp = QString(
"0x%1").arg(bit,
sizeof(T)*2,16,QChar(
'0'));
1467 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown name for %1 flag 0x%2.")
1471 return result.join(
'|');
1474 template <
typename T>
1476 const QString& props)
1478 if (props.isEmpty())
1483 QStringList names = props.split(
'|');
1484 for (
const auto& n : names )
1486 uint bit = propNames.key(n, 0);
1489 LOG(VB_GENERAL, LOG_ERR, QString(
"Unknown flag for %1 %2")
1545 uint date_format)
const
1550 QString channelFormat =
1552 QString longChannelFormat =
1562 QString tempSubTitle =
m_title;
1566 tempSubTitle = QString(
"%1 - \"%2\"")
1568 tempSortSubtitle = QString(
"%1 - \"%2\"")
1572 progMap[
"titlesubtitle"] = tempSubTitle;
1573 progMap[
"sorttitlesubtitle"] = tempSortSubtitle;
1575 progMap[
"description"] = progMap[
"description0"] =
m_description;
1582 progMap[
"s00e00"] = QString(
"s%1e%2")
1585 progMap[
"00x00"] = QString(
"%1x%2")
1591 progMap[
"season"] = progMap[
"episode"] =
"";
1592 progMap[
"totalepisodes"] =
"";
1593 progMap[
"s00e00"] = progMap[
"00x00"] =
"";
1601 progMap[
"commfree"] = (
m_programFlags & FL_CHANCOMMFREE) ?
"1" :
"0";
1605 progMap[
"starttime"] =
"";
1606 progMap[
"startdate"] =
"";
1607 progMap[
"endtime"] =
"";
1608 progMap[
"enddate"] =
"";
1609 progMap[
"recstarttime"] =
"";
1610 progMap[
"recstartdate"] =
"";
1611 progMap[
"recendtime"] =
"";
1612 progMap[
"recenddate"] =
"";
1616 progMap[
"startdate"] =
"";
1617 progMap[
"recstartdate"] =
"";
1621 progMap[
"startdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1622 progMap[
"recstartdate"] =
m_startTs.toLocalTime().toString(
"yyyy");
1629 progMap[
"startdate"] =
1639 progMap[
"startts"] = QString::number(
m_startTs.toSecsSinceEpoch());
1640 progMap[
"endts"] = QString::number(
m_endTs.toSecsSinceEpoch());
1641 if (timeNow.toLocalTime().date().year() !=
1643 progMap[
"startyear"] =
m_startTs.toLocalTime().toString(
"yyyy");
1644 if (timeNow.toLocalTime().date().year() !=
1645 m_endTs.toLocalTime().date().year())
1646 progMap[
"endyear"] =
m_endTs.toLocalTime().toString(
"yyyy");
1650 progMap[
"timedate"] =
1654 progMap[
"shorttimedate"] =
1658 progMap[
"starttimedate"] =
1661 progMap[
"shortstarttimedate"] =
1665 progMap[
"lastmodifieddate"] =
1667 progMap[
"lastmodified"] =
1674 progMap[
"chanid"] = QString::number(
m_chanId);
1677 progMap[
"longchannel"] =
ChannelText(longChannelFormat);
1679 QString tmpSize = locale.toString(
m_fileSize * (1.0 / (1024.0 * 1024.0 * 1024.0)),
'f', 2);
1680 progMap[
"filesize_str"] = QObject::tr(
"%1 GB",
"GigaBytes").arg(tmpSize);
1682 progMap[
"filesize"] = locale.toString((quint64)
m_fileSize);
1685 int minutes = seconds / 60;
1687 QString min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1689 progMap[
"lenmins"] = min_str;
1690 int hours = minutes / 60;
1691 minutes = minutes % 60;
1693 progMap[
"lentime"] = min_str;
1694 if (hours > 0 && minutes > 0)
1696 min_str = QObject::tr(
"%n minute(s)",
"",minutes);
1697 progMap[
"lentime"] = QString(
"%1 %2")
1698 .arg(QObject::tr(
"%n hour(s)",
"", hours), min_str);
1702 progMap[
"lentime"] = QObject::tr(
"%n hour(s)",
"", hours);
1705 progMap[
"recordedpercent"] =
1708 progMap[
"watchedpercent"] =
1716 QString tmp_rec = progMap[
"rectype"];
1734 tmp_rec += QObject::tr(
"Re-Record");
1741 progMap[
"rectypestatus"] = tmp_rec;
1751 progMap[
"recordinggroup"] = (
m_recGroup ==
"Default")
1756 progMap[
"storagegroup"] = QObject::tr(
"Default");
1762 progMap[
"storagegroup"] = QObject::tr(
m_storageGroup.toUtf8().constData());
1786 progMap[
"repeat"] = QString(
"(%1) ").arg(QObject::tr(
"Repeat"));
1787 progMap[
"longrepeat"] = progMap[
"repeat"];
1790 progMap[
"longrepeat"] = QString(
"(%1 %2) ")
1791 .arg(QObject::tr(
"Repeat"),
1799 progMap[
"repeat"] =
"";
1800 progMap[
"longrepeat"] =
"";
1808 progMap[
"year"] =
m_year > 1895 ? QString::number(
m_year) :
"";
1813 QString star_str = (
m_stars != 0.0F) ?
1814 QObject::tr(
"%n star(s)",
"",
GetStars(star_range)) :
"";
1815 progMap[
"stars"] = star_str;
1816 progMap[
"numstars"] = QString::number(
GetStars(star_range));
1819 progMap[
"yearstars"] = QString(
"(%1, %2)").arg(
m_year).arg(star_str);
1821 progMap[
"yearstars"] = QString(
"(%1)").arg(star_str);
1823 progMap[
"yearstars"] = QString(
"(%1)").arg(
m_year);
1825 progMap[
"yearstars"] =
"";
1830 progMap[
"originalairdate"] =
"";
1831 progMap[
"shortoriginalairdate"] =
"";
1845 QString mediaTypeString;
1849 mediaType =
"video";
1850 mediaTypeString = QObject::tr(
"Video");
1854 mediaTypeString = QObject::tr(
"DVD");
1857 mediaType =
"httpstream";
1858 mediaTypeString = QObject::tr(
"HTTP Streaming");
1861 mediaType =
"rtspstream";
1862 mediaTypeString = QObject::tr(
"RTSP Streaming");
1865 mediaType =
"bluraydisc";
1866 mediaTypeString = QObject::tr(
"Blu-ray Disc");
1870 mediaType =
"recording";
1871 mediaTypeString = QObject::tr(
"Recording",
1872 "Recorded file, object not action");
1874 progMap[
"mediatype"] = mediaType;
1875 progMap[
"mediatypestring"] = mediaTypeString;
1883 return (recsecs > 0s) ? recsecs : std::max(duration, 0s);
1895 uint64_t last_frame = 0;
1904 if (!posMap.empty())
1906 frm_pos_map_t::const_iterator it = posMap.constEnd();
1908 last_frame = it.key();
1915 if (qsizetype idx =
m_inputName.indexOf(
'/'); idx >= 0)
1942 str +=
" startts(" +
1945 ") recendts(" +
m_recEndTs.toString() +
")\n";
1946 str +=
" title(" +
m_title +
")";
1954 QString(
"%1%2%3%4").arg(sep, grp,
m_subtitle, grp) :
1959 str = QString(
"%1 at %2")
1963 str = QString(
"%1 @ %2")
1986 const uint _chanid,
const QDateTime &_recstartts)
1988 if (!_chanid || !_recstartts.isValid())
1997 "WHERE r.chanid = :CHANID AND "
1998 " r.starttime = :RECSTARTTS");
2000 query.
bindValue(
":RECSTARTTS", _recstartts);
2053 if (!query.
value(7).toString().isEmpty())
2067 QString new_basename = query.
value(14).toString();
2068 if ((
GetBasename() != new_basename) || !is_reload)
2072 LOG(VB_FILE, LOG_INFO,
LOC +
2073 QString(
"Updated pathname '%1':'%2' -> '%3'")
2096 m_stars = std::clamp((
float)query.
value(23).toDouble(), 0.0F, 1.0F);
2209 if (index == oindex && (index < 0 ||
2268 if (index == oindex && (index < 0 ||
2363 QMap<QString, int> authMap;
2364 std::array<QString,3> tables {
"program",
"recorded",
"oldrecorded" };
2367 for (
const QString& table : tables)
2370 "SELECT DISTINCT LEFT(programid, LOCATE('/', programid)) "
2371 "FROM %1 WHERE programid <> ''").arg(table));
2376 while (query.
next())
2377 authMap[query.
value(0).toString()] = 1;
2381 int numAuths = authMap.count();
2382 LOG(VB_GENERAL, LOG_INFO,
2383 QString(
"Found %1 distinct programid authorities").arg(numAuths));
2396 QString retval = QString(
"%1_%2.%3")
2397 .arg(QString::number(
m_chanId), starts, ext);
2403 uint chanid,
const QString &pathname,
bool use_remote)
2405 QString fn_lower = pathname.toLower();
2409 else if (fn_lower.startsWith(
"http:"))
2411 else if (fn_lower.startsWith(
"rtsp:"))
2417 if (fn_lower.startsWith(
"dvd:"))
2421 else if (fn_lower.startsWith(
"bd:"))
2425 else if (use_remote && fn_lower.startsWith(
"myth://"))
2427 QString tmpFileDVD = pathname +
"/VIDEO_TS";
2428 QString tmpFileBD = pathname +
"/BDMV";
2456 LOG(VB_GUI, LOG_INFO,
2471 query.
prepare(
"UPDATE recorded "
2472 "SET basename = :BASENAME "
2473 "WHERE recordedid = :RECORDEDID;");
2483 query.
prepare(
"UPDATE recordedfile "
2484 "SET basename = :BASENAME "
2485 "WHERE recordedid = :RECORDEDID;");
2517 "FROM recordedfile "
2518 "WHERE recordedid = :RECORDEDID;");
2525 else if (query.
next())
2527 return query.
value(0).toString();
2531 LOG(VB_GENERAL, LOG_INFO,
2532 QString(
"QueryBasename found no entry for recording ID %1")
2547 bool checkMaster,
bool forceCheckLocal)
2554 if (basename.isEmpty())
2563 if (!fullpath.startsWith(
"myth://", Qt::CaseInsensitive) || !checklocal)
2566 QUrl url = QUrl(fullpath);
2567 QString path = url.path();
2568 QString host = url.toString(QUrl::RemovePath).mid(7);
2569 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2570 QStringList list = host.split(
":", QString::SkipEmptyParts);
2572 QStringList list = host.split(
":", Qt::SkipEmptyParts);
2577 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2578 list = host.split(
"@", QString::SkipEmptyParts);
2580 list = host.split(
"@", Qt::SkipEmptyParts);
2583 if (!list.empty() && list.size() < 3)
2585 host = list.size() == 1 ? list[0] : list[1];
2586 group = list.size() == 1 ? QString() : list[0];
2589 if (!local.isEmpty() && sg.
FileExists(local))
2602 LOG(VB_FILE, LOG_DEBUG,
LOC +
2603 QString(
"GetPlaybackURL: CHECKING SG : %1 : ").arg(tmpURL));
2605 tmpURL = sgroup.
FindFile(basename);
2607 if (!tmpURL.isEmpty())
2609 LOG(VB_FILE, LOG_INFO,
LOC +
2610 QString(
"GetPlaybackURL: File is local: '%1'") .arg(tmpURL));
2615 LOG(VB_GENERAL, LOG_ERR,
LOC +
2616 QString(
"GetPlaybackURL: '%1' should be local, but it can "
2617 "not be found.").arg(basename));
2620 return QString(
"GetPlaybackURL/UNABLE/TO/FIND/LOCAL/FILE/ON/%1/%2")
2626 if ((checkMaster) &&
2634 LOG(VB_FILE, LOG_INFO,
LOC +
2635 QString(
"GetPlaybackURL: Found @ '%1'").arg(tmpURL));
2644 LOG(VB_FILE, LOG_INFO,
LOC +
2645 QString(
"GetPlaybackURL: Using default of: '%1'") .arg(tmpURL));
2659 query.
prepare(
"SELECT mplexid FROM channel "
2660 "WHERE chanid = :CHANID");
2665 else if (query.
next())
2666 ret = query.
value(0).toUInt();
2669 ret = (32767 == ret) ? 0 : ret;
2681 bool is_valid = (frame > 0);
2702 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2703 " bookmark = :BOOKMARKFLAG "
2704 "WHERE recordedid = :RECORDEDID");
2706 query.
bindValue(
":BOOKMARKFLAG", bookmarked);
2718 bool isValid = frame > 0;
2743 "SET bookmarkupdate = CURRENT_TIMESTAMP, "
2744 " lastplay = :LASTPLAYFLAG "
2745 "WHERE recordedid = :RECORDEDID");
2747 query.
bindValue(
":LASTPLAYFLAG", hasLastPlay);
2778 "SELECT bookmarkupdate "
2780 "WHERE chanid = :CHANID AND"
2781 " starttime = :STARTTIME");
2789 else if (query.
next())
2809 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2819 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2836 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2853 return (bookmarkmap.isEmpty()) ? 0 : bookmarkmap.begin().key();
2861 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using last position @ %1").arg(start));
2865 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using bookmark @ %1").arg(start));
2870 LOG(VB_PLAYBACK, LOG_INFO,
"Ignoring progstart as cutlist exists");
2874 LOG(VB_PLAYBACK, LOG_INFO, QString(
"Using progstart @ %1").arg(start));
2878 LOG(VB_PLAYBACK, LOG_INFO,
"Using file start");
2889 const QString &serialid)
const
2891 QStringList fields = QStringList();
2896 query.
prepare(
" SELECT dvdstate, title, framenum, audionum, subtitlenum "
2897 " FROM dvdbookmark "
2898 " WHERE serialid = :SERIALID ");
2903 QString dvdstate = query.
value(0).toString();
2905 if (!dvdstate.isEmpty())
2907 fields.append(dvdstate);
2912 for(
int i = 1; i < 5; i++)
2913 fields.append(query.
value(i).toString());
2923 QStringList::const_iterator it = fields.begin();
2926 QString serialid = *(it);
2927 QString name = *(++it);
2929 if( fields.count() == 3 )
2932 QString state = *(++it);
2934 query.
prepare(
"INSERT IGNORE INTO dvdbookmark "
2936 " VALUES ( :SERIALID, :NAME );");
2943 query.
prepare(
" UPDATE dvdbookmark "
2944 " SET dvdstate = :STATE , "
2945 " timestamp = NOW() "
2946 " WHERE serialid = :SERIALID");
2953 query.
prepare(
"DELETE FROM dvdbookmark "
2954 "WHERE serialid = :SERIALID");
2967 QStringList fields = QStringList();
2972 query.
prepare(
" SELECT bdstate FROM bdbookmark "
2973 " WHERE serialid = :SERIALID ");
2977 fields.append(query.
value(0).toString());
2985 QStringList::const_iterator it = fields.begin();
2988 QString serialid = *(it);
2989 QString name = *(++it);
2991 if( fields.count() == 3 )
2994 QString state = *(++it);
2996 query.
prepare(
"INSERT IGNORE INTO bdbookmark "
2998 " VALUES ( :SERIALID, :NAME );");
3005 query.
prepare(
" UPDATE bdbookmark "
3006 " SET bdstate = :STATE , "
3007 " timestamp = NOW() "
3008 " WHERE serialid = :SERIALID");
3015 query.
prepare(
"DELETE FROM bdbookmark "
3016 "WHERE serialid = :SERIALID");
3035 query.
prepare(
" SELECT category_type "
3036 " FROM recordedprogram "
3037 " WHERE chanid = :CHANID "
3038 " AND starttime = :STARTTIME;");
3058 query.
prepare(
"UPDATE recorded"
3059 " SET watched = :WATCHEDFLAG"
3060 " WHERE chanid = :CHANID"
3061 " AND starttime = :STARTTIME ;");
3064 query.
bindValue(
":WATCHEDFLAG", watched);
3076 if (url.startsWith(
"myth://"))
3078 url = QUrl(url).path();
3083 query.
prepare(
"UPDATE videometadata"
3084 " SET watched = :WATCHEDFLAG"
3085 " WHERE title = :TITLE"
3086 " AND subtitle = :SUBTITLE"
3087 " AND filename = :FILENAME ;");
3091 query.
bindValue(
":WATCHEDFLAG", watched);
3110 query.
prepare(
"SELECT editing FROM recorded"
3111 " WHERE chanid = :CHANID"
3112 " AND starttime = :STARTTIME ;");
3117 editing = query.
value(0).toBool();
3134 query.
prepare(
"UPDATE recorded"
3135 " SET editing = :EDIT"
3136 " WHERE chanid = :CHANID"
3137 " AND starttime = :STARTTIME ;");
3159 query.
prepare(
"UPDATE recorded"
3160 " SET deletepending = :DELETEFLAG, "
3162 " WHERE chanid = :CHANID"
3163 " AND starttime = :STARTTIME ;");
3166 query.
bindValue(
":DELETEFLAG", deleteFlag);
3191 query.
prepare(
"SELECT hostname, recusage FROM inuseprograms "
3192 " WHERE chanid = :CHANID"
3193 " AND starttime = :STARTTIME "
3194 " AND lastupdatetime > :ONEHOURAGO ;");
3197 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
3200 if (query.
exec() && query.
size() > 0)
3204 while (query.
next())
3206 usageStr = QObject::tr(
"Unknown");
3207 recusage = query.
value(1).toString();
3210 usageStr = QObject::tr(
"Playing");
3212 usageStr = QObject::tr(
"PIP");
3214 usageStr = QObject::tr(
"PBP");
3217 usageStr = QObject::tr(
"Recording");
3219 usageStr = QObject::tr(
"File transfer");
3221 usageStr = QObject::tr(
"Delete");
3223 usageStr = QObject::tr(
"Commercial Detection");
3225 usageStr = QObject::tr(
"Transcoding");
3227 usageStr = QObject::tr(
"Preview Generation");
3229 usageStr = QObject::tr(
"User Job");
3231 byWho.push_back(recusage);
3232 byWho.push_back(query.
value(0).toString());
3233 byWho.push_back(query.
value(0).toString() +
" (" + usageStr +
")");
3251 for (
int i = 0; i+2 < users.size(); i+=3)
3252 byWho += users[i+2] +
"\n";
3279 for (
uint i = 0; (i+2 < (
uint)byWho.size()) && ok; i+=3)
3289 (one_playback_allowed && (play_cnt <= 1)));
3291 ok = ok && (ft_cnt == jq_cnt);
3302 query.
prepare(
"SELECT transcoded FROM recorded"
3303 " WHERE chanid = :CHANID"
3304 " AND starttime = :STARTTIME ;");
3324 "SET transcoded = :VALUE "
3325 "WHERE chanid = :CHANID AND"
3326 " starttime = :STARTTIME");
3345 query.
prepare(
"UPDATE recorded"
3346 " SET commflagged = :FLAG"
3347 " WHERE chanid = :CHANID"
3348 " AND starttime = :STARTTIME ;");
3371 query.
prepare(
"UPDATE recorded"
3372 " SET preserve = :PRESERVE"
3373 " WHERE chanid = :CHANID"
3374 " AND starttime = :STARTTIME ;");
3375 query.
bindValue(
":PRESERVE", preserveEpisode);
3398 query.
prepare(
"UPDATE recorded"
3399 " SET autoexpire = :AUTOEXPIRE"
3400 " WHERE chanid = :CHANID"
3401 " AND starttime = :STARTTIME ;");
3408 else if (updateDelete)
3427 auto delay_secs = std::chrono::seconds(
m_recStartTs.secsTo(timeNow));
3428 auto delay = duration_cast<std::chrono::hours>(delay_secs);
3429 delay = std::clamp(delay, 1h, 200h);
3431 query.
prepare(
"UPDATE record SET last_delete = :TIME, "
3432 "avg_delay = (avg_delay * 3 + :DELAY) / 4 "
3433 "WHERE recordid = :RECORDID");
3435 query.
bindValue(
":DELAY",
static_cast<qint64
>(delay.count()));
3439 query.
prepare(
"UPDATE record SET last_delete = NULL "
3440 "WHERE recordid = :RECORDID");
3453 query.
prepare(
"SELECT autoexpire FROM recorded"
3454 " WHERE chanid = :CHANID"
3455 " AND starttime = :STARTTIME ;");
3476 for (
auto i = autosaveMap.constBegin(); i != autosaveMap.constEnd(); ++i)
3478 uint64_t frame = i.key();
3484 delMap[frame] =
mark;
3494 return !delMap.isEmpty();
3510 for (
auto i = delMap.constBegin(); i != delMap.constEnd(); ++i)
3512 uint64_t frame = i.key();
3521 tmpDelMap[frame] =
mark;
3530 query.
prepare(
"UPDATE recorded"
3531 " SET cutlist = :CUTLIST"
3532 " WHERE chanid = :CHANID"
3533 " AND starttime = :STARTTIME ;");
3535 query.
bindValue(
":CUTLIST", delMap.isEmpty() ? 0 : 1);
3564 comp += QString(
" AND mark >= %1 ").arg(min_frame);
3567 comp += QString(
" AND mark <= %1 ").arg(max_frame);
3570 comp += QString(
" AND type = :TYPE ");
3574 query.
prepare(
"DELETE FROM filemarkup"
3575 " WHERE filename = :PATH "
3581 query.
prepare(
"DELETE FROM recordedmarkup"
3582 " WHERE chanid = :CHANID"
3583 " AND STARTTIME = :STARTTIME"
3600 int64_t min_frame, int64_t max_frame)
const
3612 query.
prepare(
"SELECT starttime FROM recorded"
3613 " WHERE chanid = :CHANID"
3614 " AND starttime = :STARTTIME ;");
3629 frm_dir_map_t::const_iterator it;
3630 for (it =
marks.begin(); it !=
marks.end(); ++it)
3632 uint64_t frame = it.key();
3634 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3637 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3644 query.
prepare(
"INSERT INTO filemarkup (filename, mark, type)"
3645 " VALUES ( :PATH , :MARK , :TYPE );");
3650 query.
prepare(
"INSERT INTO recordedmarkup"
3651 " (chanid, starttime, mark, type)"
3652 " VALUES ( :CHANID , :STARTTIME , :MARK , :TYPE );");
3656 query.
bindValue(
":MARK", (quint64)frame);
3682 const QString &video_pathname,
3691 query.
prepare(
"SELECT mark, type "
3693 "WHERE filename = :PATH AND "
3696 query.
bindValue(
":PATH", video_pathname);
3705 while (query.
next())
3713 uint chanid,
const QDateTime &recstartts,
3721 query.
prepare(
"SELECT mark, type "
3722 "FROM recordedmarkup "
3723 "WHERE chanid = :CHANID AND "
3724 " starttime = :STARTTIME AND"
3728 query.
bindValue(
":STARTTIME", recstartts);
3737 while (query.
next())
3751 return flagMap.contains(0);
3779 query.
prepare(
"SELECT mark, `offset` FROM filemarkup"
3780 " WHERE filename = :PATH"
3781 " AND type = :TYPE ;");
3786 query.
prepare(
"SELECT mark, `offset` FROM recordedseek"
3787 " WHERE chanid = :CHANID"
3788 " AND starttime = :STARTTIME"
3789 " AND type = :TYPE ;");
3805 while (query.
next())
3806 posMap[query.
value(0).toULongLong()] = query.
value(1).toULongLong();
3822 query.
prepare(
"DELETE FROM filemarkup"
3823 " WHERE filename = :PATH"
3824 " AND type = :TYPE ;");
3829 query.
prepare(
"DELETE FROM recordedseek"
3830 " WHERE chanid = :CHANID"
3831 " AND starttime = :STARTTIME"
3832 " AND type = :TYPE ;");
3849 int64_t min_frame, int64_t max_frame)
const
3855 if ((min_frame >= 0) || (max_frame >= 0))
3863 uint64_t frame = it.key();
3864 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3866 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3868 new_map.insert(it.key(), *it);
3878 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
3880 uint64_t frame = it.key();
3881 if ((min_frame >= 0) && (frame >= (uint64_t)min_frame))
3883 if ((min_frame >= 0) && (frame <= (uint64_t)max_frame))
3887 .insert(frame, *it);
3897 comp +=
" AND mark >= :MIN_FRAME ";
3899 comp +=
" AND mark <= :MAX_FRAME ";
3906 query.
prepare(
"DELETE FROM filemarkup"
3907 " WHERE filename = :PATH"
3914 query.
prepare(
"DELETE FROM recordedseek"
3915 " WHERE chanid = :CHANID"
3916 " AND starttime = :STARTTIME"
3929 query.
bindValue(
":MIN_FRAME", (quint64)min_frame);
3931 query.
bindValue(
":MAX_FRAME", (quint64)max_frame);
3936 if (posMap.isEmpty())
3940 QStringList q(
"INSERT INTO ");
3944 q <<
"filemarkup (filename, type, mark, `offset`)";
3945 qfields = QString(
"('%1',%2,") .
3952 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
3953 qfields = QString(
"(%1,'%2',%3,") .
3960 bool add_comma =
false;
3961 frm_pos_map_t::iterator it;
3962 for (it = posMap.begin(); it != posMap.end(); ++it)
3964 uint64_t frame = it.key();
3966 if ((min_frame >= 0) && (frame < (uint64_t)min_frame))
3969 if ((max_frame >= 0) && (frame > (uint64_t)max_frame))
3972 uint64_t offset = *it;
3982 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
3994 if (posMap.isEmpty())
4001 for (
auto it = posMap.cbegin(); it != posMap.cend(); ++it)
4008 QStringList q(
"INSERT INTO ");
4012 q <<
"filemarkup (filename, type, mark, `offset`)";
4013 qfields = QString(
"('%1',%2,") .
4020 q <<
"recordedseek (chanid, starttime, type, mark, `offset`)";
4021 qfields = QString(
"(%1,'%2',%3,") .
4032 bool add_comma =
false;
4033 frm_pos_map_t::iterator it;
4034 for (it = posMap.begin(); it != posMap.end(); ++it)
4036 uint64_t frame = it.key();
4037 uint64_t offset = *it;
4047 q << qfields << QString(
"%1,%2)").arg(frame).arg(offset);
4059 "SELECT mark, `offset` FROM filemarkup"
4060 " WHERE filename = :PATH"
4062 " AND mark >= :QUERY_ARG"
4063 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4065 "SELECT mark, `offset` FROM filemarkup"
4066 " WHERE filename = :PATH"
4068 " AND mark <= :QUERY_ARG"
4069 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4071 "SELECT mark, `offset` FROM recordedseek"
4072 " WHERE chanid = :CHANID"
4073 " AND starttime = :STARTTIME"
4075 " AND mark >= :QUERY_ARG"
4076 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4078 "SELECT mark, `offset` FROM recordedseek"
4079 " WHERE chanid = :CHANID"
4080 " AND starttime = :STARTTIME"
4082 " AND mark <= :QUERY_ARG"
4083 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4085 "SELECT `offset`,mark FROM filemarkup"
4086 " WHERE filename = :PATH"
4088 " AND `offset` >= :QUERY_ARG"
4089 " ORDER BY filename ASC, type ASC, mark ASC LIMIT 1;";
4091 "SELECT `offset`,mark FROM filemarkup"
4092 " WHERE filename = :PATH"
4094 " AND `offset` <= :QUERY_ARG"
4095 " ORDER BY filename DESC, type DESC, mark DESC LIMIT 1;";
4097 "SELECT `offset`,mark FROM recordedseek"
4098 " WHERE chanid = :CHANID"
4099 " AND starttime = :STARTTIME"
4101 " AND `offset` >= :QUERY_ARG"
4102 " ORDER BY chanid ASC, starttime ASC, type ASC, mark ASC LIMIT 1;";
4104 "SELECT `offset`,mark FROM recordedseek"
4105 " WHERE chanid = :CHANID"
4106 " AND starttime = :STARTTIME"
4108 " AND `offset` <= :QUERY_ARG"
4109 " ORDER BY chanid DESC, starttime DESC, type DESC, mark DESC LIMIT 1;";
4112 uint64_t position_or_keyframe,
4115 const char *from_filemarkup_asc,
4116 const char *from_filemarkup_desc,
4117 const char *from_recordedseek_asc,
4118 const char *from_recordedseek_desc)
const
4125 query.
prepare(from_filemarkup_desc);
4127 query.
prepare(from_filemarkup_asc);
4133 query.
prepare(from_recordedseek_desc);
4135 query.
prepare(from_recordedseek_asc);
4140 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4150 *result = query.
value(1).toULongLong();
4157 query.
prepare(from_filemarkup_asc);
4159 query.
prepare(from_filemarkup_desc);
4165 query.
prepare(from_recordedseek_asc);
4167 query.
prepare(from_recordedseek_desc);
4172 query.
bindValue(
":QUERY_ARG", (
unsigned long long)position_or_keyframe);
4182 *result = query.
value(1).toULongLong();
4191 bool backwards)
const
4200 bool backwards)
const
4209 bool backwards)
const
4218 bool backwards)
const
4238 query.
prepare(
"INSERT INTO recordedmarkup"
4239 " (chanid, starttime, mark, type, data)"
4241 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4245 query.
bindValue(
":MARK", (quint64)frame);
4253 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
4254 query.
bindValue(
":DATA", QVariant(QVariant::UInt));
4256 query.
bindValue(
":DATA", QVariant(QMetaType(QMetaType::UInt)));
4274 query.
prepare(
"INSERT INTO recordedmarkup"
4275 " (chanid, starttime, mark, type, data)"
4277 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4280 query.
bindValue(
":MARK", (quint64)frame);
4299 query.
prepare(
"INSERT INTO recordedmarkup"
4300 " (chanid, starttime, mark, type, data)"
4302 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4305 query.
bindValue(
":MARK", (quint64)frame);
4322 query.
prepare(
"DELETE FROM recordedmarkup "
4323 " WHERE chanid=:CHANID "
4324 " AND starttime=:STARTTIME "
4333 query.
prepare(
"INSERT INTO recordedmarkup"
4334 " (chanid, starttime, mark, type, data)"
4336 " ( :CHANID, :STARTTIME, 0, :TYPE, :DATA);");
4354 query.
prepare(
"DELETE FROM recordedmarkup "
4355 " WHERE chanid=:CHANID "
4356 " AND starttime=:STARTTIME "
4365 query.
prepare(
"INSERT INTO recordedmarkup"
4366 " (chanid, starttime, mark, type, data)"
4368 " ( :CHANID, :STARTTIME, 0, :TYPE, :DATA);");
4388 query.
prepare(
"INSERT INTO recordedmarkup"
4389 " (chanid, starttime, mark, type, data)"
4391 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4394 query.
bindValue(
":MARK", (quint64)frame);
4401 query.
prepare(
"INSERT INTO recordedmarkup"
4402 " (chanid, starttime, mark, type, data)"
4404 " ( :CHANID, :STARTTIME, :MARK, :TYPE, :DATA);");
4407 query.
bindValue(
":MARK", (quint64)frame);
4418 QString qstr = QString(
4419 "SELECT recordedmarkup.data "
4420 "FROM recordedmarkup "
4421 "WHERE recordedmarkup.chanid = :CHANID AND "
4422 " recordedmarkup.starttime = :STARTTIME AND "
4423 " recordedmarkup.type = :TYPE "
4424 "GROUP BY recordedmarkup.data "
4425 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, recordedmarkup.mark)"
4426 " FROM recordedmarkup AS rm "
4427 " WHERE rm.chanid = recordedmarkup.chanid AND "
4428 " rm.starttime = recordedmarkup.starttime AND "
4429 " rm.type = recordedmarkup.type AND "
4430 " rm.mark > recordedmarkup.mark "
4431 " ORDER BY rm.mark ASC LIMIT 1 "
4432 " ) - recordedmarkup.mark "
4440 query.
bindValue(
":STARTTIME", recstartts);
4448 return (query.
next()) ? query.
value(0).toUInt() : 0;
4481 query.
prepare(
"SELECT recordedmarkup.type "
4482 "FROM recordedmarkup "
4483 "WHERE recordedmarkup.chanid = :CHANID AND "
4484 " recordedmarkup.starttime = :STARTTIME AND "
4485 " recordedmarkup.type >= :ASPECTSTART AND "
4486 " recordedmarkup.type <= :ASPECTEND "
4487 "GROUP BY recordedmarkup.type "
4488 "ORDER BY SUM( ( SELECT IFNULL(rm.mark, ( "
4489 " SELECT MAX(rmmax.mark) "
4490 " FROM recordedmarkup AS rmmax "
4491 " WHERE rmmax.chanid = recordedmarkup.chanid "
4492 " AND rmmax.starttime = recordedmarkup.starttime "
4494 " FROM recordedmarkup AS rm "
4495 " WHERE rm.chanid = recordedmarkup.chanid AND "
4496 " rm.starttime = recordedmarkup.starttime AND "
4497 " rm.type >= :ASPECTSTART2 AND "
4498 " rm.type <= :ASPECTEND2 AND "
4499 " rm.mark > recordedmarkup.mark "
4500 " ORDER BY rm.mark ASC LIMIT 1 "
4501 " ) - recordedmarkup.mark "
4563 QVector<MarkupEntry> &mapSeek)
const
4569 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4570 " WHERE filename = :PATH"
4571 " AND type NOT IN (:KEYFRAME,:DURATION)"
4572 " ORDER BY mark, type;");
4579 query.
prepare(
"SELECT type, mark, data FROM recordedmarkup"
4580 " WHERE chanid = :CHANID"
4581 " AND STARTTIME = :STARTTIME"
4582 " ORDER BY mark, type");
4595 while (query.
next())
4598 uint64_t frame = query.
value(1).toLongLong();
4600 bool isDataNull = query.
value(2).isNull();
4602 data = query.
value(2).toLongLong();
4609 query.
prepare(
"SELECT type, mark, `offset` FROM filemarkup"
4610 " WHERE filename = :PATH"
4611 " AND type IN (:KEYFRAME,:DURATION)"
4612 " ORDER BY mark, type;");
4619 query.
prepare(
"SELECT type, mark, `offset` FROM recordedseek"
4620 " WHERE chanid = :CHANID"
4621 " AND STARTTIME = :STARTTIME"
4622 " ORDER BY mark, type");
4631 while (query.
next())
4634 uint64_t frame = query.
value(1).toLongLong();
4636 bool isDataNull = query.
value(2).isNull();
4638 data = query.
value(2).toLongLong();
4644 const QVector<MarkupEntry> &mapSeek)
const
4650 if (mapMark.isEmpty())
4652 LOG(VB_GENERAL, LOG_INFO,
4653 QString(
"No mark entries in input, "
4654 "not removing marks from DB"));
4658 query.
prepare(
"DELETE FROM filemarkup"
4659 " WHERE filename = :PATH"
4660 " AND type NOT IN (:KEYFRAME,:DURATION)");
4669 for (
const auto& entry : qAsConst(mapMark))
4673 if (entry.isDataNull)
4675 query.
prepare(
"INSERT INTO filemarkup"
4676 " (filename,type,mark)"
4677 " VALUES (:PATH,:TYPE,:MARK)");
4681 query.
prepare(
"INSERT INTO filemarkup"
4682 " (filename,type,mark,`offset`)"
4683 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4684 query.
bindValue(
":OFFSET", (quint64)entry.data);
4688 query.
bindValue(
":MARK", (quint64)entry.frame);
4696 if (mapSeek.isEmpty())
4698 LOG(VB_GENERAL, LOG_INFO,
4699 QString(
"No seek entries in input, "
4700 "not removing marks from DB"));
4704 query.
prepare(
"DELETE FROM filemarkup"
4705 " WHERE filename = :PATH"
4706 " AND type IN (:KEYFRAME,:DURATION)");
4715 for (
int i = 0; i < mapSeek.size(); ++i)
4717 if (i > 0 && (i % 1000 == 0))
4719 LOG(VB_GENERAL, LOG_INFO,
4720 QString(
"Inserted %1 of %2 records")
4721 .arg(i).arg(mapSeek.size()));
4724 query.
prepare(
"INSERT INTO filemarkup"
4725 " (filename,type,mark,`offset`)"
4726 " VALUES (:PATH,:TYPE,:MARK,:OFFSET)");
4741 if (mapMark.isEmpty())
4743 LOG(VB_GENERAL, LOG_INFO,
4744 QString(
"No mark entries in input, "
4745 "not removing marks from DB"));
4749 query.
prepare(
"DELETE FROM recordedmarkup"
4750 " WHERE chanid = :CHANID"
4751 " AND starttime = :STARTTIME");
4759 for (
const auto& entry : qAsConst(mapMark))
4761 if (entry.isDataNull)
4763 query.
prepare(
"INSERT INTO recordedmarkup"
4764 " (chanid,starttime,type,mark)"
4765 " VALUES (:CHANID,:STARTTIME,:TYPE,:MARK)");
4769 query.
prepare(
"INSERT INTO recordedmarkup"
4770 " (chanid,starttime,type,mark,data)"
4771 " VALUES (:CHANID,:STARTTIME,"
4772 " :TYPE,:MARK,:OFFSET)");
4773 query.
bindValue(
":OFFSET", (quint64)entry.data);
4778 query.
bindValue(
":MARK", (quint64)entry.frame);
4786 if (mapSeek.isEmpty())
4788 LOG(VB_GENERAL, LOG_INFO,
4789 QString(
"No seek entries in input, "
4790 "not removing marks from DB"));
4794 query.
prepare(
"DELETE FROM recordedseek"
4795 " WHERE chanid = :CHANID"
4796 " AND starttime = :STARTTIME");
4804 for (
int i = 0; i < mapSeek.size(); ++i)
4806 if (i > 0 && (i % 1000 == 0))
4808 LOG(VB_GENERAL, LOG_INFO,
4809 QString(
"Inserted %1 of %2 records")
4810 .arg(i).arg(mapSeek.size()));
4813 query.
prepare(
"INSERT INTO recordedseek"
4814 " (chanid,starttime,type,mark,`offset`)"
4815 " VALUES (:CHANID,:STARTTIME,"
4816 " :TYPE,:MARK,:OFFSET)");
4836 LOG(VB_RECORD, LOG_INFO,
4837 QString(
"SaveVideoProperties(0x%1, 0x%2)")
4838 .arg(mask,2,16,QChar(
'0')).arg(video_property_flags,2,16,QChar(
'0')));
4841 "UPDATE recordedprogram "
4842 "SET videoprop = ((videoprop+0) & :OTHERFLAGS) | :FLAGS "
4843 "WHERE chanid = :CHANID AND starttime = :STARTTIME");
4846 query.
bindValue(
":FLAGS", video_property_flags);
4856 videoproperties &= ~mask;
4857 videoproperties |= video_property_flags;
4875 QString chan(format);
4885 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UpdateInUseMark(%1) '%2'")
4905 "SET season = :SEASON, episode = :EPISODE "
4906 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
4907 "AND recordid = :RECORDID");
4929 "SET inetref = :INETREF "
4930 "WHERE chanid = :CHANID AND starttime = :STARTTIME "
4931 "AND recordid = :RECORDID");
4970 query.
prepare(
"SELECT password FROM recgroups "
4971 "WHERE recgroup = :GROUP");
4975 result = query.
value(0).toString();
4985 query.
prepare(
"SELECT recgroup FROM recorded "
4986 "WHERE chanid = :CHANID AND "
4987 " starttime = :START");
4993 grp = query.
value(0).toString();
5001 query.
prepare(
"SELECT transcoder FROM recorded "
5002 "WHERE chanid = :CHANID AND "
5003 " starttime = :START");
5008 return query.
value(0).toUInt();
5026 if (path.startsWith(
"/"))
5028 QFileInfo testFile(path);
5029 return testFile.path();
5040 if (testFile.exists())
5042 if (testFile.isSymLink())
5045 if (testFile.isFile())
5046 return testFile.path();
5047 if (testFile.isDir())
5048 return testFile.filePath();
5052 testFile.setFile(testFile.absolutePath());
5053 if (testFile.exists())
5055 if (testFile.isSymLink())
5058 if (testFile.isDir())
5059 return testFile.filePath();
5078 bool notifyOfChange =
false;
5084 if (!usedFor.isEmpty())
5090 LOG(VB_GENERAL, LOG_INFO,
LOC +
5091 QString(
"MarkAsInUse(true, '%1'->'%2')")
5093 " -- use has changed");
5097 LOG(VB_GENERAL, LOG_INFO,
LOC +
5098 QString(
"MarkAsInUse(true, ''->'%1')").arg(usedFor));
5100 #endif // DEBUG_IN_USE
5107 .arg(QObject::tr(
"Unknown")).arg(getpid());
5108 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5110 " -- use was not explicitly set");
5113 notifyOfChange =
true;
5118 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5119 QString(
"MarkAsInUse(false, '%1'->'%2')")
5121 " -- use has changed since first setting as in use.");
5126 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"MarkAsInUse(false, '%1')")
5129 #endif // DEBUG_IN_USE
5136 LOG(VB_GENERAL, LOG_WARNING,
LOC +
5137 "MarkAsInUse requires a key to delete in use mark");
5145 "DELETE FROM inuseprograms "
5146 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5147 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5172 "FROM inuseprograms "
5173 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5174 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5184 else if (!query.
next())
5186 LOG(VB_GENERAL, LOG_ERR,
LOC +
"MarkAsInUse -- select query failed");
5188 else if (query.
value(0).toBool())
5191 "UPDATE inuseprograms "
5192 "SET lastupdatetime = :UPDATETIME "
5193 "WHERE chanid = :CHANID AND starttime = :STARTTIME AND "
5194 " hostname = :HOSTNAME AND recusage = :RECUSAGE");
5199 query.
bindValue(
":UPDATETIME", inUseTime);
5209 "INSERT INTO inuseprograms "
5210 " (chanid, starttime, recusage, hostname, "
5211 " lastupdatetime, rechost, recdir) "
5213 " (:CHANID, :STARTTIME, :RECUSAGE, :HOSTNAME, "
5214 " :UPDATETIME, :RECHOST, :RECDIR)");
5219 query.
bindValue(
":UPDATETIME", inUseTime);
5231 if (!notifyOfChange)
5236 query.
prepare(
"SELECT DISTINCT recusage "
5237 "FROM inuseprograms "
5238 "WHERE lastupdatetime >= :ONEHOURAGO AND "
5239 " chanid = :CHANID AND "
5240 " starttime = :STARTTIME");
5243 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5247 m_programFlags &= ~(FL_INUSEPLAYING | FL_INUSERECORDING | FL_INUSEOTHER);
5248 while (query.
next())
5250 QString inUseForWhat = query.
value(0).toString();
5272 query.
prepare(
"SELECT channel.channum, capturecard.inputname "
5273 "FROM channel, capturecard "
5274 "WHERE channel.chanid = :CHANID AND "
5275 " capturecard.sourceid = :SOURCEID AND "
5276 " capturecard.cardid = :INPUTID");
5283 channum = query.
value(0).toString();
5284 input = query.
value(1).toString();
5293 static bool s_done =
false;
5294 static QMutex s_initTrLock;
5295 QMutexLocker locker(&s_initTrLock);
5299 QString rec_profile_names =
5300 QObject::tr(
"Default",
"Recording Profile Default") +
5301 QObject::tr(
"High Quality",
"Recording Profile High Quality") +
5302 QObject::tr(
"Live TV",
"Recording Profile Live TV") +
5303 QObject::tr(
"Low Quality",
"Recording Profile Low Quality") +
5304 QObject::tr(
"Medium Quality",
"Recording Profile Medium Quality") +
5305 QObject::tr(
"MPEG-2",
"Recording Profile MPEG-2") +
5306 QObject::tr(
"RTjpeg/MPEG-4",
"Recording Profile RTjpeg/MPEG-4");
5309 QString rec_profile_groups =
5310 QObject::tr(
"CRC IP Recorders",
5311 "Recording Profile Group Name") +
5312 QObject::tr(
"FireWire Input",
5313 "Recording Profile Group Name") +
5314 QObject::tr(
"Freebox Input",
5315 "Recording Profile Group Name") +
5316 QObject::tr(
"Hardware DVB Encoders",
5317 "Recording Profile Group Name") +
5318 QObject::tr(
"Hardware HDTV",
5319 "Recording Profile Group Name") +
5320 QObject::tr(
"Hardware MJPEG Encoders (Matrox G200-TV, Miro DC10, etc)",
5321 "Recording Profile Group Name") +
5322 QObject::tr(
"HD-PVR Recorders",
5323 "Recording Profile Group Name") +
5324 QObject::tr(
"HDHomeRun Recorders",
5325 "Recording Profile Group Name") +
5326 QObject::tr(
"MPEG-2 Encoders (PVR-x50, PVR-500)",
5327 "Recording Profile Group Name") +
5328 QObject::tr(
"Software Encoders (V4L based)",
5329 "Recording Profile Group Name") +
5330 QObject::tr(
"Transcoders",
5331 "Recording Profile Group Name") +
5332 QObject::tr(
"USB MPEG-4 Encoder (Plextor ConvertX, etc)",
5333 "Recording Profile Group Name") +
5334 QObject::tr(
"V4L2 Encoders",
5335 "Recording Profile Group Name");
5337 QString display_rec_groups =
5338 QObject::tr(
"All Programs",
"Recording Group All Programs") +
5339 QObject::tr(
"All",
"Recording Group All Programs -- short form") +
5340 QObject::tr(
"Live TV",
"Recording Group Live TV") +
5341 QObject::tr(
"Default",
"Recording Group Default") +
5342 QObject::tr(
"Deleted",
"Recording Group Deleted");
5344 QString special_program_groups =
5345 QObject::tr(
"All Programs - %1",
5346 "Show all programs from a specific recording group");
5348 QString storage_groups =
5349 QObject::tr(
"Default",
"Storage Group Name") +
5350 QObject::tr(
"Live TV",
"Storage Group Name") +
5351 QObject::tr(
"Thumbnails",
"Storage Group Name") +
5352 QObject::tr(
"DB Backups",
"Storage Group Name");
5354 QString play_groups =
5355 QObject::tr(
"Default",
"Playback Group Name");
5358 return (rec_profile_names.length() +
5359 rec_profile_groups.length() +
5360 display_rec_groups.length() +
5361 special_program_groups.length() +
5362 storage_groups.length() +
5363 play_groups.length());
5378 QByteArray msg_arr = msg.toLatin1();
5379 QString msg_i18n = QObject::tr(msg_arr.constData());
5380 QByteArray msg_i18n_arr = msg_i18n.toLatin1();
5381 return (msg_arr == msg_i18n_arr) ? msg : msg_i18n;
5393 if (pburl.startsWith(
"myth://"))
5395 str.replace(QString(
"%DIR%"), pburl);
5399 QFileInfo dirInfo(pburl);
5400 str.replace(QString(
"%DIR%"), dirInfo.path());
5408 str.replace(QString(
"%TITLE%"),
m_title.replace(
"\"",
"ʺ"));
5409 str.replace(QString(
"%SUBTITLE%"),
m_subtitle.replace(
"\"",
"ʺ"));
5410 str.replace(QString(
"%SEASON%"), QString::number(
m_season));
5411 str.replace(QString(
"%EPISODE%"), QString::number(
m_episode));
5412 str.replace(QString(
"%TOTALEPISODES%"), QString::number(
m_totalEpisodes));
5414 str.replace(QString(
"%DESCRIPTION%"),
m_description.replace(
"\"",
"ʺ"));
5415 str.replace(QString(
"%HOSTNAME%"),
m_hostname);
5416 str.replace(QString(
"%CATEGORY%"),
m_category);
5417 str.replace(QString(
"%RECGROUP%"),
m_recGroup);
5419 str.replace(QString(
"%CHANID%"), QString::number(
m_chanId));
5420 str.replace(QString(
"%INETREF%"),
m_inetRef);
5421 str.replace(QString(
"%PARTNUMBER%"), QString::number(
m_partNumber));
5422 str.replace(QString(
"%PARTTOTAL%"), QString::number(
m_partTotal));
5423 str.replace(QString(
"%ORIGINALAIRDATE%"),
5425 static const std::array<const QString,4> s_timeStr
5426 {
"STARTTIME",
"ENDTIME",
"PROGSTART",
"PROGEND", };
5427 const std::array<const QDateTime *,4> time_dtr
5429 for (
size_t i = 0; i < s_timeStr.size(); i++)
5431 str.replace(QString(
"%%1%").arg(s_timeStr[i]),
5432 (time_dtr[i]->toLocalTime()).
toString(
"yyyyMMddhhmmss"));
5433 str.replace(QString(
"%%1ISO%").arg(s_timeStr[i]),
5435 str.replace(QString(
"%%1UTC%").arg(s_timeStr[i]),
5436 time_dtr[i]->
toString(
"yyyyMMddhhmmss"));
5437 str.replace(QString(
"%%1ISOUTC%").arg(s_timeStr[i]),
5440 str.replace(QString(
"%RECORDEDID%"), QString::number(
m_recordedId));
5445 QMap<QString, uint32_t> inUseMap;
5450 query.
prepare(
"SELECT DISTINCT chanid, starttime, recusage "
5451 "FROM inuseprograms WHERE lastupdatetime >= :ONEHOURAGO");
5452 query.
bindValue(
":ONEHOURAGO", oneHourAgo);
5457 while (query.
next())
5460 query.
value(0).toUInt(),
5463 QString inUseForWhat = query.
value(2).toString();
5465 if (!inUseMap.contains(inUseKey))
5466 inUseMap[inUseKey] = 0;
5469 inUseMap[inUseKey] |= FL_INUSEPLAYING;
5471 inUseMap[inUseKey] |= FL_INUSERECORDING;
5473 inUseMap[inUseKey] |= FL_INUSEOTHER;
5481 QMap<QString,bool> is_job_running;
5484 query.
prepare(
"SELECT chanid, starttime, status FROM jobqueue "
5485 "WHERE type = :TYPE");
5488 return is_job_running;
5490 while (query.
next())
5494 int tmpStatus = query.
value(2).toInt();
5495 if ((tmpStatus != 0x0000) &&
5496 (tmpStatus != 0x0001) &&
5497 (!(tmpStatus & 0x0100)))
5504 return is_job_running;
5508 const QString &tmptable,
int recordid)
5513 if (
sched && tmptable.isEmpty())
5521 LOG(VB_GENERAL, LOG_ERR,
5522 "Called from master backend\n\t\t\t"
5523 "with recordid or tmptable, this is not currently supported");
5528 (tmptable.isEmpty()) ?
5529 QString(
"QUERY_GETALLPENDING") :
5530 QString(
"QUERY_GETALLPENDING %1 %2").arg(tmptable).arg(recordid));
5534 LOG(VB_GENERAL, LOG_ALERT,
5535 "LoadFromScheduler(): Error querying master.");
5553 QString columns = QString(
5554 "program.chanid, program.starttime, program.endtime, "
5555 "program.title, program.subtitle, program.description, "
5556 "program.category, channel.channum, channel.callsign, "
5557 "channel.name, program.previouslyshown, channel.commmethod, "
5558 "channel.outputfilters, program.seriesid, program.programid, "
5559 "program.airdate, program.stars, program.originalairdate, "
5560 "program.category_type, oldrecstatus.recordid, "
5561 "oldrecstatus.rectype, oldrecstatus.recstatus, "
5562 "oldrecstatus.findid, program.videoprop+0, program.audioprop+0, "
5563 "program.subtitletypes+0, program.syndicatedepisodenumber, "
5564 "program.partnumber, program.parttotal, "
5565 "program.season, program.episode, program.totalepisodes ");
5567 QString querystr = QString(
5570 "LEFT JOIN channel ON program.chanid = channel.chanid "
5571 "LEFT JOIN oldrecorded AS oldrecstatus ON "
5572 " oldrecstatus.future = 0 AND "
5573 " program.title = oldrecstatus.title AND "
5574 " channel.callsign = oldrecstatus.station AND "
5575 " program.starttime = oldrecstatus.starttime "
5581 querystr += QString(
"LIMIT %1 ").arg(limit);
5582 else if (!querystr.contains(
" LIMIT "))
5583 querystr +=
" LIMIT 20000 ";
5585 MSqlBindings::const_iterator it;
5602 if (start > 0 || limit > 0)
5604 QString countStr = querystr.arg(
"SQL_CALC_FOUND_ROWS program.chanid");
5606 for (it = bindings.begin(); it != bindings.end(); ++it)
5608 if (countStr.contains(it.key()))
5618 if (query.
exec(
"SELECT FOUND_ROWS()") && query.
next())
5619 count = query.
value(0).toUInt();
5623 querystr += QString(
"OFFSET %1 ").arg(start);
5625 querystr = querystr.arg(columns);
5627 for (it = bindings.begin(); it != bindings.end(); ++it)
5629 if (querystr.contains(it.key()))
5643 const QString &groupBy,
const QString &orderBy,
5648 QString queryStr =
"";
5650 if (!where.isEmpty())
5651 queryStr.append(QString(
"WHERE %1 ").arg(where));
5653 if (!groupBy.isEmpty())
5654 queryStr.append(QString(
"GROUP BY %1 ").arg(groupBy));
5656 if (!orderBy.isEmpty())
5657 queryStr.append(QString(
"ORDER BY %1 ").arg(orderBy));
5661 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0, count);
5670 QString queryStr = sql;
5684 if (!queryStr.contains(
"WHERE"))
5685 queryStr +=
" WHERE deleted IS NULL AND visible > 0 ";
5693 if (!queryStr.contains(
"GROUP BY"))
5694 queryStr +=
" GROUP BY program.starttime, channel.channum, "
5695 " channel.callsign, program.title ";
5697 if (!queryStr.contains(
"ORDER BY"))
5699 queryStr +=
" ORDER BY program.starttime, ";
5702 if (chanorder !=
"channum")
5703 queryStr += chanorder +
" ";
5705 queryStr +=
"atsc_major_chan,atsc_minor_chan,channum,callsign ";
5710 return LoadFromProgram(destination, queryStr, bindings, schedList, 0, 0, count);
5718 destination.
clear();
5720 if (sql.contains(
" OFFSET", Qt::CaseInsensitive))
5722 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains OFFSET "
5723 "clause, caller should be updated to use "
5724 "start parameter instead");
5727 if (sql.contains(
" LIMIT", Qt::CaseInsensitive))
5729 LOG(VB_GENERAL, LOG_WARNING,
"LoadFromProgram(): SQL contains LIMIT "
5730 "clause, caller should be updated to use "
5731 "limit parameter instead");
5740 count = query.
size();
5742 while (query.
next())
5746 query.
value(3).toString(),
5748 query.
value(4).toString(),
5750 query.
value(5).toString(),
5751 query.
value(26).toString(),
5752 query.
value(6).toString(),
5754 query.
value(0).toUInt(),
5755 query.
value(7).toString(),
5756 query.
value(8).toString(),
5757 query.
value(9).toString(),
5758 query.
value(12).toString(),
5765 query.
value(13).toString(),
5766 query.
value(14).toString(),
5769 query.
value(16).toFloat(),
5770 query.
value(15).toUInt(),
5771 query.
value(27).toUInt(),
5772 query.
value(28).toUInt(),
5773 query.
value(17).toDate(),
5775 query.
value(19).toUInt(),
5777 query.
value(22).toUInt(),