Sophie

Sophie

distrib > Mageia > 6 > armv5tl > media > core-release-src > by-pkgid > e62519f85900136ff4a98a5eff4a1a93 > files > 3

mythtv-0.28.1-20170528.6.mga6.src.rpm

diff --git a/mythplugins/mytharchive/mytharchive/thumbfinder.cpp b/mythplugins/mytharchive/mytharchive/thumbfinder.cpp
index d2bcdf56d1..25b3829237 100644
--- a/mythplugins/mytharchive/mytharchive/thumbfinder.cpp
+++ b/mythplugins/mytharchive/mytharchive/thumbfinder.cpp
@@ -159,6 +159,8 @@ bool ThumbFinder::Create(void)
 
     connect(m_frameButton, SIGNAL(Clicked()), this, SLOT(updateThumb()));
 
+    m_seekAmountText->SetText(SeekAmounts[m_currentSeek].name);
+
     BuildFocusList();
 
     SetFocusWidget(m_imageGrid);
@@ -274,6 +276,12 @@ void ThumbFinder::loadCutList()
         delete progInfo;
     }
 
+    if (m_deleteMap.isEmpty())
+    {
+        LOG(VB_GENERAL, LOG_ERR, "ThumbFinder::loadCutList: Got an empty delete map");
+        return;
+    }
+
     // if the first mark is a end mark then add the start mark at the beginning
     frm_dir_map_t::const_iterator it = m_deleteMap.begin();
     if (it.value() == MARK_CUT_END)
diff --git a/mythtv/bindings/perl/MythTV.pm b/mythtv/bindings/perl/MythTV.pm
index 188fcc0080..db196ecdd2 100644
--- a/mythtv/bindings/perl/MythTV.pm
+++ b/mythtv/bindings/perl/MythTV.pm
@@ -372,6 +372,8 @@ EOF
                                       $self->{'db_user'},
                                       $self->{'db_pass'})
             or die "Cannot connect to database: $!\n\n";
+        $self->{'dbh'}->do("SET SESSION sql_mode = ''")
+            or die "Can't set sql_mode: $!\n\n";
         $self->{'dbh'}->do("SET time_zone = 'Etc/UTC'")
             or die "Can't set timezone: $!\n\n";
 
diff --git a/mythtv/bindings/python/MythTV/dataheap.py b/mythtv/bindings/python/MythTV/dataheap.py
index 859e060112..4de3085423 100644
--- a/mythtv/bindings/python/MythTV/dataheap.py
+++ b/mythtv/bindings/python/MythTV/dataheap.py
@@ -283,7 +283,7 @@ class Recorded( CMPRecord, DBDataWrite ):
                  'commflagged':0,    'recgroup':'Default',   'seriesid':'',
                  'programid':'',     'lastmodified':'CURRENT_TIMESTAMP',
                  'filesize':0,       'stars':0,              'previouslyshown':0,
-                 'preserve':0,       'bookmarkupdate':0,
+                 'preserve':0,       'bookmarkupdate':None,
                  'findid':0,         'deletepending':0,      'transcoder':0,
                  'timestretch':1,    'recpriority':0,        'playgroup':'Default',
                  'profile':'No',     'duplicate':1,          'transcoded':0,
diff --git a/mythtv/libs/libmythbase/lcddevice.cpp b/mythtv/libs/libmythbase/lcddevice.cpp
index f3924d912d..1ee9964351 100644
--- a/mythtv/libs/libmythbase/lcddevice.cpp
+++ b/mythtv/libs/libmythbase/lcddevice.cpp
@@ -77,6 +77,7 @@ LCD::LCD()
 
     connect(m_retryTimer, SIGNAL(timeout()),   this, SLOT(restartConnection()));
     connect(m_LEDTimer,   SIGNAL(timeout()),   this, SLOT(outputLEDs()));
+    connect(this, &LCD::sendToServer, this, &LCD::sendToServerSlot, Qt::QueuedConnection);
 }
 
 bool LCD::m_enabled = false;
@@ -204,13 +205,20 @@ bool LCD::connectToHost(const QString &lhostname, unsigned int lport)
     return m_connected;
 }
 
