Skip to content

Commit

Permalink
PlaybackBox: Remove Image Hunt in favor of user-selected artwork.
Browse files Browse the repository at this point in the history
(and incur the ire of those who think the image hunt is "good enough")

http://www.mythtv.org/wiki/Enhancing_Recordings_with_Metadata_Lookup#Picking_Artwork_for_Your_Recording_Rules

As documented above, remove the costly, slow image hunt and instead allow the user to assign exactly the images they want, to exactly which recording rules, and even to particular seasons within that rule.

I will work on ways to pre-populate recording rules in the coming days.  Possibly a one-time set of image hunts in mythmetadatalookup that fills the recordedartwork table.
  • Loading branch information
Robert McNamara committed Jul 12, 2011
1 parent 834e958 commit 8911af5
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 214 deletions.
68 changes: 31 additions & 37 deletions mythtv/programs/mythfrontend/playbackbox.cpp
Expand Up @@ -164,8 +164,6 @@ static bool comp_recordDate_rev_less_than(
return comp_recordDate_rev(a, b) < 0;
}

static const ArtworkType s_artType[] =
{ kArtworkFan, kArtworkBanner, kArtworkCover, };
static const uint s_artDelay[] =
{ kArtworkFanTimeout, kArtworkBannerTimeout, kArtworkCoverTimeout,};

Expand Down Expand Up @@ -489,9 +487,9 @@ bool PlaybackBox::Create()
m_noRecordingsText = dynamic_cast<MythUIText *> (GetChild("norecordings"));

m_previewImage = dynamic_cast<MythUIImage *>(GetChild("preview"));
m_artImage[kArtworkFan] = dynamic_cast<MythUIImage*>(GetChild("fanart"));
m_artImage[kArtworkBanner] = dynamic_cast<MythUIImage*>(GetChild("banner"));
m_artImage[kArtworkCover]= dynamic_cast<MythUIImage*>(GetChild("coverart"));
m_artImage[FANART] = dynamic_cast<MythUIImage*>(GetChild("fanart"));
m_artImage[BANNER] = dynamic_cast<MythUIImage*>(GetChild("banner"));
m_artImage[COVERART]= dynamic_cast<MythUIImage*>(GetChild("coverart"));

if (!m_recordingList || !m_groupList)
{
Expand All @@ -515,9 +513,9 @@ bool PlaybackBox::Create()
SLOT(ItemVisible(MythUIButtonListItem*)));

// connect up timers...
connect(m_artTimer[kArtworkFan], SIGNAL(timeout()), SLOT(fanartLoad()));
connect(m_artTimer[kArtworkBanner],SIGNAL(timeout()), SLOT(bannerLoad()));
connect(m_artTimer[kArtworkCover], SIGNAL(timeout()), SLOT(coverartLoad()));
connect(m_artTimer[FANART], SIGNAL(timeout()), SLOT(fanartLoad()));
connect(m_artTimer[BANNER], SIGNAL(timeout()), SLOT(bannerLoad()));
connect(m_artTimer[COVERART], SIGNAL(timeout()), SLOT(coverartLoad()));

BuildFocusList();
m_programInfoCache.ScheduleLoad(false);
Expand Down Expand Up @@ -622,32 +620,29 @@ void PlaybackBox::updateGroupInfo(const QString &groupname,
infoMap["show"] = grouplabel;
}

