3#include <QCoreApplication>
6#include <QRegularExpression>
28 int sourceid, QString channelname)
30 m_strChannelname(
std::move(channelname)), m_fRefresh(fRefresh), m_sourceId(sourceid),
32 "https://services.mythtv.org") +
"/channel-icon")
37 LOG(VB_GENERAL, LOG_INFO,
42 LOG(VB_GENERAL, LOG_INFO,
"Fetching icons for multiple channels");
57 QStringList files =
m_tmpDir.entryList();
58 for (
const QString &
file : std::as_const(files))
83 LOG(VB_GENERAL, LOG_ERR,
84 "Unable to load window 'iconimport', missing required element(s)");
195 LOG(VB_GENERAL, LOG_INFO, QString(
"Menu Selection: %1 %2 %3")
196 .arg(entry.strID, entry.strName, entry.strLogo));
257 if (!iconpath.isEmpty())
272 QDir configDir(dirpath);
273 if (!configDir.exists() && !configDir.mkdir(dirpath))
275 LOG(VB_GENERAL, LOG_ERR, QString(
"Could not create %1").arg(dirpath));
283 LOG(VB_GENERAL, LOG_ERR,
288 bool closeDialog =
false;
290 QString querystring(
"SELECT chanid, name, xmltvid, callsign,"
291 "dtv_multiplex.transportid, atsc_major_chan, "
292 "atsc_minor_chan, dtv_multiplex.networkid, "
293 "channel.serviceid, channel.mplexid,"
294 "dtv_multiplex.mplexid, channel.icon, channel.visible "
295 "FROM channel LEFT JOIN dtv_multiplex "
296 "ON channel.mplexid = dtv_multiplex.mplexid "
297 "WHERE deleted IS NULL AND ");
299 querystring.append(
"name=\"" + name +
"\"");
301 querystring.append(
"channel.visible > 0");
303 querystring.append(QString(
" AND channel.sourceid = %1").arg(
m_sourceId));
304 querystring.append(
" ORDER BY name");
314 if (query.
exec() && query.
size() > 0)
324 QCoreApplication::processEvents();
335 QString relativeIconPath = query.
value(11).toString();
339 if (
m_fRefresh && !relativeIconPath.isEmpty() &&
340 QFile(absoluteIconPath).
exists() &&
341 !QImage(absoluteIconPath).isNull())
343 LOG(VB_GENERAL, LOG_NOTICE, QString(
"Icon already exists, skipping (%1)").arg(absoluteIconPath));
356 entry.
strIconCSV= QString(
"%1,%2,%3,%4,%5,%6,%7,%8,%9\n").
367 LOG(VB_CHANNEL, LOG_INFO,
377 QCoreApplication::processEvents();
392 "IconImportInitProgress");
398 QCoreApplication::processEvents();
410 QString downloadMessage = tr(
"Downloading %1 (%2 of %3)");
414 QString message = downloadMessage.arg(
m_iter->strName)
418 LOG(VB_GENERAL, LOG_NOTICE, message);
422 message.append(
"\n");
423 message.append(tr(
"Could not find %n icon(s).",
"",
439 QCoreApplication::processEvents();
460 LOG(VB_CHANNEL, LOG_INFO, QString(
"Icons: Found %1 / Missing %2")
465 (*m_missingIter).strName.isEmpty())
473 LOG(VB_CHANNEL, LOG_INFO,
"doLoad Icon search complete");
480 .arg((*m_missingIter).strName));
482 if (!
search((*m_missingIter).strName))
485 .arg((*m_missingIter).strName));
497 static const QRegularExpression rxDblForEscape(
"\"");
499 str2.replace(rxDblForEscape,
"\\\"");
500 return "\""+str2+
"\"";
507 bool in_comment =
false;
508 bool in_escape =
false;
510 for (
const auto& cur : std::as_const(line))
519 in_comment = !in_comment;
521 else if (cur ==
'\\')
525 else if (!in_comment && (cur ==
','))
540 while (ret.size() < 5)
548 QByteArray data(strParam.toLatin1());
550 auto *req =
new QNetworkRequest(url);
551 req->setHeader(QNetworkRequest::ContentTypeHeader, QString(
"application/x-www-form-urlencoded"));
552 req->setHeader(QNetworkRequest::ContentLengthHeader, data.size());
554 LOG(VB_CHANNEL, LOG_DEBUG, QString(
"ImportIconsWizard: posting to: %1, params: %2")
555 .arg(url.toString(), strParam));
559 LOG(VB_CHANNEL, LOG_DEBUG, QString(
"ImportIconsWizard: result: %1").arg(QString(data)));
566#include <QTemporaryFile>
569 QString
filename = url.section(
'/', -1);
576 QTemporaryFile tmpFile(filePath);
579 LOG(VB_GENERAL, LOG_INFO,
"Icon Download: Couldn't create temporary file");
587 LOG(VB_GENERAL, LOG_INFO,
588 QString(
"Download for icon %1 failed").arg(
filename));
592 QImage icon(tmpFile.fileName());
595 LOG(VB_GENERAL, LOG_INFO,
596 QString(
"Downloaded icon for %1 isn't a valid image").arg(
filename));
601 QFile
file(filePath);
605 tmpFile.rename(filePath);
606 tmpFile.setAutoRemove(
false);
609 QString qstr =
"UPDATE channel SET icon = :ICON "
610 "WHERE chanid = :CHANID";
627 QString strParam1 = QUrl::toPercentEncoding(
"callsign="+strParam);
628 QUrl url(
m_url+
"/lookup");
630 QString str =
wget(url,strParam1);
631 if (str.isEmpty() || str.startsWith(
"Error", Qt::CaseInsensitive))
633 LOG(VB_GENERAL, LOG_ERR,
634 QString(
"Error from icon lookup : %1").arg(str));
637 LOG(VB_CHANNEL, LOG_INFO,
638 QString(
"Icon Import: Working lookup : %1").arg(str));
645 QString strParam1 = QUrl::toPercentEncoding(strParam);
648 QUrl url(
m_url+
"/search");
651 QString channelcsv = QString(
"%1,%2,%3,%4,%5,%6,%7,%8\n")
661 QString message = QObject::tr(
"Searching for icons for channel %1")
666 QString str =
wget(url,
"s="+strParam1+
"&csv="+channelcsv);
670 if (str.isEmpty() || str.startsWith(
"#") ||
671 str.startsWith(
"Error", Qt::CaseInsensitive))
673 LOG(VB_GENERAL, LOG_ERR, QString(
"Error from search : %1").arg(str));
678 LOG(VB_CHANNEL, LOG_INFO,
679 QString(
"Icon Import: Working search : %1").arg(str));
680 QStringList strSplit = str.split(
"\n");
685 if (strSplit.size() > 150)
687 LOG(VB_GENERAL, LOG_WARNING,
688 QString(
"Warning: Result set contains %1 items, "
689 "truncating to the first %2 results")
690 .arg(strSplit.size()).arg(150));
691 while (strSplit.size() > 150)
692 strSplit.removeLast();
696 QString prevIconName;
699 for (
const QString& row : std::as_const(strSplit))
704 LOG(VB_CHANNEL, LOG_INFO,
705 QString(
"Icon Import: search : %1 %2 %3")
706 .arg(ret[0], ret[1], ret[2]));
708 entry.
strID = ret[0];
714 if (prevIconName == entry.
strName)
716 QString newname = QString(
"%1 (%2)").arg(entry.
strName)
719 QVariant::fromValue(entry));
725 QVariant::fromValue(entry));
729 QString iconname = entry.
strName;
732 item->
SetText(iconname,
"iconname");
747 QString strParam1 = QUrl::toPercentEncoding(strParam);
748 QUrl url(
m_url+
"/findmissing");
750 QString str =
wget(url,
"csv="+strParam1);
751 LOG(VB_CHANNEL, LOG_INFO,
752 QString(
"Icon Import: findmissing : strParam1 = %1. str = %2")
753 .arg(strParam1, str));
754 if (str.isEmpty() || str.startsWith(
"#"))
758 if (str.startsWith(
"Error", Qt::CaseInsensitive))
760 LOG(VB_GENERAL, LOG_ERR,
761 QString(
"Error from findmissing : %1").arg(str));
765 LOG(VB_CHANNEL, LOG_INFO,
766 QString(
"Icon Import: Working findmissing : %1") .arg(str));
767 QStringList strSplit = str.split(
"\n", Qt::SkipEmptyParts);
768 for (
const auto& line : std::as_const(strSplit))
770 if (line[0] == QChar(
'#'))
774 LOG(VB_CHANNEL, LOG_INFO,
775 QString(
"Icon Import: findmissing : %1 %2 %3 %4 %5")
776 .arg(ret[0], ret[1], ret[2], ret[3], ret[4]));
785 QString message = tr(
"You now have the opportunity to transmit your "
786 "choices back to mythtv.org so that others can "
787 "benefit from your selections.");
791 confirmPopup->SetReturnEvent(
this,
"submitresults");
793 if (confirmPopup->Create())
799 QString strParam1 = QUrl::toPercentEncoding(
m_strParam);
800 QUrl url(
m_url+
"/submit");
802 QString str =
wget(url,
"csv="+strParam1);
803 if (str.isEmpty() || str.startsWith(
"#") ||
804 str.startsWith(
"Error", Qt::CaseInsensitive))
806 LOG(VB_GENERAL, LOG_ERR, QString(
"Error from submit : %1").arg(str));
811 LOG(VB_CHANNEL, LOG_INFO, QString(
"Icon Import: Working submit : %1")
813 QStringList strSplit = str.split(
"\n", Qt::SkipEmptyParts);
816 unsigned callsign = 0;
818 unsigned xmltvid = 0;
819 for (
const auto& line : std::as_const(strSplit))
821 if (line[0] == QChar(
'#'))
824 QStringList strSplit2=(line).split(
":", Qt::SkipEmptyParts);
825 if (strSplit2.size() < 2)
828 QString s = strSplit2[0].trimmed();
830 atsc = strSplit2[1].toUInt();
832 callsign = strSplit2[1].toUInt();
834 dvb = strSplit2[1].toUInt();
836 tv = strSplit2[1].toUInt();
838 xmltvid = strSplit2[1].toUInt();
840 LOG(VB_CHANNEL, LOG_INFO,
841 QString(
"Icon Import: working submit : atsc=%1 callsign=%2 "
842 "dvb=%3 tv=%4 xmltvid=%5")
843 .arg(atsc).arg(callsign).arg(dvb).arg(tv).arg(xmltvid));
854 QString resultid = dce->GetId();
855 int buttonnum = dce->GetResult();
857 if (resultid ==
"submitresults")
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
static const Type kEventType
bool m_fRefresh
are we doing a refresh or not
MythUITextEdit * m_manualEdit
manual edit field
ListEntriesIter m_iter
the current iterator
int m_missingCount
the current search point (0..m_missingCount)
void menuSelection(MythUIButtonListItem *item)
process the icon selection
bool checkAndDownload(const QString &url, const QString &localChanId)
checks and attempts to download the logo file to the appropriate place
bool findmissing(const QString &strParam)
retrieve the actual logo for the TV channel
QString m_strChannelDir
the location of the channel icon dir
void customEvent(QEvent *event) override
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
MythUIProgressDialog * m_progressDialog
MythUIText * m_nameText
name field for the icon
bool doLoad()
attempts to move the iteration on one/more than one
void skip()
skip this icon
void askSubmit(const QString &strParam)
int m_nMaxCount
the maximum number of TV channels
void manualSearch()
process the manual search
MythUIText * m_statusText
MythScreenStack * m_popupStack
ListEntries m_missingEntries
list of TV channels with no unique icon
static QString escape_csv(const QString &str)
changes a string into csv format
int m_missingMaxCount
the total number of missing icons
MythUIButton * m_manualButton
manual button field
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
ListSearchEntries m_listSearch
the list of SearchEntry
bool Create(void) override
bool lookup(const QString &strParam)
looks up the string to determine the caller/xmltvid
void itemChanged(MythUIButtonListItem *item)
MythUIButton * m_skipButton
button skip
~ImportIconsWizard() override
static QStringList extract_csv(const QString &strLine)
extracts the csv values out of a string
ImportIconsWizard(MythScreenStack *parent, bool fRefresh, int sourceid=0, QString channelname="")
bool initialLoad(const QString &name="")
attempt the inital load of the TV channel information
void enableControls(ImportIconsWizard::dialogState state=STATE_NORMAL)
enable/disable the controls
ListEntriesIter m_missingIter
ListEntries m_listEntries
list of TV channels to search for
MythUIText * m_previewtitle
static QString wget(QUrl &url, const QString &strParam)
use the equivalent of wget to fetch the POST command
int m_nCount
the current search point (0..m_nMaxCount)
QString m_strChannelname
the channel name if searching for a single channel icon
MythUIButtonList * m_iconsList
list of potential icons
bool submit()
submit the icon information back to the remote db
int m_sourceId
selected video source or 0 for all sources
QString m_strMatches
the string for the submit() call
bool search(const QString &strParam)
search the remote db for icons etc
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Dialog asking for user confirmation.
static void DBError(const QString &where, const MSqlQuery &query)
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Screen in which all other widgets are contained and rendered.
void OpenBusyPopup(const QString &message="")
void BuildFocusList(void)
bool SetFocusWidget(MythUIType *widget=nullptr)
void CloseBusyPopup(void)
Image widget, displays a single image or multiple images in sequence.
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
void Reset(void) override
Reset the image back to the default defined in the theme.
bool Create(void) override
void SetProgress(uint count)
void SetMessage(const QString &message)
void SetTotal(uint total)
A text entry and edit widget.
QString GetText(void) const
void SetText(const QString &text, bool moveCursor=true)
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
All purpose text widget, displays a text string.
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
virtual void SetText(const QString &text)
void SetEnabled(bool enable)
void SetHelpText(const QString &text)
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MythMainWindow * GetMythMainWindow(void)
describes the TV channel name
QString strAtscMinorChan
ATSC minor number.
QString strAtscMajorChan
ATSC major number.
QString strServiceId
service id
QString strTransportId
transport id
QString strNetworkId
network id
QString strChanId
local channel id
QString strIconCSV
icon name (csv form)
QString strXmlTvId
the xmltvid
QString strName
channel name
QString strCallsign
callsign
QString strNameCSV
name (csv form)
QString strName
the remote name
QString strLogo
the actual logo
QString strID
the remote channel id