-void LCD::sendToServer(const QString &someText)
+void LCD::sendToServerSlot(const QString &someText)
 {
     QMutexLocker locker(&m_socketLock);
 
     if (!m_socket || !m_lcdReady)
         return;
 
+    if (m_socket->thread() != QThread::currentThread())
+    {
+        LOG(VB_GENERAL, LOG_ERR,
+            "Sending to LCDServer from wrong thread.");
+        return;
+    }
+
     // Check the socket, make sure the connection is still up
     if (QAbstractSocket::ConnectedState != m_socket->state())
     {
diff --git a/mythtv/libs/libmythbase/lcddevice.h b/mythtv/libs/libmythbase/lcddevice.h
index b6346ecf6a..c3247b4c93 100644
--- a/mythtv/libs/libmythbase/lcddevice.h
+++ b/mythtv/libs/libmythbase/lcddevice.h
@@ -293,10 +293,13 @@ class MBASE_PUBLIC LCD : public QObject
     void restartConnection();      // Try to re-establish the connection to
                                    // LCDServer every 10 seconds
     void outputLEDs();
+    void sendToServerSlot(const QString &someText);
+
+signals:
+    void sendToServer(const QString &someText);
 
   private:
     bool startLCDServer(void);
-    void sendToServer(const QString &someText);
     void init();
     void handleKeyPress(const QString &keyPressed);
     QString quotedString(const QString &string);
diff --git a/mythtv/libs/libmythbase/loggingserver.cpp b/mythtv/libs/libmythbase/loggingserver.cpp
index 4ebb705f62..15aafa2ef1 100644
--- a/mythtv/libs/libmythbase/loggingserver.cpp
+++ b/mythtv/libs/libmythbase/loggingserver.cpp
@@ -722,7 +722,7 @@ void DBLoggerThread::run(void)
             if (!item)
                 continue;
 
-            if (item->message()[0] != '\0')
+            if (item->message()[0] != QChar('\0'))
             {
                 qLock.unlock();
                 bool logged = m_logger->logqmsg(*query, item);
diff --git a/mythtv/libs/libmythtv/deletemap.cpp b/mythtv/libs/libmythtv/deletemap.cpp
index 1be1a02897..adf06c2f11 100644
--- a/mythtv/libs/libmythtv/deletemap.cpp
+++ b/mythtv/libs/libmythtv/deletemap.cpp
@@ -489,7 +489,8 @@ void DeleteMap::NewCut(uint64_t frame)
                 {
                     LOG(VB_PLAYBACK, LOG_INFO, LOC +
                         QString("Deleting bounded marker: %1").arg(otherframe));
-                    Delete(otherframe);
+                    it = m_deleteMap.erase(it);
+                    m_changed = true;
                 }
             }
         }
diff --git a/mythtv/libs/libmythtv/eitfixup.cpp b/mythtv/libs/libmythtv/eitfixup.cpp
index 6c664c92ad..28b9816cc2 100644
--- a/mythtv/libs/libmythtv/eitfixup.cpp
+++ b/mythtv/libs/libmythtv/eitfixup.cpp
@@ -2658,8 +2658,10 @@ void EITFixUp::FixGreekEIT(DBEventEIT &event) const
         bool ok;
         uint y = tmpRegEx.cap(1).toUInt(&ok);
         if (ok)
+        {
             event.originalairdate = QDate(y, 1, 1);
             event.description.replace(tmpRegEx, "");
+        }
     }
     // Remove white spaces
     event.description = event.description.trimmed();
diff --git a/mythtv/libs/libmythtv/eithelper.cpp b/mythtv/libs/libmythtv/eithelper.cpp
index 5b66988766..1369cab6c3 100644
--- a/mythtv/libs/libmythtv/eithelper.cpp
+++ b/mythtv/libs/libmythtv/eithelper.cpp
@@ -1085,16 +1085,17 @@ static void init_fixup(FixupMap &fix)
        fix[ (long long)i << 32 | 2U << 16] = EITFixUp::kFixUK;
     fix[ 2059LL << 32 | 2U << 16] = EITFixUp::kFixUK;
     fix[ 2061LL << 32 | 2U << 16] = EITFixUp::kFixUK;