if (m_artImage[kArtworkFan])
if (m_artImage[FANART])
{
if (!groupname.isEmpty() && !m_progLists[groupname].empty())
{
ProgramInfo *pginfo = *m_progLists[groupname].begin();
QString arthost((!m_artHostOverride.isEmpty()) ?
m_artHostOverride : pginfo->GetHostname());

QString artworkSeriesID = "_GROUP_";
QString fn = m_helper.LocateArtwork(
artworkSeriesID, groupname, kArtworkFan, arthost, NULL);
pginfo->GetInetRef(), pginfo->GetSeason(), FANART, NULL, groupname);

if (fn.isEmpty())
{
m_artTimer[kArtworkFan]->stop();
m_artImage[kArtworkFan]->Reset();
m_artTimer[FANART]->stop();
m_artImage[FANART]->Reset();
}
else if (m_artImage[kArtworkFan]->GetFilename() != fn)
else if (m_artImage[FANART]->GetFilename() != fn)
{
m_artImage[kArtworkFan]->SetFilename(fn);
m_artTimer[kArtworkFan]->start(kArtworkFanTimeout);
m_artImage[FANART]->SetFilename(fn);
m_artTimer[FANART]->start(kArtworkFanTimeout);
}
}
else
{
m_artImage[kArtworkFan]->Reset();
m_artImage[FANART]->Reset();
}
}

Expand Down Expand Up @@ -696,11 +691,11 @@ void PlaybackBox::updateGroupInfo(const QString &groupname,
if (m_previewImage)
m_previewImage->Reset();

if (m_artImage[kArtworkBanner])
m_artImage[kArtworkBanner]->Reset();
if (m_artImage[BANNER])
m_artImage[BANNER]->Reset();

if (m_artImage[kArtworkCover])
m_artImage[kArtworkCover]->Reset();
if (m_artImage[COVERART])
m_artImage[COVERART]->Reset();

updateIcons();
}
Expand Down Expand Up @@ -847,8 +842,8 @@ void PlaybackBox::UpdateUIListItem(
}

QString fn = m_helper.LocateArtwork(
pginfo->GetSeriesID(), pginfo->GetTitle(),
s_artType[i], arthost, pginfo);
pginfo->GetInetRef(), pginfo->GetSeason(),
(VideoArtworkType)i, pginfo);

