Files
harbour-calibreweb/src/opdsparser.cpp
T

124 lines
4.6 KiB
C++

#include "opdsparser.h"
#include <QStringList>
#include <QVariantMap>
#include <QXmlStreamReader>
static QString elementText(QXmlStreamReader &reader)
{
return reader.readElementText(QXmlStreamReader::IncludeChildElements).trimmed();
}
static QVariantMap parseEntry(QXmlStreamReader &reader)
{
QVariantMap entry;
QStringList authors;
QVariantList formats;
QString title;
QString summary;
QString id;
QString coverHref;
QString thumbHref;
QString navHref;
while (!reader.atEnd()) {
reader.readNext();
if (reader.tokenType() == QXmlStreamReader::EndElement
&& reader.name() == QLatin1String("entry"))
break;
if (reader.tokenType() != QXmlStreamReader::StartElement)
continue;
const QStringRef name = reader.name();
if (name == QLatin1String("title")) {
title = elementText(reader);
} else if (name == QLatin1String("id")) {
id = elementText(reader);
} else if (name == QLatin1String("name")) {
const QString author = elementText(reader);
if (!author.isEmpty())
authors.append(author);
} else if (name == QLatin1String("content") || name == QLatin1String("summary")) {
if (summary.isEmpty())
summary = elementText(reader);
} else if (name == QLatin1String("link")) {
const QXmlStreamAttributes attrs = reader.attributes();
const QString rel = attrs.value(QLatin1String("rel")).toString();
const QString href = attrs.value(QLatin1String("href")).toString();
const QString type = attrs.value(QLatin1String("type")).toString();
if (rel == QLatin1String("http://opds-spec.org/image")) {
coverHref = href;
} else if (rel == QLatin1String("http://opds-spec.org/image/thumbnail")) {
thumbHref = href;
} else if (rel == QLatin1String("http://opds-spec.org/acquisition")) {
QVariantMap format;
format.insert(QStringLiteral("format"), attrs.value(QLatin1String("title")).toString());
format.insert(QStringLiteral("mime"), type);
format.insert(QStringLiteral("size"), attrs.value(QLatin1String("length")).toString().toLongLong());
format.insert(QStringLiteral("url"), href);
formats.append(format);
} else if (rel == QLatin1String("subsection")) {
if (navHref.isEmpty())
navHref = href;
} else if (navHref.isEmpty() && type.contains(QLatin1String("opds-catalog"))) {
// calibre-web: i link di navigazione dell'indice non hanno rel="subsection"
navHref = href;
}
}
}
entry.insert(QStringLiteral("title"), title);
entry.insert(QStringLiteral("authors"), authors.join(QStringLiteral(", ")));
entry.insert(QStringLiteral("summary"), summary);
entry.insert(QStringLiteral("coverUrl"), !coverHref.isEmpty() ? coverHref : thumbHref);
entry.insert(QStringLiteral("formats"), formats);
entry.insert(QStringLiteral("id"), id);
entry.insert(QStringLiteral("isNavigation"), !navHref.isEmpty());
entry.insert(QStringLiteral("linkUrl"), navHref);
return entry;
}
bool OpdsParser::parse(const QByteArray &xml,
QVariantList *entries,
QString *nextUrl,
QString *feedTitle,
QString *errorMessage)
{
QXmlStreamReader reader(xml);
QVariantList result;
QString next;
QString title;
while (!reader.atEnd()) {
reader.readNext();
if (reader.tokenType() != QXmlStreamReader::StartElement)
continue;
const QStringRef name = reader.name();
if (name == QLatin1String("entry")) {
result.append(parseEntry(reader));
} else if (name == QLatin1String("link")) {
const QXmlStreamAttributes attrs = reader.attributes();
if (attrs.value(QLatin1String("rel")).toString() == QLatin1String("next"))
next = attrs.value(QLatin1String("href")).toString();
} else if (name == QLatin1String("title") && title.isEmpty()) {
title = elementText(reader);
}
}
if (reader.hasError() && result.isEmpty()) {
if (errorMessage)
*errorMessage = reader.errorString();
return false;
}
if (entries)
*entries = result;
if (nextUrl)
*nextUrl = next;
if (feedTitle)
*feedTitle = title;
return true;
}