-    fix[ 2063LL << 32 | 2U << 16] = EITFixUp::kFixUK;
-    fix[ 2064LL << 32 | 2U << 16] = EITFixUp::kFixUK;
-    fix[ 2066LL << 32 | 2U << 16] = EITFixUp::kFixUK;
-    fix[ 2068LL << 32 | 2U << 16] = EITFixUp::kFixUK;
-    fix[ 2069LL << 32 | 2U << 16] = EITFixUp::kFixUK;
+    for (int i = 2063; i <= 2069; ++i)
+       fix[ (long long)i << 32 | 2U << 16] = EITFixUp::kFixUK;
+    fix[ 2071LL << 32 | 2U << 16] = EITFixUp::kFixUK;
     fix[ 2076LL << 32 | 2U << 16] = EITFixUp::kFixUK;
     fix[ 2081LL << 32 | 2U << 16] = EITFixUp::kFixUK;
-    fix[ 2089LL << 32 | 2U << 16] = EITFixUp::kFixUK;
-    fix[ 2096LL << 32 | 2U << 16] = EITFixUp::kFixUK | EITFixUp::kFixHTML;
-    fix[ 2107LL << 32 | 2U << 16] = EITFixUp::kFixUK;
+    for (int i = 2089; i <= 2092; ++i)
+       fix[ (long long)i << 32 | 2U << 16] = EITFixUp::kFixUK;
+    for (int i = 2094; i <= 2099; ++i)
+       fix[ (long long)i << 32 | 2U << 16] = EITFixUp::kFixUK;
+    for (int i = 2102; i <= 2110; ++i)
+       fix[ (long long)i << 32 | 2U << 16] = EITFixUp::kFixUK;
     fix[ 2112LL << 32 | 2U << 16] = EITFixUp::kFixUK;
     fix[ 2116LL << 32 | 2U << 16] = EITFixUp::kFixUK;
     fix[ 2301LL << 32 | 2U << 16] = EITFixUp::kFixUK | EITFixUp::kFixHTML;
diff --git a/mythtv/libs/libmythtv/iptvtuningdata.h b/mythtv/libs/libmythtv/iptvtuningdata.h
index c5a3c2ea87..111052d6b9 100644
--- a/mythtv/libs/libmythtv/iptvtuningdata.h
+++ b/mythtv/libs/libmythtv/iptvtuningdata.h
@@ -97,7 +97,7 @@ class MTV_PUBLIC IPTVTuningData
         const QUrl u = GetDataURL();
         if (IsHLS())
             return QString("%1(%2)").arg(u.toString()).arg(GetBitrate(0));
-        if (IsHTTPTS())
+        if (IsHTTPTS() || IsRTSP())
             return QString("%1").arg(u.toString());
         return QString("%1:%2:%3")
             .arg(u.host()).arg(u.userInfo()).arg(u.port()).toLower();
diff --git a/mythtv/libs/libmythtv/mythavutil.cpp b/mythtv/libs/libmythtv/mythavutil.cpp
index afed323917..c69c4d279e 100644
--- a/mythtv/libs/libmythtv/mythavutil.cpp
+++ b/mythtv/libs/libmythtv/mythavutil.cpp
@@ -9,6 +9,7 @@
 #include "mythframe.h"
 #include "mythavutil.h"
 #include "mythcorecontext.h"
