Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Metadata: Parse XBMC-style NFO files.

XBMC has a XML NFO format that goes side-by-side files in media directories.  These XML files contain most of the basic metadata.  This commit adds basic support for parsing the metadata out of them.

I didn't implement everything in the format, yet, and I haven't turned it on for Television stuff (since the format is somewhat ugly in this regard-- there's one file for the series, and one for the episode.  I want to think a bit more about it.).  The format also doesn't implement all of the metadata *we* keep and pull in, but it does have the basics that people care about-- title, subtitle, year, season, episode, plot, inetref, etc.

I'll flesh out the parser a little more to cover cast, director, and other people, and maybe watched/unwatched status too.  Once I'm done with that I'll circle back and get it working for TV shows as well.  Most of the needed stuff is already in the parser, just need to combine the two sets of metadata in a way that makes sense.

Format documentation: http://wiki.xbmc.org/?title=Import_-_Export_Library
Hilarious logging censored by sphery.
  • Loading branch information...
commit 581175a90dc9b96232b00b9a36c7141a1ff558eb 1 parent 7f37123
Robert McNamara authored
View
2  mythtv/libs/libmythbase/mythversion.h
@@ -12,7 +12,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
-#define MYTH_BINARY_VERSION "0.25.20110628-2"
+#define MYTH_BINARY_VERSION "0.25.20110629-1"
/** \brief Increment this whenever the MythTV network protocol changes.
*
View
70 mythtv/libs/libmythmetadata/metadatacommon.cpp
@@ -15,6 +15,7 @@ MetadataLookup::MetadataLookup(void) :
m_allowoverwrites(false),
m_dvdorder(false),
m_host(),
+ m_filename(),
m_title(),
m_categories(),
m_userrating(0),
@@ -58,6 +59,7 @@ MetadataLookup::MetadataLookup(
bool allowoverwrites,
bool preferdvdorder,
QString host,
+ QString filename,
QString title,
const QStringList categories,
const float userrating,
@@ -98,6 +100,7 @@ MetadataLookup::MetadataLookup(
m_allowoverwrites(allowoverwrites),
m_dvdorder(preferdvdorder),
m_host(host),
+ m_filename(filename),
m_title(title),
m_categories(categories),
m_userrating(userrating),
@@ -152,6 +155,7 @@ ArtworkList MetadataLookup::GetArtwork(VideoArtworkType type) const
void MetadataLookup::toMap(MetadataMap &metadataMap)
{
+ metadataMap["filename"] = m_filename;
metadataMap["title"] = m_title;
metadataMap["category"] = m_categories.join(", ");
metadataMap["userrating"] = QString::number(m_userrating);
@@ -362,14 +366,74 @@ MetadataLookup* ParseMetadataItem(const QDomElement& item,
return new MetadataLookup(lookup->GetType(), lookup->GetData(),
lookup->GetStep(), lookup->GetAutomatic(), lookup->GetHandleImages(),
lookup->GetAllowOverwrites(), lookup->GetPreferDVDOrdering(),
- lookup->GetHost(), title, categories, userrating, language, subtitle,
- tagline, description, season, episode, certification, countries,
- popularity, budget, revenue, album, tracknum, system, year,
+ lookup->GetHost(), lookup->GetFilename(), title, categories,
+ userrating, language, subtitle, tagline, description,
+ season, episode, certification, countries, popularity,
+ budget, revenue, album, tracknum, system, year,
releasedate, lastupdated, runtime, runtimesecs, inetref,
tmsref, imdb, people, studios, homepage, trailerURL, artwork,
DownloadMap());
}
+MetadataLookup* ParseMetadataMovieNFO(const QDomElement& item,
+ MetadataLookup *lookup)
+{
+ if (!lookup)
+ return new MetadataLookup();
+
+ uint year = 0, runtime = 0, runtimesecs = 0,
+ season = 0, episode = 0;
+ QString title, subtitle, tagline, description,
+ inetref, trailer, certification;
+ float userrating = 0;
+ QDate releasedate;
+ QStringList categories;
+ PeopleMap people;
+ ArtworkMap artwork;
+
+ // Get the easy parses
+ QString titletmp;
+ if (item.tagName() == "movie")
+ title = Parse::UnescapeHTML(item.firstChildElement("title").text());
+ else if (item.tagName() == "episodedetails")
+ subtitle = Parse::UnescapeHTML(item.firstChildElement("title").text());
+ userrating = item.firstChildElement("rating").text().toFloat();
+ year = item.firstChildElement("year").text().toUInt();
+ season = item.firstChildElement("season").text().toUInt();
+ episode = item.firstChildElement("episode").text().toUInt();
+ description = Parse::UnescapeHTML(item.firstChildElement("plot").text());
+ tagline = Parse::UnescapeHTML(item.firstChildElement("tagline").text());
+ inetref = item.firstChildElement("id").text();
+ trailer = item.firstChildElement("trailer").text();
+ certification = item.firstChildElement("mpaa").text();
+ categories.append(item.firstChildElement("genre").text());
+
+ QString tmpDate = item.firstChildElement("releasedate").text();
+ if (!tmpDate.isEmpty())
+ releasedate = QDate::fromString(tmpDate, "yyyy-MM-dd");
+ else if (year > 0)
+ releasedate = QDate::fromString(QString::number(year), "yyyy");
+
+ runtime = item.firstChildElement("runtime").text()
+ .remove(QRegExp("[A-Za-z]"))
+ .trimmed().toUInt();
+ runtimesecs = runtime * 60;
+
+ return new MetadataLookup(lookup->GetType(), lookup->GetData(),
+ lookup->GetStep(), lookup->GetAutomatic(), lookup->GetHandleImages(),
+ lookup->GetAllowOverwrites(), lookup->GetPreferDVDOrdering(),
+ lookup->GetHost(), lookup->GetFilename(), title, categories,
+ userrating, QString() /*language*/, subtitle,
+ tagline, description, season, episode,
+ certification, QStringList() /*countries*/,
+ 0 /*popularity*/, 0 /*budget*/, 0 /*revenue*/, QString() /*album*/,
+ 0 /*tracknum*/, QString() /*system*/, year,
+ releasedate, QDateTime() /*lastupdated*/, runtime, runtimesecs,
+ inetref, QString() /*tmsref*/, QString() /*imdb*/, people,
+ QStringList() /*studios*/, QString() /*homepage*/, trailer, artwork,
+ DownloadMap());
+}
+
PeopleMap ParsePeople(QDomElement people)
{
PeopleMap ret;
View
6 mythtv/libs/libmythmetadata/metadatacommon.h
@@ -94,6 +94,7 @@ class META_PUBLIC MetadataLookup : public QObject
bool allowoverwrites,
bool preferdvdorder,
QString host,
+ QString filename,
QString title,
const QStringList categories,
const float userrating,
@@ -147,6 +148,7 @@ class META_PUBLIC MetadataLookup : public QObject
// General Sets
void SetTitle(QString title) { m_title = title; };
+ void SetFilename(QString filename) { m_filename = filename; };
// General Sets - Video
void SetSubtitle(QString subtitle) { m_subtitle = subtitle; };
@@ -176,6 +178,7 @@ class META_PUBLIC MetadataLookup : public QObject
bool GetAllowOverwrites() const { return m_allowoverwrites; };
// General
+ QString GetFilename() const { return m_filename; };
QString GetTitle() const { return m_title; };
QStringList GetCategories() const { return m_categories; };
float GetUserRating() const { return m_userrating; };
@@ -237,6 +240,7 @@ class META_PUBLIC MetadataLookup : public QObject
bool m_dvdorder;
QString m_host;
+ QString m_filename;
QString m_title;
const QStringList m_categories;
float m_userrating;
@@ -290,6 +294,8 @@ Q_DECLARE_METATYPE(MetadataLookup*)
META_PUBLIC MetadataLookup* ParseMetadataItem(const QDomElement& item,
MetadataLookup *lookup,
bool passseas = true);
+META_PUBLIC MetadataLookup* ParseMetadataMovieNFO(const QDomElement& item,
+ MetadataLookup *lookup);
META_PUBLIC PeopleMap ParsePeople(QDomElement people);
META_PUBLIC ArtworkMap ParseArtwork(QDomElement artwork);
View
141 mythtv/libs/libmythmetadata/metadatadownload.cpp
@@ -2,6 +2,7 @@
#include <QCoreApplication>
#include <QEvent>
#include <QDir>
+#include <QUrl>
// myth
#include "mythcorecontext.h"
@@ -10,6 +11,7 @@
#include "mythsystem.h"
#include "metadatadownload.h"
#include "util.h"
+#include "remotefile.h"
#include "mythlogging.h"
QEvent::Type MetadataLookupEvent::kEventType =
@@ -204,6 +206,67 @@ MetadataLookupList MetadataDownload::runGrabber(QString cmd, QStringList args,
return list;
}
+MetadataLookupList MetadataDownload::readNFO(QString NFOpath,
+ MetadataLookup* lookup)
+{
+ MetadataLookupList list;
+
+ VERBOSE(VB_GENERAL, QString("Matching NFO file found. "
+ "Parsing %1 for metadata...")
+ .arg(NFOpath));
+
+ if (lookup->GetType() == VID)
+ {
+ QByteArray nforaw;
+ QDomElement item;
+ if (NFOpath.startsWith("myth://"))
+ {
+ RemoteFile *rf = new RemoteFile(NFOpath);
+ if (rf && rf->Open())
+ {
+ bool loaded = rf->SaveAs(nforaw);
+ if (loaded)
+ {
+ QDomDocument doc;
+ if (doc.setContent(nforaw, true))
+ {
+ lookup->SetStep(GETDATA);
+ item = doc.documentElement();
+ }
+ else
+ VERBOSE(VB_GENERAL, QString("PIRATE ERROR: Invalid NFO file found."));
+ }
+ rf->Close();
+ }
+
+ delete rf;
+ rf = NULL;
+ }
+ else
+ {
+ QFile file(NFOpath);
+ if (file.open(QIODevice::ReadOnly))
+ {
+ nforaw = file.readAll();
+ QDomDocument doc;
+ if (doc.setContent(nforaw, true))
+ {
+ lookup->SetStep(GETDATA);
+ item = doc.documentElement();
+ }
+ else
+ VERBOSE(VB_GENERAL, QString("PIRATE ERROR: Invalid NFO file found."));
+ file.close();
+ }
+ }
+
+ MetadataLookup *tmp = ParseMetadataMovieNFO(item, lookup);
+ list.append(tmp);
+ }
+
+ return list;
+}
+
MetadataLookupList MetadataDownload::handleGame(MetadataLookup* lookup)
{
MetadataLookupList list;
@@ -245,35 +308,42 @@ MetadataLookupList MetadataDownload::handleMovie(MetadataLookup* lookup)
{
MetadataLookupList list;
- QString def_cmd = QDir::cleanPath(QString("%1/%2")
- .arg(GetShareDir())
- .arg("metadata/Movie/tmdb.py"));
+ QString nfo = getNFOPath(lookup->GetFilename());
- QString cmd = gCoreContext->GetSetting("MovieGrabber", def_cmd);
+ if (nfo.isEmpty())
+ {
+ QString def_cmd = QDir::cleanPath(QString("%1/%2")
+ .arg(GetShareDir())
+ .arg("metadata/Movie/tmdb.py"));
- QStringList args;
- args.append(QString("-l")); // Language Flag
- args.append(gCoreContext->GetLanguage()); // UI Language
+ QString cmd = gCoreContext->GetSetting("MovieGrabber", def_cmd);
- // If the inetref is populated, even in search mode,
- // become a getdata grab and use that.
- if (lookup->GetStep() == SEARCH &&
- (!lookup->GetInetref().isEmpty() &&
- lookup->GetInetref() != "00000000"))
- lookup->SetStep(GETDATA);
+ QStringList args;
+ args.append(QString("-l")); // Language Flag
+ args.append(gCoreContext->GetLanguage()); // UI Language
- if (lookup->GetStep() == SEARCH)
- {
- args.append(QString("-M"));
- QString title = lookup->GetTitle();
- args.append(ShellEscape(title));
- }
- else if (lookup->GetStep() == GETDATA)
- {
- args.append(QString("-D"));
- args.append(lookup->GetInetref());
+ // If the inetref is populated, even in search mode,
+ // become a getdata grab and use that.
+ if (lookup->GetStep() == SEARCH &&
+ (!lookup->GetInetref().isEmpty() &&
+ lookup->GetInetref() != "00000000"))
+ lookup->SetStep(GETDATA);
+
+ if (lookup->GetStep() == SEARCH)
+ {
+ args.append(QString("-M"));
+ QString title = lookup->GetTitle();
+ args.append(ShellEscape(title));
+ }
+ else if (lookup->GetStep() == GETDATA)
+ {
+ args.append(QString("-D"));
+ args.append(lookup->GetInetref());
+ }
+ list = runGrabber(cmd, args, lookup);
}
- list = runGrabber(cmd, args, lookup);
+ else
+ list = readNFO(nfo, lookup);
return list;
}
@@ -351,3 +421,26 @@ MetadataLookupList MetadataDownload::handleVideoUndetermined(
return list;
}
+QString MetadataDownload::getNFOPath(QString filename)
+{
+ QString ret;
+ QString nfoname;
+ QUrl qurl(filename);
+ QString ext = QFileInfo(qurl.path()).suffix();
+ nfoname = filename.left(filename.size() - ext.size()) + "nfo";
+
+ VERBOSE(VB_GENERAL, QString("NFOName = %1 ").arg(nfoname));
+
+ if (nfoname.startsWith("myth://"))
+ {
+ if (RemoteFile::Exists(nfoname))
+ ret = nfoname;
+ }
+ else
+ {
+ if (QFile::exists(nfoname))
+ ret = nfoname;
+ }
+
+ return ret;
+}
View
3  mythtv/libs/libmythmetadata/metadatadownload.h
@@ -48,6 +48,8 @@ class META_PUBLIC MetadataDownload : public QThread
void run();
+ QString getNFOPath(QString filename);
+
private:
// Video handling
MetadataLookupList handleMovie(MetadataLookup* lookup);
@@ -61,6 +63,7 @@ class META_PUBLIC MetadataDownload : public QThread
MetadataLookupList runGrabber(QString cmd, QStringList args,
MetadataLookup* lookup,
bool passseas = true);
+ MetadataLookupList readNFO(QString NFOpath, MetadataLookup* lookup);
MetadataLookup* moreWork();
QObject *m_parent;
View
7 mythtv/programs/mythfrontend/videodlg.cpp
@@ -3578,6 +3578,13 @@ void VideoDialog::VideoSearch(MythGenericTree *node,
lookup->SetSeason(metadata->GetSeason());
lookup->SetEpisode(metadata->GetEpisode());
lookup->SetInetref(metadata->GetInetRef());
+ QString fntmp;
+ if (metadata->GetHost().isEmpty())
+ fntmp = metadata->GetFilename();
+ else
+ fntmp = generate_file_url("Videos", metadata->GetHost(),
+ metadata->GetFilename());
+ lookup->SetFilename(fntmp);
if (m_query->isRunning())
m_query->prependLookup(lookup);
else
Please sign in to comment.
Something went wrong with that request. Please try again.