if (fn.isEmpty())
{
Expand Down Expand Up @@ -2442,17 +2437,17 @@ void PlaybackBox::RemoveProgram(

void PlaybackBox::fanartLoad(void)
{
m_artImage[kArtworkFan]->Load();
m_artImage[FANART]->Load();
}

void PlaybackBox::bannerLoad(void)
{
m_artImage[kArtworkBanner]->Load();
m_artImage[BANNER]->Load();
}

void PlaybackBox::coverartLoad(void)
{
m_artImage[kArtworkCover]->Load();
m_artImage[COVERART]->Load();
}

void PlaybackBox::ShowDeletePopup(DeletePopupType type)
Expand Down Expand Up @@ -4116,15 +4111,14 @@ void PlaybackBox::customEvent(QEvent *event)
if (info)
info->SetPathname(me->ExtraData(1));
}
else if ((message == "FOUND_ARTWORK") && (me->ExtraDataCount() >= 6))
else if ((message == "FOUND_ARTWORK") && (me->ExtraDataCount() >= 5))
{
QString seriesid = me->ExtraData(0);
QString groupname = me->ExtraData(1);
ArtworkType type = (ArtworkType) me->ExtraData(2).toInt();
QString pikey = me->ExtraData(4);
QString fn = me->ExtraData(5);
VideoArtworkType type = (VideoArtworkType) me->ExtraData(2).toInt();
QString pikey = me->ExtraData(3);
QString group = me->ExtraData(4);
QString fn = me->ExtraData(5);

if (seriesid != "_GROUP_" && !pikey.isEmpty())
if (!pikey.isEmpty())
{
ProgramInfo *pginfo = m_programInfoCache.GetProgramInfo(pikey);
if (pginfo &&
Expand All @@ -4136,8 +4130,8 @@ void PlaybackBox::customEvent(QEvent *event)
m_artTimer[(uint)type]->start(s_artDelay[(uint)type]);
}
}
else if (seriesid == "_GROUP_" && !groupname.isEmpty() &&
(m_currentGroup == groupname) &&
else if (!group.isEmpty() &&
(m_currentGroup == group) &&
m_artImage[type] &&
m_groupList->GetItemCurrent() &&
m_artImage[(uint)type]->GetFilename() != fn)
Expand Down
186 changes: 22 additions & 164 deletions mythtv/programs/mythfrontend/playbackboxhelper.cpp
Expand Up @@ -8,6 +8,7 @@ using namespace std;
#include <QDir>

#include "previewgeneratorqueue.h"
#include "metadataimagehelper.h"
#include "playbackboxhelper.h"
#include "mythcorecontext.h"
#include "tvremoteutil.h"
Expand All @@ -22,52 +23,6 @@ using namespace std;
#define LOC_WARN QString("PlaybackBoxHelper Warning: ")
#define LOC_ERR QString("PlaybackBoxHelper Error: ")

QString toString(ArtworkType t)
{
switch (t)
{
case kArtworkFan: return "fanart";
case kArtworkBanner: return "banner";
case kArtworkCover: return "coverart";
}
return QString();
}

QString toLocalDir(ArtworkType t)
{
static QMutex m;
static bool initrun = false;
static QString kFanDir, kBannerDir, kCoverDir;

QMutexLocker locker(&m);
if (!initrun)
{
kFanDir = gCoreContext->GetSetting("mythvideo.fanartDir");
kBannerDir = gCoreContext->GetSetting("mythvideo.bannerDir");
kCoverDir = gCoreContext->GetSetting("VideoArtworkDir");
initrun = true;
}

switch (t)
{
case kArtworkFan: return kFanDir;
case kArtworkBanner: return kBannerDir;
case kArtworkCover: return kCoverDir;
}
return QString();
}

QString toSG(ArtworkType t)
{
switch (t)
{
case kArtworkFan: return "Fanart";
case kArtworkBanner: return "Banners";
case kArtworkCover: return "Coverart";
}
return QString();
}

class PBHEventHandler : public QObject
{
public:
Expand Down Expand Up @@ -311,121 +266,23 @@ bool PBHEventHandler::event(QEvent *e)
}
else if (me->Message() == "LOCATE_ARTWORK")
{
QString seriesid = me->ExtraData(0);
QString title = me->ExtraData(1);
const ArtworkType type = (ArtworkType)me->ExtraData(2).toInt();
const QString host = me->ExtraData(3);
const QString sgroup = toSG(type);
const QString localDir = toLocalDir(type);
const QString cacheKey = QString("%1:%2:%3")
.arg((int)type).arg(seriesid).arg(title);

seriesid = (seriesid == "_GROUP_") ? QString() : seriesid;

// Attempts to match image file in specified directory.
// Falls back like this:
//
// Pushing Daisies 5.png
// PushingDaisies5.png
// PushingDaisiesSeason5.png
// Pushing Daisies Season 5 Episode 1.png
// PuShinG DaisIES s05e01.png
// etc. (you get it)
//
// Or any permutation thereof including -,_, or . instead of space
// Then, match by seriesid (for future PBB grabber):
//
// EP0012345.png
//
// Then, as a final fallback, match just title
//
// Pushing Daisies.png (or Pushing_Daisies.png, etc.)
//
// All this allows for grabber to grab an image with format:
//
// Title SeasonNumber.ext or Title SeasonNum # Epnum #.ext
// or SeriesID.ext or Title.ext (without caring about cases,
// spaces, dashes, periods, or underscores)

QDir dir(localDir);
dir.setSorting(QDir::Name | QDir::Reversed | QDir::IgnoreCase);

QStringList entries = dir.entryList();
QString grpHost = sgroup + ":" + host;

if (!m_fileListCache.contains(grpHost))
{
QStringList sgEntries;
RemoteGetFileList(host, "", &sgEntries, sgroup, true);
m_fileListCache[grpHost] = sgEntries;
}

title.replace(' ', "(?:\\s|-|_|\\.)?");
QString regs[] = {
QString("%1" // title
"(?:\\s|-|_|\\.)?" // optional separator
"(?:" // begin optional Season portion
"S(?:eason)?" // optional "S" or "Season"
"(?:\\s|-|_|\\.)?" // optional separator
"[0-9]{1,3}" // number
")?" // end optional Season portion
"(?:" // begin optional Episode portion
"(?:\\s|-|_|\\.)?" // optional separator
"(?:x?" // optional "x"
"(?:\\s|-|_|\\.)?" // optional separator
"(?:E(?:pisode)?)?" // optional "E" or "Episode"
"(?:\\s|-|_|\\.)?)?" // optional separator
"[0-9]{1,3}" // number portion of
// optional Episode portion
")?" // end optional Episode portion
"(?:_%2)?" // optional Suffix portion
"\\.(?:png|gif|jpg)" // file extension
).arg(title).arg(toString(type)),
QString("%1_%2\\.(?:png|jpg|gif)")
.arg(seriesid).arg(toString(type)),
QString("%1\\.(?:png|jpg|gif)").arg(seriesid),
};

QString foundFile;
for (uint i = 0; i < sizeof(regs) / sizeof(QString); i++)
{
QRegExp re(regs[i], Qt::CaseInsensitive);
QString inetref = me->ExtraData(0);
uint season = me->ExtraData(1).toUInt();
const VideoArtworkType type = (VideoArtworkType)me->ExtraData(2).toInt();
const QString pikey = me->ExtraData(3);
const QString group = me->ExtraData(4);
const QString cacheKey = QString("%1:%2:%3")
.arg((int)type).arg(inetref).arg(season);

for (QStringList::const_iterator it = entries.begin();
it != entries.end(); ++it)
{
if (re.exactMatch(*it))
{
foundFile = *it;
break;
}
}
ArtworkMap map = GetArtwork(inetref, season);

for (QStringList::const_iterator it =
m_fileListCache[grpHost].begin();
it != m_fileListCache[grpHost].end(); ++it)
{
if (!re.exactMatch(*it))
continue;
foundFile = gCoreContext->GenMythURL(
gCoreContext->GetSettingOnHost("BackendServerIP", host),
gCoreContext->GetSettingOnHost("BackendServerPort", host).toInt(),
*it,
StorageGroup::GetGroupToUse(host, sgroup));

break;
}
}
ArtworkInfo info = map.value(type);

if (!foundFile.isEmpty())
{
if (localDir.endsWith("/"))
localDir.left(localDir.length()-1);
if (!foundFile.startsWith("myth://"))
foundFile = QString("%1/%2").arg(localDir).arg(foundFile);
}
QString foundFile;

if (!info.url.isEmpty())
{
foundFile = info.url;
QMutexLocker locker(&m_pbh.m_lock);
m_pbh.m_artworkFilenameCache[cacheKey] = foundFile;
}
Expand Down Expand Up @@ -577,12 +434,13 @@ void PlaybackBoxHelper::CheckAvailability(
}

QString PlaybackBoxHelper::LocateArtwork(
const QString &seriesid, const QString &title,
ArtworkType type, const QString &host,
const ProgramInfo *pginfo)
const QString &inetref, uint season,
const VideoArtworkType type,
const ProgramInfo *pginfo,
const QString &groupname)
{
QString cacheKey = QString("%1:%2:%3")
.arg((int)type).arg(seriesid).arg(title);
.arg((int)type).arg(inetref).arg(season);

QMutexLocker locker(&m_lock);

Expand All @@ -592,11 +450,11 @@ QString PlaybackBoxHelper::LocateArtwork(
if (it != m_artworkFilenameCache.end())
return *it;

QStringList list(seriesid);
list.push_back(title);
list.push_back(QString::number((int)type));
list.push_back(host);
QStringList list(inetref);
list.push_back(QString::number(season));
list.push_back(QString::number(type));
list.push_back((pginfo)?pginfo->MakeUniqueKey():"");
list.push_back(groupname);
MythEvent *e = new MythEvent("LOCATE_ARTWORK", list);
QCoreApplication::postEvent(m_eventHandler, e);

Expand Down

0 comments on commit 8911af5

Please sign in to comment.