Index: programs/mythfrontend/playbackbox.cpp
===================================================================
--- programs/mythfrontend/playbackbox.cpp	(revision 26451)
+++ programs/mythfrontend/playbackbox.cpp	(working copy)
@@ -784,9 +784,18 @@
 
     item->DisplayState(rating, "ratingstate");
 
-    QString oldimgfile = item->GetImage("preview");
+    // If there is no preview image, load it.
+    QString oldimgfile = GetLoadedPreview(*pginfo);
     if (oldimgfile.isEmpty() || force_preview_reload)
         m_preview_tokens.insert(m_helper.GetPreviewImage(*pginfo));
+    // Try to set preview image
+    if (oldimgfile.isEmpty())
+        oldimgfile = GetStalePreview(*pginfo);
+    if (item->GetImage("preview").isEmpty())
+    {
+        if (!oldimgfile.isEmpty())
+            item->SetImage(oldimgfile, "preview", false); 
+    }
 
     if ((GetFocusWidget() == m_recordingList) && is_sel)
     {
@@ -810,7 +819,7 @@
         if (m_previewImage)
         {
             m_previewImage->SetFilename(oldimgfile);
-            m_previewImage->Load(true, true);
+            m_previewImage->Load(false, false);
         }
 
         // Handle artwork
@@ -849,33 +858,103 @@
 void PlaybackBox::ItemVisible(MythUIButtonListItem *item)
 {
     ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
+    if (!pginfo)
+        return;
 
     // Job status (recording, transcoding, flagging)
     QString job = extract_job_state(*pginfo);
     item->DisplayState(job, "jobstate");
 
     MythUIButtonListItem *sel_item = item->parent()->GetItemCurrent();
-    if ((item != sel_item) && pginfo && item->GetImage("preview").isEmpty() &&
-        (asAvailable == pginfo->GetAvailableStatus()))
+    if (item == sel_item)
+        return;
+
+    if ((asAvailable == pginfo->GetAvailableStatus()) &&
+        GetLoadedPreview(*pginfo).isEmpty())
     {
         QString token = m_helper.GetPreviewImage(*pginfo, true);
-        if (token.isEmpty())
-            return;
-
-        m_preview_tokens.insert(token);
-        // now make sure selected item is still at the top of the queue
-        ProgramInfo *sel_pginfo =
-            qVariantValue<ProgramInfo*>(sel_item->GetData());
-        if (sel_pginfo && sel_item->GetImage("preview").isEmpty() &&
-            (asAvailable == sel_pginfo->GetAvailableStatus()))
+        if (!token.isEmpty())
         {
-            m_preview_tokens.insert(
-                m_helper.GetPreviewImage(*sel_pginfo, false));
+            m_preview_tokens.insert(token);
+            // now make sure selected item is still at the top of the queue
+            ProgramInfo *sel_pginfo =
+                qVariantValue<ProgramInfo*>(sel_item->GetData());
+            if (sel_pginfo && GetLoadedPreview(*sel_pginfo).isEmpty() &&
+                (asAvailable == sel_pginfo->GetAvailableStatus()))
+            {
+                m_preview_tokens.insert(
+                    m_helper.GetPreviewImage(*sel_pginfo, false));
+            }
         }
     }
+
+    if (item->GetImage("preview").isEmpty())
+    {
+        QString cachedPreview = GetStalePreview(*pginfo);
+        if (!cachedPreview.isEmpty())
+            item->SetImage(cachedPreview, "preview", true);
+    }
 }
 
+/** \brief Returns a relatively up to date preview file name if available.
+ *  This will only be returned after the preview generator hands us this
+ *  preview file as an up to date preview file. This returns an empty string
+ *  when not available.
+ *  \sa GetStalePreview()
+ */
+QString PlaybackBox::GetLoadedPreview(const ProgramInfo &pginfo) const
+{
+    PreviewCache::const_iterator it =
+        m_previewCache.find(pginfo.MakeUniqueKey());
+    return (it == m_previewCache.end()) ? QString() :
+        ((*it).left(6) == "cache:") ? QString() : *it;
+}
 
+/** \brief Returns the most up to date preview we have in local storage.
+ *  This image may be quite stale, as another frontent may have changed
+ *  the file or the bookmarks since the last time it was shown on screen
+ *  on this frontend. This is meant as a temporary placeholder image.
+ *  \sa GetLoadedPreview()
+ */
+QString PlaybackBox::GetStalePreview(const ProgramInfo &pginfo) const
+{
+    QString key = pginfo.MakeUniqueKey();
+    PreviewCache::const_iterator it = m_previewCache.find(key);
+    QString ret;
+    if (it != m_previewCache.end())
+        ret = ((*it).left(6) == "cache:") ? (*it).mid(6) : *it;
+    if (ret.left(12) == "<NOT_CACHED>")
+        return QString();
+    else if (ret.length())
+    {
+        VERBOSE(VB_IMPORTANT, QString("GetStalePreview() 1 -> '%1'")
+                .arg(ret));
+        return ret;
+    }
+
+    QString preview;
+    QString remotecachedirname = QString("%1/remotecache").arg(GetConfDir());
+    QDir remotecachedir(remotecachedirname);
+    if (remotecachedir.exists())
+    {
+        QString filename = QString("%1/%2")
+            .arg(remotecachedirname)
+            .arg(pginfo.GetBasename() + ".png");
+        if (QFileInfo(filename).isReadable())
+            preview = filename;
+    }
+
+    ret = m_previewCache[key] = QString("cache:") +
+        ((preview.isEmpty()) ? QString("<NOT_CACHED>") : preview);
+    ret = (ret.left(6) == "cache:") ? (ret).mid(6) : ret;
+
+    if (ret.left(12) != "<NOT_CACHED>")
+        VERBOSE(VB_IMPORTANT, QString("GetStalePreview() 2 -> '%1'")
+                .arg(ret));
+
+    return (ret.left(12) == "<NOT_CACHED>") ? QString() : ret;
+}
+
 /** \brief Updates the UI properties for a new preview file.
  *  This first update the image property of the MythUIButtonListItem
  *  with the new preview file, then if it is selected and there is
@@ -946,6 +1025,8 @@
                 QString("Loading preview %1,\n\t\t\tmsg %2")
                 .arg(previewFile).arg(message));
 
+        m_previewCache[info->MakeUniqueKey()] = previewFile;
+
         item->SetImage(previewFile, "preview", true);
 
         if ((GetFocusWidget() == m_recordingList) &&
Index: programs/mythfrontend/playbackboxhelper.cpp
===================================================================
--- programs/mythfrontend/playbackboxhelper.cpp	(revision 26451)
+++ programs/mythfrontend/playbackboxhelper.cpp	(working copy)
@@ -602,6 +602,9 @@
 QString PlaybackBoxHelper::GetPreviewImage(
     const ProgramInfo &pginfo, bool check_availability)
 {
+    VERBOSE(VB_IMPORTANT, QString("GetPreviewImage(%1)")
+            .arg(pginfo.GetBasename()));
+
     if (!check_availability && pginfo.GetAvailableStatus() != asAvailable)
         return QString();
 
Index: programs/mythfrontend/playbackbox.h
===================================================================
--- programs/mythfrontend/playbackbox.h	(revision 26451)
+++ programs/mythfrontend/playbackbox.h	(working copy)
@@ -45,6 +45,7 @@
 class MythDialogBox;
 
 typedef QMap<QString,ProgramList>       ProgramMap;
+typedef QMap<QString,QString>           PreviewCache;
 typedef QMap<QString,QString>           Str2StrMap;
 
 enum {
@@ -327,6 +328,9 @@
 
     QString CreateProgramInfoString(const ProgramInfo &program) const;
 
+    QString GetLoadedPreview(const ProgramInfo &pginfo) const;
+    QString GetStalePreview(const ProgramInfo &pginfo) const;
+
   private:
     QRegExp m_prefixes;   ///< prefixes to be ignored when sorting
     QRegExp m_titleChaff; ///< stuff to remove for search rules
@@ -398,6 +402,7 @@
     // Main Recording List support
     QStringList         m_titleList;  ///< list of pages
     ProgramMap          m_progLists;  ///< lists of programs by page
+    mutable PreviewCache m_previewCache;
     int                 m_progsInDB;  ///< total number of recordings in DB
     bool                m_isFilling;
 
