MythTV master
programinforemoteutil.cpp
Go to the documentation of this file.
2
3#include <unistd.h>
4
5#include <QFileInfo>
6#include <QFile>
7#include <QDir>
8
11
12#include "programinfo.h"
13
14static uint RemoteGetRecordingList(std::vector<ProgramInfo *> &reclist, QStringList &strList)
15{
16 if (!gCoreContext->SendReceiveStringList(strList) || strList.isEmpty())
17 return 0;
18
19 int numrecordings = strList[0].toInt();
20 if (numrecordings <= 0)
21 return 0;
22
23 if ((numrecordings * NUMPROGRAMLINES) + 1 > strList.size())
24 {
25 LOG(VB_GENERAL, LOG_ERR,
26 "RemoteGetRecordingList() list size appears to be incorrect.");
27 return 0;
28 }
29
30 uint reclist_initial_size = (uint) reclist.size();
31 QStringList::const_iterator it = strList.cbegin() + 1;
32 for (int i = 0; i < numrecordings; i++)
33 {
34 auto *pginfo = new ProgramInfo(it, strList.cend());
35 reclist.push_back(pginfo);
36 }
37
38 return ((uint) reclist.size()) - reclist_initial_size;
39}
40
41std::vector<ProgramInfo *> *RemoteGetRecordedList(int sort)
42{
43 QString str = "QUERY_RECORDINGS ";
44 if (sort < 0)
45 str += "Descending";
46 else if (sort > 0)
47 str += "Ascending";
48 else
49 str += "Unsorted";
50
51 QStringList strlist(str);
52
53 auto *info = new std::vector<ProgramInfo *>;
54
55 if (!RemoteGetRecordingList(*info, strlist))
56 {
57 delete info;
58 return nullptr;
59 }
60
61 return info;
62}
63
64bool RemoteDeleteRecording(uint recordingID, bool forceMetadataDelete,
65 bool forgetHistory)
66{
67 // FIXME: Remove when DELETE_RECORDING has been updated to use recording id
68 ProgramInfo recInfo(recordingID);
69 bool result = true;
70 QString cmd =
71 QString("DELETE_RECORDING %1 %2 %3 %4")
72 .arg(QString::number(recInfo.GetChanID()),
73 recInfo.GetRecordingStartTime().toString(Qt::ISODate),
74 forceMetadataDelete ? "FORCE" : "NO_FORCE",
75 forgetHistory ? "FORGET" : "NO_FORGET");
76 QStringList strlist(cmd);
77
78 if ((!gCoreContext->SendReceiveStringList(strlist) || strlist.isEmpty()) ||
79 (strlist[0].toInt() == -2))
80 result = false;
81
82 if (!result)
83 {
84 LOG(VB_GENERAL, LOG_ALERT,
85 QString("Failed to delete recording %1:%2")
86 .arg(recInfo.GetChanID())
87 .arg(recInfo.GetRecordingStartTime().toString(Qt::ISODate)));
88 }
89
90 return result;
91}
92
94{
95 // FIXME: Remove when UNDELETE_RECORDING has been updated to use recording id
96 ProgramInfo recInfo(recordingID);
97 bool result = false;
98
99#if 0
100 if (!gCoreContext->GetNumSetting("AutoExpireInsteadOfDelete", 0))
101 return result;
102#endif
103
104 QStringList strlist(QString("UNDELETE_RECORDING"));
105 strlist.push_back(QString::number(recInfo.GetChanID()));
106 strlist.push_back(recInfo.GetRecordingStartTime().toString(Qt::ISODate));
107
109
110 if (!strlist.isEmpty() && strlist[0].toInt() == 0)
111 result = true;
112
113 return result;
114}
115
116void RemoteGetAllScheduledRecordings(std::vector<ProgramInfo *> &scheduledlist)
117{
118 QStringList strList(QString("QUERY_GETALLSCHEDULED"));
119 RemoteGetRecordingList(scheduledlist, strList);
120}
121
122void RemoteGetAllExpiringRecordings(std::vector<ProgramInfo *> &expiringlist)
123{
124 QStringList strList(QString("QUERY_GETEXPIRING"));
125 RemoteGetRecordingList(expiringlist, strList);
126}
127
128std::vector<ProgramInfo *> *RemoteGetConflictList(const ProgramInfo *pginfo)
129{
130 QString cmd = QString("QUERY_GETCONFLICTING");
131 QStringList strlist( cmd );
132 pginfo->ToStringList(strlist);
133
134 auto *retlist = new std::vector<ProgramInfo *>;
135
136 RemoteGetRecordingList(*retlist, strlist);
137 return retlist;
138}
139
143 const ProgramInfo &pginfo, const QString &cachefile)
144{
145 QString loc("RemoteGetPreviewIfModified: ");
146 QDateTime cacheLastModified;
147 QFileInfo cachefileinfo(cachefile);
148 if (cachefileinfo.exists())
149 cacheLastModified = cachefileinfo.lastModified();
150
151 QStringList strlist("QUERY_PIXMAP_GET_IF_MODIFIED");
152 strlist << ((cacheLastModified.isValid()) ? // unix secs, UTC
153 QString::number(cacheLastModified.toSecsSinceEpoch()) :
154 QString("-1"));
155 strlist << QString::number(200 * 1024); // max size of preview file
156 pginfo.ToStringList(strlist);
157
158 if (!gCoreContext->SendReceiveStringList(strlist) ||
159 strlist.isEmpty() || strlist[0] == "ERROR")
160 {
161 LOG(VB_GENERAL, LOG_ERR, loc + "Remote error" +
162 ((strlist.size() >= 2) ? (":\n\t\t\t" + strlist[1]) : ""));
163
164 return {};
165 }
166
167 if (strlist[0] == "WARNING")
168 {
169 LOG(VB_NETWORK, LOG_WARNING, loc + "Remote warning" +
170 ((strlist.size() >= 2) ? (":\n\t\t\t" + strlist[1]) : ""));
171
172 return {};
173 }
174
175 QDateTime retdatetime;
176 qlonglong timet = strlist[0].toLongLong();
177 if (timet >= 0)
178 {
179 retdatetime = MythDate::fromSecsSinceEpoch(timet);
180 }
181
182 if (strlist.size() < 4)
183 {
184 return retdatetime;
185 }
186
187 size_t length = strlist[1].toULongLong();
188 quint16 checksum16 = strlist[2].toUInt();
189 QByteArray data = QByteArray::fromBase64(strlist[3].toLatin1());
190 if ((size_t) data.size() < length)
191 { // (note data.size() may be up to 3 bytes longer after decoding
192 LOG(VB_GENERAL, LOG_ERR, loc +
193 QString("Preview size check failed %1 < %2")
194 .arg(data.size()).arg(length));
195 return {};
196 }
197 data.resize(length);
198
199#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
200 quint16 calculated = qChecksum(data.constData(), data.size());
201#else
202 quint16 calculated = qChecksum(data);
203#endif
204 if (checksum16 != calculated)
205 {
206 LOG(VB_GENERAL, LOG_ERR, loc + "Preview checksum failed");
207 return {};
208 }
209
210 QString pdir(cachefile.section("/", 0, -2));
211 QDir cfd(pdir);
212 if (!cfd.exists() && !cfd.mkdir(pdir))
213 {
214 LOG(VB_GENERAL, LOG_ERR, loc +
215 QString("Unable to create remote cache directory '%1'")
216 .arg(pdir));
217
218 return {};
219 }
220
221 QFile file(cachefile);
222 if (!file.open(QIODevice::WriteOnly|QIODevice::Truncate))
223 {
224 LOG(VB_GENERAL, LOG_ERR, loc +
225 QString("Unable to open cached preview file for writing '%1'")
226 .arg(cachefile));
227
228 return {};
229 }
230
231 off_t offset = 0;
232 size_t remaining = length;
233 uint failure_cnt = 0;
234 while ((remaining > 0) && (failure_cnt < 5))
235 {
236 ssize_t written = file.write(data.data() + offset, remaining);
237 if (written < 0)
238 {
239 failure_cnt++;
240 usleep(50000);
241 continue;
242 }
243
244 failure_cnt = 0;
245 offset += written;
246 remaining -= written;
247 }
248
249 if (remaining)
250 {
251 LOG(VB_GENERAL, LOG_ERR, loc +
252 QString("Failed to write cached preview file '%1'")
253 .arg(cachefile));
254
255 file.resize(0); // in case unlink fails..
256 file.remove(); // closes fd
257 return {};
258 }
259
260 file.close();
261
262 return retdatetime;
263}
264
265/* vim: set expandtab tabstop=4 shiftwidth=4: */
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
int GetNumSetting(const QString &key, int defaultval=0)
Holds information on recordings and videos.
Definition: programinfo.h:70
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:375
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:407
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
unsigned int uint
Definition: compat.h:68
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:81
@ ISODate
Default UTC.
Definition: mythdate.h:17
dictionary info
Definition: azlyrics.py:7
static constexpr int8_t NUMPROGRAMLINES
Definition: programinfo.h:30
void RemoteGetAllScheduledRecordings(std::vector< ProgramInfo * > &scheduledlist)
QDateTime RemoteGetPreviewIfModified(const ProgramInfo &pginfo, const QString &cachefile)
Download preview & get timestamp if newer than cachefile's last modified time, otherwise just get the...
std::vector< ProgramInfo * > * RemoteGetConflictList(const ProgramInfo *pginfo)
bool RemoteDeleteRecording(uint recordingID, bool forceMetadataDelete, bool forgetHistory)
std::vector< ProgramInfo * > * RemoteGetRecordedList(int sort)
static uint RemoteGetRecordingList(std::vector< ProgramInfo * > &reclist, QStringList &strList)
void RemoteGetAllExpiringRecordings(std::vector< ProgramInfo * > &expiringlist)
bool RemoteUndeleteRecording(uint recordingID)