+#include "mythconfig.h"
 extern "C" {
 #include "libswscale/swscale.h"
 #include "libavfilter/avfilter.h"
@@ -161,8 +162,20 @@ int MythAVCopy::Copy(AVPicture *dst, AVPixelFormat dst_pix_fmt,
         return frameout.size;
     }
 
+    int new_width = width;
+#if ARCH_ARM
+    // The ARM build of FFMPEG has a bug that if sws_scale is
+    // called with source and dest sizes the same, and
+    // formats as shown below, it causes a bus error and the
+    // application core dumps. To avoid this I make a -1
+    // difference in the new width, causing it to bypass
+    // the code optimization which is failing.
+    if (pix_fmt == AV_PIX_FMT_YUV420P
+      && dst_pix_fmt == AV_PIX_FMT_BGRA)
+        new_width = width - 1;
+#endif
     d->swsctx = sws_getCachedContext(d->swsctx, width, height, pix_fmt,
-                                     width, height, dst_pix_fmt,
+                                     new_width, height, dst_pix_fmt,
                                      SWS_FAST_BILINEAR, NULL, NULL, NULL);
     if (d->swsctx == NULL)
     {
diff --git a/mythtv/libs/libmythupnp/mythxmlclient.cpp b/mythtv/libs/libmythupnp/mythxmlclient.cpp
index 45d7497fd9..c6fe011338 100644
--- a/mythtv/libs/libmythupnp/mythxmlclient.cpp
+++ b/mythtv/libs/libmythupnp/mythxmlclient.cpp
@@ -115,7 +115,9 @@ UPnPResultCode MythXMLClient::GetConnectionInfo( const QString &sPin, DatabasePa
 
     if (( nErrCode == UPnPResult_HumanInterventionRequired ) || 
         ( nErrCode == UPnPResult_ActionNotAuthorized       ) ||
-        ( nErrCode == 501                                  ))
+        ( nErrCode == 501                                  ) ||
+        // Not Authorized is generating invalid xml these days
+          nErrCode == UPnPResult_MythTV_XmlParseError )
     {
         // Service calls no longer return UPnPResult codes, 
         // convert standard 501 to UPnPResult code for now.
diff --git a/mythtv/libs/libmythupnp/soapclient.cpp b/mythtv/libs/libmythupnp/soapclient.cpp
index 4940e13d94..16748cf33e 100644
--- a/mythtv/libs/libmythupnp/soapclient.cpp
+++ b/mythtv/libs/libmythupnp/soapclient.cpp
@@ -267,9 +267,11 @@ QDomDocument SOAPClient::SendSOAPRequest(const QString &sMethod,
     list.clear();
 
     QDomDocument doc;
+    int ErrLineNum = 0;
 
-    if (!doc.setContent(sXml, true, &sErrDesc, &nErrCode))
+    if (!doc.setContent(sXml, true, &sErrDesc, &ErrLineNum))
     {
+        nErrCode = UPnPResult_MythTV_XmlParseError;
         LOG(VB_UPNP, LOG_ERR,
             QString("SendSOAPRequest( %1 ) - Invalid response from %2")
                 .arg(sMethod).arg(url.toString()) + 
diff --git a/mythtv/libs/libmythupnp/ssdp.cpp b/mythtv/libs/libmythupnp/ssdp.cpp
index cf54274220..d89e009bde 100644
--- a/mythtv/libs/libmythupnp/ssdp.cpp
+++ b/mythtv/libs/libmythupnp/ssdp.cpp
@@ -624,6 +624,10 @@ bool SSDP::ProcessSearchResponse( const QStringMap &headers )
     if (nPos < 0)
         return false;
 
+    // Ignore link local ip addresses
+    if (sDescURL.startsWith("http://[fe80::",Qt::CaseInsensitive))
+        return false;
+
     if ((nPos = sCache.indexOf("=", nPos)) < 0)
         return false;
 
diff --git a/mythtv/libs/libmythupnp/upnp.h b/mythtv/libs/libmythupnp/upnp.h
index 4b0457f4e8..acc2bd9ff7 100644
--- a/mythtv/libs/libmythupnp/upnp.h
+++ b/mythtv/libs/libmythupnp/upnp.h
@@ -80,6 +80,7 @@ typedef enum
     UPnPResult_MS_AccessDenied               = 801,
 
     UPnPResult_MythTV_NoNamespaceGiven       = 32001,
+    UPnPResult_MythTV_XmlParseError          = 32002,
 
 } UPnPResultCode;
 
diff --git a/mythtv/programs/mythfilldatabase/channeldata.cpp b/mythtv/programs/mythfilldatabase/channeldata.cpp
index c0ee522b65..9825c4e8d4 100644
--- a/mythtv/programs/mythfilldatabase/channeldata.cpp
+++ b/mythtv/programs/mythfilldatabase/channeldata.cpp
@@ -128,27 +128,31 @@ QString ChannelData::normalizeChannelKey(const QString &chanName) const
     return result;
 }
 
-QHash<QString, ChannelInfo> ChannelData::channelList(int sourceId)
+ChannelList ChannelData::channelList(int sourceId)
 {
-    QHash<QString, ChannelInfo> retList;
+    ChannelList retList;
 
-    ChannelInfoList channelList = ChannelUtil::GetChannels(sourceId, false);
+    uint avail = 0;
+    ChannelInfoList channelList = ChannelUtil::LoadChannels(0, 0, avail, false,
+                                                ChannelUtil::kChanOrderByChanNum,
+                                                ChannelUtil::kChanGroupByChanid,
+                                                sourceId);
 
     ChannelInfoList::iterator it = channelList.begin();
     for ( ; it != channelList.end(); ++it)
     {
         QString chanName = (*it).name;
         QString key  = normalizeChannelKey(chanName);
-        retList[key] = (*it);
+        retList.insert(key, *it);
     }
 
     return retList;
 }
 
 ChannelInfo ChannelData::FindMatchingChannel(const ChannelInfo &chanInfo,
-                            QHash<QString, ChannelInfo> existingChannels) const
+                                             ChannelList existingChannels) const
 {
-    QHash<QString, ChannelInfo>::iterator it;
+    ChannelList::iterator it;
     for (it = existingChannels.begin(); it != existingChannels.end(); ++it)
     {
         if ((*it).xmltvid == chanInfo.xmltvid)
@@ -158,6 +162,27 @@ ChannelInfo ChannelData::FindMatchingChannel(const ChannelInfo &chanInfo,
     QString searchKey = normalizeChannelKey(chanInfo.name);
     ChannelInfo existChan = existingChannels.value(searchKey);
 
+    if (existChan.chanid < 1)
+    {
+        // Check if it is ATSC
+        int chansep = chanInfo.channum.indexOf(QRegExp("\\D"));
+        if (chansep > 0)
+        {
+            // Populate xmltvid for scanned ATSC channels
+            uint major = chanInfo.channum.left(chansep).toInt();
+            uint minor = chanInfo.channum.right
+                         (chanInfo.channum.length() - (chansep + 1)).toInt();
+
+            for (it = existingChannels.begin();
+                 it != existingChannels.end(); ++it)
+            {
+                if ((*it).atsc_major_chan == major &&
+                    (*it).atsc_minor_chan == minor)
+                    return (*it);
+            }
+        }
+    }
+
     return existChan;
 }
 
@@ -169,7 +194,7 @@ void ChannelData::handleChannels(int id, ChannelInfoList *chanlist)
         return;
     }
 
-    QHash<QString, ChannelInfo> existingChannels = channelList(id);
+    ChannelList existingChannels = channelList(id);
     QString fileprefix = SetupIconCacheDirectory();
 
     QDir::setCurrent(fileprefix);
diff --git a/mythtv/programs/mythfilldatabase/channeldata.h b/mythtv/programs/mythfilldatabase/channeldata.h
index 978ec8c77b..af0aa1c04d 100644
--- a/mythtv/programs/mythfilldatabase/channeldata.h
+++ b/mythtv/programs/mythfilldatabase/channeldata.h
@@ -7,6 +7,8 @@
 // libmythtv
 #include "channelinfo.h"
 
+using ChannelList = QMultiHash<QString, ChannelInfo>;
+
 class ChannelData
 {
   public:
@@ -21,8 +23,8 @@ class ChannelData
                                          unsigned int chanid);
 
     ChannelInfo FindMatchingChannel(const ChannelInfo &chanInfo,
-                            QHash<QString, ChannelInfo> existingChannels) const;
-    QHash<QString, ChannelInfo> channelList(int sourceId);
+                            ChannelList existingChannels) const;
+    ChannelList channelList(int sourceId);
     QString normalizeChannelKey(const QString &chanName) const;
 
   public:
diff --git a/mythtv/programs/mythfilldatabase/xmltvparser.cpp b/mythtv/programs/mythfilldatabase/xmltvparser.cpp
index 62a3a13820..21bf5b8324 100644
--- a/mythtv/programs/mythfilldatabase/xmltvparser.cpp
+++ b/mythtv/programs/mythfilldatabase/xmltvparser.cpp
@@ -131,82 +131,107 @@ static void fromXMLTVDate(QString &timestr, QDateTime &dt)
         return;
     }
 
-    QStringList split = timestr.split(" ");
+    QStringList split = timestr.split(" ", QString::SkipEmptyParts);
     QString ts = split[0];
-    QDateTime tmpDT;
-    tmpDT.setTimeSpec(Qt::LocalTime);
-
-    // UTC/GMT, just strip
-    if (ts.endsWith('Z'))
-        ts.truncate(ts.length()-1);
-    
-    if (ts.length() == 14)
-    {
-        tmpDT = QDateTime::fromString(ts, "yyyyMMddHHmmss");
-    }
-    else if (ts.length() == 12)
-    {
-        tmpDT = QDateTime::fromString(ts, "yyyyMMddHHmm");
-    }
-    else if (ts.length() == 8)
-    {
-        tmpDT = QDateTime::fromString(ts, "yyyyMMdd");
-    }
-    else if (ts.length() == 6)
+    QDate tmpDate;
+    QTime tmpTime;
+    QString tzoffset;
+
+    // Process the TZ offset (if any)
+    if (split.size() > 1)
     {
-        tmpDT = QDateTime::fromString(ts, "yyyyMM");
+        tzoffset = split[1];
+        // These shouldn't be required and they aren't ISO 8601 but the
+        // xmltv spec mentions these and just these so handle them just in
+        // case
+        if (tzoffset == "GMT" || tzoffset == "UTC")
+            tzoffset = "+0000";
+        else if (tzoffset == "BST")
+            tzoffset = "+0100";
     }
-    else if (ts.length() == 4)
+    else
     {
-        tmpDT = QDateTime::fromString(ts, "yyyy");
+        // We will accept a datetime with a trailing Z as being explicit
+        if (ts.endsWith('Z'))
+        {
+            tzoffset = "+0000";
+            ts.truncate(ts.length()-1);
+        }
+        else
+        {
+            tzoffset = "+0000";
+            static bool warned_once_on_implicit_utc = false;
+            if (!warned_once_on_implicit_utc)
+            {
+                LOG(VB_XMLTV, LOG_WARNING, "No explicit time zone found, "
+                    "guessing implicit UTC! Please consider enhancing "
+                    "the guide source to provide explicit UTC or local "
+                    "time instead.");
+                warned_once_on_implicit_utc = true;
+            }
+        }
     }
 
-    if (!tmpDT.isValid())
+    // Process the date part
+    QString tsDate = ts.left(8);
+    if (tsDate.length() == 8)
+        tmpDate = QDate::fromString(tsDate, "yyyyMMdd");
+    else if (tsDate.length() == 6)
+        tmpDate = QDate::fromString(tsDate, "yyyyMM");
+    else if (tsDate.length() == 4)
+        tmpDate = QDate::fromString(tsDate, "yyyy");
+    if (!tmpDate.isValid())
     {
-        LOG(VB_GENERAL, LOG_ERR,
-            QString("Ignoring unknown timestamp format: %1")
-                .arg(ts));
+        LOG(VB_XMLTV, LOG_ERR,
+            QString("Invalid datetime (date) in XMLTV data, ignoring: %1")
+                .arg(timestr));
         return;
     }
-    
-    if (split.size() > 1)
+
+    // Process the time part (if any)
+    if (ts.length() > 8)
     {
-        QString tmp = split[1].trimmed();
-        
-        // These shouldn't be required and they aren't ISO 8601 but the
-        // xmltv spec mentions these and just these so handle them just in
-        // case
-        if (tmp == "GMT" || tmp == "UTC")
-            tmp = "+0000";
-        else if (tmp == "BST")
-            tmp = "+0100";
-        
-        // While this seems like a hack, it's better than what was done before
-        QString isoDateString = QString("%1 %2").arg(tmpDT.toString(Qt::ISODate))
-                                                .arg(tmp);
-        // Work around Qt bug where zero offset dates are flagged as LocalTime
-        tmpDT = QDateTime::fromString(isoDateString, Qt::ISODate);
-        if (tmpDT.timeSpec() == Qt::LocalTime)
-            tmpDT.setTimeSpec(Qt::UTC);
-        dt = tmpDT.toUTC();
+        QString tsTime = ts.mid(8);
+        if (tsTime.length() == 6)
+            tmpTime = QTime::fromString(tsTime, "HHmmss");
+        else if (tsTime.length() == 4)
+            tmpTime = QTime::fromString(tsTime, "HHmm");
+        else if (tsTime.length() == 2)
+            tmpTime = QTime::fromString(tsTime, "HH");
+        if (!tmpTime.isValid())
+        {
+            // Time part exists, but is (somehow) invalid
+            LOG(VB_XMLTV, LOG_ERR,
+                QString("Invalid datetime (time) in XMLTV data, ignoring: %1")
+                    .arg(timestr));
+            return;
+        }
     }
-    
-    if (!dt.isValid())
-    {
-        static bool warned_once_on_implicit_utc = false;
-        if (!warned_once_on_implicit_utc)
+
+    QDateTime tmpDT = QDateTime(tmpDate, tmpTime, Qt::UTC);
+    if (!tmpDT.isValid())
         {
-            LOG(VB_XMLTV, LOG_ERR, "No explicit time zone found, "
-                "guessing implicit UTC! Please consider enhancing "
-                "the guide source to provice explicit UTC or local "
-                "time instead.");
-            warned_once_on_implicit_utc = true;
+            LOG(VB_XMLTV, LOG_ERR,
+                QString("Invalid datetime (combination of date/time) "
+                    "in XMLTV data, ignoring: %1").arg(timestr));
+            return;
         }
-        dt = tmpDT;
+
+    // While this seems like a hack, it's better than what was done before
+    QString isoDateString = tmpDT.toString(Qt::ISODate);
+    if (isoDateString.endsWith('Z'))    // Should always be Z, but ...
+        isoDateString.truncate(isoDateString.length()-1);
+    isoDateString += tzoffset;
+    dt = QDateTime::fromString(isoDateString, Qt::ISODate).toUTC();
+
+    if (!dt.isValid())
+    {
+        LOG(VB_XMLTV, LOG_ERR,
+            QString("Invalid datetime (zone offset) in XMLTV data, "
+                "ignoring: %1").arg(timestr));
+        return;
     }
 
-    dt.setTimeSpec(Qt::UTC);
-    
     timestr = MythDate::toString(dt, MythDate::kFilename);
 }
 
@@ -277,8 +302,7 @@ static void parseAudio(QDomElement &element, ProgInfo *pginfo)
 
 ProgInfo *XMLTVParser::parseProgram(QDomElement &element)
 {
-    QString uniqueid, season, episode, totalepisodes;
-    int dd_progid_done = 0;
+    QString programid, season, episode, totalepisodes;
     ProgInfo *pginfo = new ProgInfo();
 
     QString text = element.attribute("start", "");
@@ -451,8 +475,11 @@ ProgInfo *XMLTVParser::parseProgram(QDomElement &element)
                     int idx = episodenum.indexOf('.');
                     if (idx != -1)
                         episodenum.remove(idx, 1);
-                    pginfo->programId = episodenum;
-                    dd_progid_done = 1;
+                    programid = episodenum;
+                    /* Only EPisodes and SHows are part of a series for SD */
+                    if (programid.startsWith(QString("EP")) ||
+                        programid.startsWith(QString("SH")))
+                        pginfo->seriesId = QString("EP") + programid.mid(2,8);
                 }
                 else if (info.attribute("system") == "xmltv_ns")
                 {
@@ -462,6 +489,7 @@ ProgInfo *XMLTVParser::parseProgram(QDomElement &element)
                     totalepisodes = episode.section('/',1,1).trimmed();
                     episode = episode.section('/',0,0).trimmed();
                     season = episodenum.section('.',0,0).trimmed();
+                    season = season.section('/',0,0).trimmed();
                     QString part(episodenum.section('.',2,2));
                     QString partnumber(part.section('/',0,0).trimmed());
                     QString parttotal(part.section('/',1,1).trimmed());
@@ -549,22 +577,20 @@ ProgInfo *XMLTVParser::parseProgram(QDomElement &element)
         && ProgramInfo::kCategorySeries != pginfo->categoryType)
         pginfo->airdate = current_year;
 
-    /* Let's build ourself a programid */
-    QString programid;
+    if (programid.isEmpty())
+    {
 
-    if (ProgramInfo::kCategoryMovie == pginfo->categoryType)
-        programid = "MV";
-    else if (ProgramInfo::kCategorySeries == pginfo->categoryType)
-        programid = "EP";
-    else if (ProgramInfo::kCategorySports == pginfo->categoryType)
-        programid = "SP";
-    else
-        programid = "SH";
+        /* Let's build ourself a programid */
+
+        if (ProgramInfo::kCategoryMovie == pginfo->categoryType)
+            programid = "MV";
+        else if (ProgramInfo::kCategorySeries == pginfo->categoryType)
+            programid = "EP";
+        else if (ProgramInfo::kCategorySports == pginfo->categoryType)
+            programid = "SP";
+        else
+            programid = "SH";
 
-    if (!uniqueid.isEmpty()) // we already have a unique id ready for use
-        programid.append(uniqueid);
-    else
-    {
         QString seriesid = QString::number(ELFHash(pginfo->title.toUtf8()));
         pginfo->seriesId = seriesid;
         programid.append(seriesid);
@@ -602,8 +628,8 @@ ProgInfo *XMLTVParser::parseProgram(QDomElement &element)
                 programid.clear();
         }
     }
-    if (dd_progid_done == 0)
-        pginfo->programId = programid;
+
+    pginfo->programId = programid;
 
     return pginfo;
 }
@@ -662,7 +688,21 @@ bool XMLTVParser::parseFile(
             {
                 ProgInfo *pginfo = parseProgram(e);
 
-                if (pginfo->startts == pginfo->endts)
+                if (!(pginfo->starttime.isValid()))
+                {
+                    LOG(VB_GENERAL, LOG_WARNING, QString("Invalid programme (%1), "
+                                                        "invalid start time, "
+                                                        "skipping")
+                                                        .arg(pginfo->title));
+                }
+                else if (pginfo->channel.isEmpty())
+                {
+                    LOG(VB_GENERAL, LOG_WARNING, QString("Invalid programme (%1), "
+                                                        "missing channel, "
+                                                        "skipping")
+                                                        .arg(pginfo->title));
+                }
+                else if (pginfo->startts == pginfo->endts)
                 {
                     LOG(VB_GENERAL, LOG_WARNING, QString("Invalid programme (%1), "
                                                         "identical start and end "
@@ -712,4 +752,3 @@ bool XMLTVParser::parseFile(
 
     return true;
 }
-
diff --git a/mythtv/programs/mythfrontend/proglist.cpp b/mythtv/programs/mythfrontend/proglist.cpp
index 37e4506130..ebd94c18a1 100644
--- a/mythtv/programs/mythfrontend/proglist.cpp
+++ b/mythtv/programs/mythfrontend/proglist.cpp
@@ -960,11 +960,11 @@ void ProgLister::FillViewList(const QString &view)
         m_viewTextList.push_back(tr("All"));
         m_viewList.push_back("= 0.0");
         m_viewTextList.push_back(tr("Unrated"));
-        m_viewList.push_back(QString("= 10.0"));
+        m_viewList.push_back(QString(">= %1").arg((10 - 0.5) / 10.0 - 0.001));
         m_viewTextList.push_back(tr("%n star(s)", "", 10));
         for (int i = 9; i > 0; i--)
         {
-            float stars = i / 10.0;
+            float stars = (i - 0.5 ) / 10.0 - 0.001;
             m_viewList.push_back(QString(">= %1").arg(stars));
             m_viewTextList.push_back(tr("%n star(s) and above", "", i));
         }