[office/tellico] /: Remove Allocine data source

Robby Stephenson null at kde.org
Sat Feb 17 01:36:20 GMT 2024


Git commit a01a0c9cacbba48b7872e37d906cef31e9523dfa by Robby Stephenson.
Committed on 17/02/2024 at 01:36.
Pushed by rstephenson into branch 'master'.

Remove Allocine data source

API has been discontinued

M  +4    -0    ChangeLog
M  +0    -8    doc/configuration.docbook
M  +0    -1    src/fetch/CMakeLists.txt
D  +0    -516  src/fetch/allocinefetcher.cpp
D  +0    -134  src/fetch/allocinefetcher.h
M  +1    -1    src/fetch/fetch.h
M  +0    -2    src/fetch/fetcherinitializer.cpp
M  +0    -2    src/fetch/fetchmanager.cpp
M  +0    -2    src/fetch/scripts/CMakeLists.txt
D  +0    -475  src/fetch/scripts/fr.allocine.py
D  +0    -38   src/fetch/scripts/fr.allocine.py.spec
M  +0    -14   src/tests/CMakeLists.txt
D  +0    -220  src/tests/allocinefetchertest.cpp
D  +0    -54   src/tests/allocinefetchertest.h

https://invent.kde.org/office/tellico/-/commit/a01a0c9cacbba48b7872e37d906cef31e9523dfa

diff --git a/ChangeLog b/ChangeLog
index 3266668ed..ff5c388ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2024-02-11  Robby Stephenson  <robby at periapsis.org>
+
+	* Removed data source for Allocine.
+
 2024-01-24  Robby Stephenson  <robby at periapsis.org>
 
 	* Fixed bug for entry selection after changing group field (Bug 480297).
diff --git a/doc/configuration.docbook b/doc/configuration.docbook
index c9bc6e81c..9b80cb15e 100644
--- a/doc/configuration.docbook
+++ b/doc/configuration.docbook
@@ -164,7 +164,6 @@ while the full list is <ulink url="https://tellico-project.org/data-sources">ava
 <listitem><simpara><link linkend="opds">OPDS catalogs</link>,</simpara></listitem>
 <!-- movies -->
 <listitem><simpara>the <link linkend="imdb">Internet Movie Database</link>,</simpara></listitem>
-<listitem><simpara><link linkend="allocine">AlloCiné</link>,</simpara></listitem>
 <listitem><simpara><link linkend="tmdb">TheMovieDB.org</link>,</simpara></listitem>
 <listitem><simpara>the <link linkend="omdb">Open Movie Database</link>,</simpara></listitem>
 <listitem><simpara><link linkend="filmaffinity">FilmAffinity</link>,</simpara></listitem>
@@ -361,13 +360,6 @@ The <ulink url="http://www.imdb.com">Internet Movie Database</ulink> provides in
 </para>
 </sect3>
 
-<sect3 id="allocine">
-<title>AlloCiné</title>
-<para>
-<ulink url="http://allocine.fr">AlloCiné</ulink> is an online movie information service, based in France.
-</para>
-</sect3>
-
 <sect3 id="filmaffinity">
 <title>FilmAffinity</title>
 <para>
diff --git a/src/fetch/CMakeLists.txt b/src/fetch/CMakeLists.txt
index a61cd7e90..d72f1de70 100644
--- a/src/fetch/CMakeLists.txt
+++ b/src/fetch/CMakeLists.txt
@@ -4,7 +4,6 @@ ADD_SUBDIRECTORY( scripts )
 
 SET(fetch_STAT_SRCS
    adsfetcher.cpp
-   allocinefetcher.cpp
    amazonfetcher.cpp
    amazonrequest.cpp
    arxivfetcher.cpp
diff --git a/src/fetch/allocinefetcher.cpp b/src/fetch/allocinefetcher.cpp
deleted file mode 100644
index 4752dda7d..000000000
--- a/src/fetch/allocinefetcher.cpp
+++ /dev/null
@@ -1,516 +0,0 @@
-/***************************************************************************
-    Copyright (C) 2012-2022 Robby Stephenson <robby at periapsis.org>
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or         *
- *   modify it under the terms of the GNU General Public License as        *
- *   published by the Free Software Foundation; either version 2 of        *
- *   the License or (at your option) version 3 or any later version        *
- *   accepted by the membership of KDE e.V. (or its successor approved     *
- *   by the membership of KDE e.V.), which shall act as a proxy            *
- *   defined in Section 14 of version 3 of the license.                    *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
- *                                                                         *
- ***************************************************************************/
-
-#include <config.h> // for TELLICO_VERSION
-
-#include "allocinefetcher.h"
-#include "../collections/videocollection.h"
-#include "../images/imagefactory.h"
-#include "../entry.h"
-#include "../utils/guiproxy.h"
-#include "../utils/string_utils.h"
-#include "../utils/mapvalue.h"
-#include "../tellico_debug.h"
-
-#include <KIO/Job>
-#include <KIO/JobUiDelegate>
-#include <KLocalizedString>
-#include <KJobWidgets/KJobWidgets>
-#include <KConfigGroup>
-
-#include <QSpinBox>
-#include <QUrl>
-#include <QLabel>
-#include <QFile>
-#include <QTextStream>
-#include <QGridLayout>
-#include <QTextCodec>
-#include <QCryptographicHash>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QUrlQuery>
-
-namespace {
-  static const char* ALLOCINE_API_KEY = "100ED1DA33EB";
-  static const char* ALLOCINE_API_URL = "http://api.allocine.fr/rest/v3/";
-  static const char* ALLOCINE_PARTNER_KEY = "1a1ed8c1bed24d60ae3472eed1da33eb";
-}
-
-using namespace Tellico;
-using Tellico::Fetch::AbstractAllocineFetcher;
-using Tellico::Fetch::AllocineFetcher;
-
-AbstractAllocineFetcher::AbstractAllocineFetcher(QObject* parent_, const QString& baseUrl_)
-    : Fetcher(parent_)
-    , m_started(false)
-    , m_apiKey(QLatin1String(ALLOCINE_API_KEY))
-    , m_baseUrl(baseUrl_)
-    , m_numCast(10) {
-  Q_ASSERT(!m_baseUrl.isEmpty());
-}
-
-AbstractAllocineFetcher::~AbstractAllocineFetcher() {
-}
-
-bool AbstractAllocineFetcher::canSearch(Fetch::FetchKey k) const {
-  return k == Keyword;
-}
-
-bool AbstractAllocineFetcher::canFetch(int type) const {
-  return type == Data::Collection::Video;
-}
-
-void AbstractAllocineFetcher::readConfigHook(const KConfigGroup& config_) {
-  QString k = config_.readEntry("API Key", ALLOCINE_API_KEY);
-  if(!k.isEmpty()) {
-    m_apiKey = k;
-  }
-  m_numCast = config_.readEntry("Max Cast", 10);
-}
-
-void AbstractAllocineFetcher::search() {
-  m_started = true;
-
-  const QString method(QStringLiteral("search"));
-
-  QUrl u(m_baseUrl);
-  u = u.adjusted(QUrl::StripTrailingSlash);
-  u.setPath(u.path() + QLatin1Char('/') + method);
-
-  // the order of the parameters appears to matter
-  QList<QPair<QString, QString> > params;
-  params.append(qMakePair(QStringLiteral("partner"), m_apiKey));
-
-  // I can't figure out how to encode accent marks, but they don't
-  // seem to be necessary
-  QString q = removeAccents(request().value());
-  // should I just remove all non alphabetical characters?
-  // see https://bugs.kde.org/show_bug.cgi?id=337432
-  q.remove(QRegularExpression(QStringLiteral("[,:!?;\\(\\)]")));
-  q.replace(QLatin1Char('\''), QLatin1Char('+'));
-  q.replace(QLatin1Char(' '), QLatin1Char('+'));
-
-  switch(request().key()) {
-    case Keyword:
-      params.append(qMakePair(QStringLiteral("q"), q));
-      break;
-
-    default:
-      myWarning() << source() << "- key not recognized:" << request().key();
-      stop();
-      return;
-  }
-
-  params.append(qMakePair(QStringLiteral("format"), QStringLiteral("json")));
-  params.append(qMakePair(QStringLiteral("filter"), QStringLiteral("movie")));
-
-  const QString sed = QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMdd"));
-  params.append(qMakePair(QStringLiteral("sed"), sed));
-
-  const QByteArray sig = calculateSignature(method, params);
-
-  QUrlQuery query;
-  query.setQueryItems(params);
-  query.addQueryItem(QStringLiteral("sig"), QLatin1String(sig));
-  u.setQuery(query);
-//  myDebug() << u;
-
-  m_job = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo);
-  configureJob(m_job);
-  KJobWidgets::setWindow(m_job, GUI::Proxy::widget());
-  connect(m_job.data(), &KJob::result, this, &AbstractAllocineFetcher::slotComplete);
-}
-
-void AbstractAllocineFetcher::stop() {
-  if(!m_started) {
-    return;
-  }
-  if(m_job) {
-    m_job->kill();
-  }
-  m_started = false;
-  emit signalDone(this);
-}
-
-Tellico::Data::EntryPtr AbstractAllocineFetcher::fetchEntryHook(uint uid_) {
-  Data::EntryPtr entry = m_entries.value(uid_);
-  if(!entry) {
-    myWarning() << "no entry in dict";
-    return Data::EntryPtr();
-  }
-
-  QString code = entry->field(QStringLiteral("allocine-code"));
-  if(code.isEmpty()) {
-    // could mean we already updated the entry
-    myDebug() << "no allocine release found";
-    return entry;
-  }
-  const QString method(QStringLiteral("movie"));
-
-  QUrl u(m_baseUrl);
-  u = u.adjusted(QUrl::StripTrailingSlash);
-  u.setPath(u.path() + QLatin1Char('/') + method);
-
-  // the order of the parameters appears to matter
-  QList<QPair<QString, QString> > params;
-  params.append(qMakePair(QStringLiteral("partner"), m_apiKey));
-  params.append(qMakePair(QStringLiteral("code"), code));
-  params.append(qMakePair(QStringLiteral("profile"), QStringLiteral("large")));
-  params.append(qMakePair(QStringLiteral("filter"), QStringLiteral("movie")));
-  params.append(qMakePair(QStringLiteral("format"), QStringLiteral("json")));
-
-  const QString sed = QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMdd"));
-  params.append(qMakePair(QStringLiteral("sed"), sed));
-
-  const QByteArray sig = calculateSignature(method, params);
-
-  QUrlQuery query;
-  query.setQueryItems(params);
-  query.addQueryItem(QStringLiteral("sig"), QLatin1String(sig));
-  u.setQuery(query);
-//  myDebug() << "url: " << u;
-//  QByteArray data = FileHandler::readDataFile(u, true);
-  KIO::StoredTransferJob* dataJob = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo);
-  configureJob(dataJob);
-  if(!dataJob->exec()) {
-    myDebug() << "Failed to load" << u;
-    return entry;
-  }
-  const QByteArray data = dataJob->data();
-
-#if 0
-  myWarning() << "Remove debug2 from allocinefetcher.cpp";
-  QFile f(QString::fromLatin1("/tmp/test2.json"));
-  if(f.open(QIODevice::WriteOnly)) {
-    QTextStream t(&f);
-    t.setCodec("UTF-8");
-    t << data;
-  }
-  f.close();
-#endif
-
-  QJsonParseError error;
-  QJsonDocument doc = QJsonDocument::fromJson(data, &error);
-  QVariantMap result = doc.object().toVariantMap().value(QStringLiteral("movie")).toMap();
-  if(error.error != QJsonParseError::NoError) {
-    myDebug() << "Bad JSON results";
-#if 0
-    myWarning() << "Remove debug3 from allocinefetcher.cpp";
-    QFile f2(QString::fromLatin1("/tmp/test3.json"));
-    if(f2.open(QIODevice::WriteOnly)) {
-      QTextStream t(&f2);
-      t.setCodec("UTF-8");
-      t << data;
-    }
-    f2.close();
-#endif
-    return entry;
-  }
-  populateEntry(entry, result);
-
-  // image might still be a URL
-  const QString image_id = entry->field(QStringLiteral("cover"));
-  if(image_id.contains(QLatin1Char('/'))) {
-    const QString id = ImageFactory::addImage(QUrl::fromUserInput(image_id), true /* quiet */);
-    if(id.isEmpty()) {
-      message(i18n("The cover image could not be loaded."), MessageHandler::Warning);
-    }
-    // empty image ID is ok
-    entry->setField(QStringLiteral("cover"), id);
-  }
-
-  // don't want to include id
-  entry->collection()->removeField(QStringLiteral("allocine-code"));
-  QStringList castRows = FieldFormat::splitTable(entry->field(QStringLiteral("cast")));
-  while(castRows.count() > m_numCast) {
-    castRows.removeLast();
-  }
-  entry->setField(QStringLiteral("cast"), castRows.join(FieldFormat::rowDelimiterString()));
-  return entry;
-}
-
-void AbstractAllocineFetcher::slotComplete(KJob*) {
-  if(m_job->error()) {
-    myDebug() << "Error:" << m_job->errorString();
-    m_job->uiDelegate()->showErrorMessage();
-    stop();
-    return;
-  }
-
-  QByteArray data = m_job->data();
-  if(data.isEmpty()) {
-    myDebug() << "no data";
-    stop();
-    return;
-  }
-  // see bug 319662. If fetcher is cancelled, job is killed
-  // if the pointer is retained, it gets double-deleted
-  m_job = nullptr;
-
-#if 0
-  myWarning() << "Remove debug from allocinefetcher.cpp";
-  QFile f(QString::fromLatin1("/tmp/test.json"));
-  if(f.open(QIODevice::WriteOnly)) {
-    QTextStream t(&f);
-    t.setCodec("UTF-8");
-    t << data;
-  }
-  f.close();
-#endif
-
-  QJsonDocument doc = QJsonDocument::fromJson(data);
-  QVariantMap result = doc.object().toVariantMap().value(QStringLiteral("feed")).toMap();
-//  myDebug() << "total:" << result.value(QLatin1String("totalResults"));
-
-  QVariantList resultList = result.value(QStringLiteral("movie")).toList();
-  if(resultList.isEmpty()) {
-    myDebug() << "no results";
-    stop();
-    return;
-  }
-
-  foreach(const QVariant& result, resultList) {
-  //  myDebug() << "found result:" << result;
-
-    //create a new collection for every result since we end up removing the allocine code field
-    // when fetchEntryHook is called. See bug 338389
-    Data::EntryPtr entry(new Data::Entry(createCollection()));
-    populateEntry(entry, result.toMap());
-
-    FetchResult* r = new FetchResult(this, entry);
-    m_entries.insert(r->uid, entry);
-    emit signalResultFound(r);
-  }
-
-  m_hasMoreResults = false;
-  stop();
-}
-
-Tellico::Data::CollPtr AbstractAllocineFetcher::createCollection() const {
-  Data::CollPtr coll(new Data::VideoCollection(true));
-  // always add the allocine release code for fetchEntryHook
-  Data::FieldPtr field(new Data::Field(QStringLiteral("allocine-code"), QStringLiteral("Allocine Code"), Data::Field::Number));
-  field->setCategory(i18n("General"));
-  coll->addField(field);
-
-  // add new fields
-  if(optionalFields().contains(QStringLiteral("allocine"))) {
-    Data::FieldPtr field(new Data::Field(QStringLiteral("allocine"), i18n("Allocine Link"), Data::Field::URL));
-    field->setCategory(i18n("General"));
-    coll->addField(field);
-  }
-  if(optionalFields().contains(QStringLiteral("origtitle"))) {
-    Data::FieldPtr f(new Data::Field(QStringLiteral("origtitle"), i18n("Original Title")));
-    f->setFormatType(FieldFormat::FormatTitle);
-    coll->addField(f);
-  }
-
-  return coll;
-}
-
-void AbstractAllocineFetcher::populateEntry(Data::EntryPtr entry, const QVariantMap& resultMap) {
-  if(entry->collection()->hasField(QStringLiteral("allocine-code"))) {
-    entry->setField(QStringLiteral("allocine-code"), mapValue(resultMap, "code"));
-  }
-
-  entry->setField(QStringLiteral("title"), mapValue(resultMap, "title"));
-  if(optionalFields().contains(QStringLiteral("origtitle"))) {
-    entry->setField(QStringLiteral("origtitle"), mapValue(resultMap, "originalTitle"));
-  }
-  if(entry->title().isEmpty()) {
-    entry->setField(QStringLiteral("title"), mapValue(resultMap,  "originalTitle"));
-  }
-  entry->setField(QStringLiteral("year"), mapValue(resultMap, "productionYear"));
-  entry->setField(QStringLiteral("plot"), mapValue(resultMap, "synopsis"));
-
-  const int runTime = mapValue(resultMap, "runtime").toInt();
-  entry->setField(QStringLiteral("running-time"), QString::number(runTime/60));
-
-  const QVariantList castList = resultMap.value(QStringLiteral("castMember")).toList();
-  QStringList actors, directors, producers, composers;
-  foreach(const QVariant& castVariant, castList) {
-    const QVariantMap castMap = castVariant.toMap();
-    const int code = mapValue(castMap, "activity", "code").toInt();
-    switch(code) {
-      case 8001:
-        actors << (mapValue(castMap, "person", "name") + FieldFormat::columnDelimiterString() + mapValue(castMap, "role"));
-        break;
-      case 8002:
-        directors << mapValue(castMap, "person", "name");
-        break;
-      case 8029:
-        producers << mapValue(castMap, "person", "name");
-        break;
-      case 8003:
-        composers << mapValue(castMap, "person", "name");
-        break;
-    }
-  }
-  entry->setField(QStringLiteral("cast"), actors.join(FieldFormat::rowDelimiterString()));
-  entry->setField(QStringLiteral("director"), directors.join(FieldFormat::delimiterString()));
-  entry->setField(QStringLiteral("producer"), producers.join(FieldFormat::delimiterString()));
-  entry->setField(QStringLiteral("composer"), composers.join(FieldFormat::delimiterString()));
-
-  const QVariantMap releaseMap = resultMap.value(QStringLiteral("release")).toMap();
-  entry->setField(QStringLiteral("studio"), mapValue(releaseMap, "distributor", "name"));
-
-  QStringList genres;
-  foreach(const QVariant& variant, resultMap.value(QLatin1String("genre")).toList()) {
-    genres << i18n(mapValue(variant.toMap(), "$").toUtf8().constData());
-  }
-  entry->setField(QStringLiteral("genre"), genres.join(FieldFormat::delimiterString()));
-
-  QStringList nats;
-  foreach(const QVariant& variant, resultMap.value(QLatin1String("nationality")).toList()) {
-    nats << mapValue(variant.toMap(), "$");
-  }
-  entry->setField(QStringLiteral("nationality"), nats.join(FieldFormat::delimiterString()));
-
-  QStringList langs;
-  foreach(const QVariant& variant, resultMap.value(QLatin1String("language")).toList()) {
-    langs << mapValue(variant.toMap(), "$");
-  }
-  entry->setField(QStringLiteral("language"), langs.join(FieldFormat::delimiterString()));
-
-  const QVariantMap colorMap = resultMap.value(QLatin1String("color")).toMap();
-  if(colorMap.value(QStringLiteral("code")) == QLatin1String("12001")) {
-    entry->setField(QStringLiteral("color"), i18n("Color"));
-  }
-
-  entry->setField(QStringLiteral("cover"), mapValue(resultMap, "poster", "href"));
-
-  if(optionalFields().contains(QStringLiteral("allocine"))) {
-    entry->setField(QStringLiteral("allocine"), mapValue(resultMap, "link", "href"));
-  }
-}
-
-Tellico::Fetch::FetchRequest AbstractAllocineFetcher::updateRequest(Data::EntryPtr entry_) {
-  QString title = entry_->field(QStringLiteral("title"));
-  if(!title.isEmpty()) {
-    return FetchRequest(Keyword, title);
-  }
-  return FetchRequest();
-}
-
-void AbstractAllocineFetcher::configureJob(KIO::StoredTransferJob* job_) {
-  // 10/8/17: UserAgent appears necessary to receive data
-  job_->addMetaData(QLatin1String("SendUserAgent"), QLatin1String("true"));
-  job_->addMetaData(QStringLiteral("UserAgent"), QStringLiteral("Tellico/%1")
-                                                                .arg(QStringLiteral(TELLICO_VERSION)));
-  job_->addMetaData(QLatin1String("Languages"), QLatin1String("fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3"));
-}
-
-AbstractAllocineFetcher::ConfigWidget::ConfigWidget(QWidget* parent_, const AbstractAllocineFetcher* fetcher_)
-    : Fetch::ConfigWidget(parent_) {
-  QGridLayout* l = new QGridLayout(optionsWidget());
-  l->setSpacing(4);
-  l->setColumnStretch(1, 10);
-
-  int row = -1;
-
-  QLabel* label = new QLabel(i18n("&Maximum cast: "), optionsWidget());
-  l->addWidget(label, ++row, 0);
-  m_numCast = new QSpinBox(optionsWidget());
-  m_numCast->setMaximum(99);
-  m_numCast->setMinimum(0);
-  m_numCast->setValue(10);
-#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
-  void (QSpinBox::* textChanged)(const QString&) = &QSpinBox::valueChanged;
-#else
-  void (QSpinBox::* textChanged)(const QString&) = &QSpinBox::textChanged;
-#endif
-  connect(m_numCast, textChanged, this, &ConfigWidget::slotSetModified);
-  l->addWidget(m_numCast, row, 1);
-  QString w = i18n("The list of cast members may include many people. Set the maximum number returned from the search.");
-  label->setWhatsThis(w);
-  m_numCast->setWhatsThis(w);
-  label->setBuddy(m_numCast);
-
-  l->setRowStretch(++row, 10);
-
-  m_numCast->setValue(fetcher_ ? fetcher_->m_numCast : 10);
-}
-
-void AbstractAllocineFetcher::ConfigWidget::saveConfigHook(KConfigGroup& config_) {
-  config_.writeEntry("Max Cast", m_numCast->value());
-}
-
-QByteArray AbstractAllocineFetcher::calculateSignature(const QString& method, const QList<QPair<QString, QString> >& params_) {
-  typedef QPair<QString, QString> StringPair;
-  QByteArray queryString;
-  foreach(const StringPair& pair, params_) {
-    queryString.append(pair.first.toUtf8().toPercentEncoding("+"));
-    queryString.append('=');
-    queryString.append(pair.second.toUtf8().toPercentEncoding("+"));
-    queryString.append('&');
-  }
-  // remove final '&'
-  queryString.chop(1);
-
-  const QByteArray toSign = method.toUtf8() + queryString + ALLOCINE_PARTNER_KEY;
-  const QByteArray hash = QCryptographicHash::hash(toSign, QCryptographicHash::Sha1);
-  return hash.toBase64();
-}
-
-/**********************************************************************************************/
-
-AllocineFetcher::AllocineFetcher(QObject* parent_)
-    : AbstractAllocineFetcher(parent_, QLatin1String(ALLOCINE_API_URL)) {
-}
-
-AllocineFetcher::~AllocineFetcher() {
-}
-
-QString AllocineFetcher::source() const {
-  return m_name.isEmpty() ? defaultName() : m_name;
-}
-
-Tellico::Fetch::ConfigWidget* AllocineFetcher::configWidget(QWidget* parent_) const {
-  return new AllocineFetcher::ConfigWidget(parent_, this);
-}
-
-QString AllocineFetcher::defaultName() {
-  return QStringLiteral("AlloCiné.fr");
-}
-
-QString AllocineFetcher::defaultIcon() {
-  return favIcon("http://www.allocine.fr");
-}
-
-Tellico::StringHash AllocineFetcher::allOptionalFields() {
-  StringHash hash;
-  hash[QStringLiteral("origtitle")] = i18n("Original Title");
-  hash[QStringLiteral("allocine")]  = i18n("Allocine Link");
-  return hash;
-}
-
-AllocineFetcher::ConfigWidget::ConfigWidget(QWidget* parent_, const AbstractAllocineFetcher* fetcher_)
-    : AbstractAllocineFetcher::ConfigWidget(parent_, fetcher_) {
-  // now add additional fields widget
-  addFieldsWidget(AllocineFetcher::allOptionalFields(), fetcher_ ? fetcher_->optionalFields() : QStringList());
-}
-
-QString AllocineFetcher::ConfigWidget::preferredName() const {
-  return AllocineFetcher::defaultName();
-}
diff --git a/src/fetch/allocinefetcher.h b/src/fetch/allocinefetcher.h
deleted file mode 100644
index 946c0537c..000000000
--- a/src/fetch/allocinefetcher.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/***************************************************************************
-    Copyright (C) 2012 Robby Stephenson <robby at periapsis.org>
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or         *
- *   modify it under the terms of the GNU General Public License as        *
- *   published by the Free Software Foundation; either version 2 of        *
- *   the License or (at your option) version 3 or any later version        *
- *   accepted by the membership of KDE e.V. (or its successor approved     *
- *   by the membership of KDE e.V.), which shall act as a proxy            *
- *   defined in Section 14 of version 3 of the license.                    *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
- *                                                                         *
- ***************************************************************************/
-
-#ifndef TELLICO_ALLOCINEFETCHER_H
-#define TELLICO_ALLOCINEFETCHER_H
-
-#include "xmlfetcher.h"
-#include "configwidget.h"
-#include "../datavectors.h"
-
-#include <QPointer>
-
-class QSpinBox;
-
-class KJob;
-namespace KIO {
-  class StoredTransferJob;
-}
-
-namespace Tellico {
-
-  namespace Fetch {
-
-/**
- * An abstract fetcher for the Allocine family of web sites
- *
- * @author Robby Stephenson
- */
-class AbstractAllocineFetcher : public Fetcher {
-Q_OBJECT
-
-public:
-  /**
-   */
-  AbstractAllocineFetcher(QObject* parent, const QString& baseUrl);
-  /**
-   */
-  virtual ~AbstractAllocineFetcher();
-
-  virtual bool isSearching() const Q_DECL_OVERRIDE { return m_started; }
-  virtual bool canSearch(FetchKey k) const Q_DECL_OVERRIDE;
-  virtual void stop() Q_DECL_OVERRIDE;
-  virtual Data::EntryPtr fetchEntryHook(uint uid) Q_DECL_OVERRIDE;
-  virtual bool canFetch(int type) const Q_DECL_OVERRIDE;
-  virtual void readConfigHook(const KConfigGroup& config) Q_DECL_OVERRIDE;
-
-  class ConfigWidget : public Fetch::ConfigWidget {
-  public:
-    explicit ConfigWidget(QWidget* parent_, const AbstractAllocineFetcher* fetcher = nullptr);
-    virtual void saveConfigHook(KConfigGroup&) Q_DECL_OVERRIDE;
-    virtual QString preferredName() const Q_DECL_OVERRIDE = 0;
-  private:
-    QSpinBox* m_numCast;
-  };
-  friend class ConfigWidget;
-
-private Q_SLOTS:
-  void slotComplete(KJob* job);
-
-private:
-  static QByteArray calculateSignature(const QString& method, const QList<QPair<QString, QString> >& params);
-
-  virtual void search() Q_DECL_OVERRIDE;
-  virtual FetchRequest updateRequest(Data::EntryPtr entry) Q_DECL_OVERRIDE;
-  Data::CollPtr createCollection() const;
-  void populateEntry(Data::EntryPtr entry, const QVariantMap& resultMap);
-  void configureJob(KIO::StoredTransferJob* job);
-
-  QHash<uint, Data::EntryPtr> m_entries;
-  QPointer<KIO::StoredTransferJob> m_job;
-
-  bool m_started;
-  QString m_apiKey;
-  QString m_baseUrl;
-  int m_numCast;
-};
-
-/**
- * A fetcher for allocine.fr
- *
- * @author Robby Stephenson
- */
-class AllocineFetcher : public AbstractAllocineFetcher {
-Q_OBJECT
-
-public:
-  /**
-   */
-  AllocineFetcher(QObject* parent);
-  ~AllocineFetcher();
-
-  virtual QString source() const Q_DECL_OVERRIDE;
-  virtual Type type() const Q_DECL_OVERRIDE { return Allocine; }
-
-  /**
-   * Returns a widget for modifying the fetcher's config.
-   */
-  virtual Fetch::ConfigWidget* configWidget(QWidget* parent) const Q_DECL_OVERRIDE;
-
-  class ConfigWidget : public AbstractAllocineFetcher::ConfigWidget {
-  public:
-    explicit ConfigWidget(QWidget* parent_, const AbstractAllocineFetcher* fetcher = nullptr);
-    virtual QString preferredName() const Q_DECL_OVERRIDE;
-  };
-
-  static QString defaultName();
-  static QString defaultIcon();
-  static StringHash allOptionalFields();
-};
-
-  } // end namespace
-} // end namespace
-#endif
diff --git a/src/fetch/fetch.h b/src/fetch/fetch.h
index 116c8be5f..df772eafe 100644
--- a/src/fetch/fetch.h
+++ b/src/fetch/fetch.h
@@ -83,7 +83,7 @@ enum Type {
   GoogleBook,
   MAS, // Removed
   Springer,
-  Allocine,
+  Allocine, // Removed
   ScreenRush, // Removed
   FilmStarts, // Removed
   SensaCine, // Removed
diff --git a/src/fetch/fetcherinitializer.cpp b/src/fetch/fetcherinitializer.cpp
index 7e23b5d4d..b1fa2493c 100644
--- a/src/fetch/fetcherinitializer.cpp
+++ b/src/fetch/fetcherinitializer.cpp
@@ -55,7 +55,6 @@
 #include "moviemeterfetcher.h"
 #include "googlebookfetcher.h"
 #include "springerfetcher.h"
-#include "allocinefetcher.h"
 #include "thegamesdbfetcher.h"
 #include "dblpfetcher.h"
 #include "mrlookupfetcher.h"
@@ -111,7 +110,6 @@ Tellico::Fetch::FetcherInitializer::FetcherInitializer() {
   RegisterFetcher<Fetch::GoogleBookFetcher> registerGoogleBook(GoogleBook);
   RegisterFetcher<Fetch::HathiTrustFetcher> registerHathiTrust(HathiTrust);
   RegisterFetcher<Fetch::VNDBFetcher> registerVNDB(VNDB);
-  RegisterFetcher<Fetch::AllocineFetcher> registerAllocine(Allocine);
   RegisterFetcher<Fetch::MovieMeterFetcher> registerMovieMeter(MovieMeter);
   RegisterFetcher<Fetch::DVDFrFetcher> registerDVDFr(DVDFr);
   RegisterFetcher<Fetch::DoubanFetcher> registerDouban(Douban);
diff --git a/src/fetch/fetchmanager.cpp b/src/fetch/fetchmanager.cpp
index 0715ada24..4085c0767 100644
--- a/src/fetch/fetchmanager.cpp
+++ b/src/fetch/fetchmanager.cpp
@@ -27,7 +27,6 @@
 #include "fetchmanager.h"
 #include "configwidget.h"
 #include "messagehandler.h"
-#include "../entry.h"
 #include "../collection.h"
 #include "../utils/tellico_utils.h"
 #include "../tellico_debug.h"
@@ -363,7 +362,6 @@ Tellico::Fetch::FetcherVec Manager::defaultFetchers() {
   }
   if(langs.contains(QStringLiteral("fr"))) {
     FETCHER_ADD(DVDFr);
-    FETCHER_ADD(Allocine);
   }
   if(langs.contains(QStringLiteral("ru"))) {
     FETCHER_ADD(KinoPoisk);
diff --git a/src/fetch/scripts/CMakeLists.txt b/src/fetch/scripts/CMakeLists.txt
index 4d337c335..78f6bbdf5 100644
--- a/src/fetch/scripts/CMakeLists.txt
+++ b/src/fetch/scripts/CMakeLists.txt
@@ -3,12 +3,10 @@
 
 SET(SCRIPT_FILES
     dark_horse_comics.py
-    fr.allocine.py
     )
 
 SET(SPEC_FILES
     dark_horse_comics.py.spec
-    fr.allocine.py.spec
     )
 
 INSTALL(PROGRAMS ${SCRIPT_FILES} DESTINATION ${TELLICO_DATA_INSTALL_DIR}/data-sources )
diff --git a/src/fetch/scripts/fr.allocine.py b/src/fetch/scripts/fr.allocine.py
deleted file mode 100755
index a250443fb..000000000
--- a/src/fetch/scripts/fr.allocine.py
+++ /dev/null
@@ -1,475 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# kate: replace-tabs off;
-# ***************************************************************************
-#    copyright            : (C) 2006-2010 by Mathias Monnerville
-#    email                : tellico at monnerville.com
-# ***************************************************************************
-#
-# ***************************************************************************
-# *                                                                         *
-# *   This program is free software; you can redistribute it and/or modify  *
-# *   it under the terms of version 2 of the GNU General Public License as  *
-# *   published by the Free Software Foundation;                            *
-# *                                                                         *
-# ***************************************************************************
-#
-# Version 0.7.3: 2010-12-07 (Reported by Romain Henriet)
-# * Fixed some regexp issues
-# * Better handling of image parsing/fetching errors
-#
-# Version 0.7.2.1: 2010-07-27 (Reported by Romain Henriet)
-# * Updated title match to allow searching without diacritical marks
-#
-# Version 0.7.2: 2010-05-27 (Reported by Romain Henriet)
-# * Fixed bug preventing searches with accent marks
-# * Added post-processing cleanup action to replace raw HTML entities with
-#   their ISO Latin-1 replacement text
-#
-# Version 0.7.1: 2010-04-26 (Thanks to Romain Henriet <romain-devel at laposte.net>)
-# * Fixed greedy regexp for genre.  Fixed nationality output. Add studio.
-#
-# Version 0.7: 2009-11-12
-# * Allocine has a brand new website. All regexps were broken.
-#
-# Version 0.6: 2009-03-04 (Thanks to R. Fischer and Henry-Nicolas Tourneur)
-# * Fixed parsing issues (various RegExp issues due to allocine's HTML changes)
-#
-# Version 0.5: 2009-01-21 (Changes contributed by R. Fischer <fischer.tellico at free.fr>)
-# * Added complete distribution of actors and roles, Genres, Nationalities, producers, composer and scenarist
-# * Fixed the plot field that returned a wrong answer when no plot is available
-# * Fixed a bug related to parameters encoding
-#
-# Version 0.4:
-# * Fixed parsing errors: some fields in allocine's HTML pages have changed recently. Multiple actors and genres
-# could not be retrieved. Fixed bad http request error due to some changes in HTML code.
-#
-# Version 0.3:
-# * Fixed parsing: some fields in allocine's HTML pages have changed. Movie's image could not be fetched anymore. Fixed.
-#
-# Version 0.2:
-# * Fixed parsing: allocine's HTML pages have changed. Movie's image could not be fetched anymore.
-#
-# Version 0.1:
-# * Initial release.
-
-import sys, os, re, hashlib, random, types
-import urllib, time, base64
-import xml.dom.minidom
-import locale
-try:
-	import htmlentitydefs as htmlents
-except ImportError:
-	try:
-		from html.entities import entitydefs as htmlents
-	except ImportError:
-		print('Python 2.5+ required')
-		raise
-
-try:
-	# For Python 3.0 and later
-	from urllib.request import urlopen
-except ImportError:
-	# Fall back to Python 2's urllib2
-	from urllib2 import urlopen
-
-XML_HEADER = """<?xml version="1.0" encoding="UTF-8"?>"""
-DOCTYPE = """<!DOCTYPE tellico PUBLIC "-//Robby Stephenson/DTD Tellico V9.0//EN" "http://periapsis.org/tellico/dtd/v9/tellico.dtd">"""
-
-VERSION = "0.7.3"
-
-def genMD5():
-	float = random.random()
-	return hashlib.md5(str(float)).hexdigest()
-
-class BasicTellicoDOM:
-	def __init__(self):
-		self.__doc = xml.dom.minidom.Document()
-		self.__root = self.__doc.createElement('tellico')
-		self.__root.setAttribute('xmlns', 'http://periapsis.org/tellico/')
-		self.__root.setAttribute('syntaxVersion', '9')
-
-		self.__collection = self.__doc.createElement('collection')
-		self.__collection.setAttribute('title', 'My Movies')
-		self.__collection.setAttribute('type', '3')
-
-		self.__fields = self.__doc.createElement('fields')
-		# Add all default (standard) fields
-		self.__dfltField = self.__doc.createElement('field')
-		self.__dfltField.setAttribute('name', '_default')
-
-		# Add a custom 'Collection' field
-		self.__customField = self.__doc.createElement('field')
-		self.__customField.setAttribute('name', 'titre-original')
-		self.__customField.setAttribute('title', 'Original Title')
-		self.__customField.setAttribute('flags', '0')
-		self.__customField.setAttribute('category', unicode('G�n�ral', 'latin-1').encode('utf-8'))
-		self.__customField.setAttribute('format', '1')
-		self.__customField.setAttribute('type', '1')
-		self.__customField.setAttribute('i18n', 'yes')
-
-		self.__fields.appendChild(self.__dfltField)
-		self.__fields.appendChild(self.__customField)
-		self.__collection.appendChild(self.__fields)
-
-		self.__images = self.__doc.createElement('images')
-
-		self.__root.appendChild(self.__collection)
-		self.__doc.appendChild(self.__root)
-
-		# Current movie id
-		self.__currentId = 0
-
-
-	def addEntry(self, movieData):
-		"""
-		Add a movie entry
-		"""
-		d = movieData
-		entryNode = self.__doc.createElement('entry')
-		entryNode.setAttribute('id', str(self.__currentId))
-
-		titleNode = self.__doc.createElement('title')
-		titleNode.appendChild(self.__doc.createTextNode(d['title']))
-
-		otitleNode = self.__doc.createElement('titre-original')
-		otitleNode.appendChild(self.__doc.createTextNode(d['otitle']))
-
-		yearNode = self.__doc.createElement('year')
-		yearNode.appendChild(self.__doc.createTextNode(d['year']))
-
-		genresNode = self.__doc.createElement('genres')
-		for g in d['genres']:
-			genreNode = self.__doc.createElement('genre')
-			genreNode.appendChild(self.__doc.createTextNode(g))
-			genresNode.appendChild(genreNode)
-
-		studsNode = self.__doc.createElement('studios')
-		for g in d['studio']:
-			studNode = self.__doc.createElement('studio')
-			studNode.appendChild(self.__doc.createTextNode(g))
-			studsNode.appendChild(studNode)
-
-		natsNode = self.__doc.createElement('nationalitys')
-		for g in d['nat']:
-			natNode = self.__doc.createElement('nationality')
-			natNode.appendChild(self.__doc.createTextNode(g))
-			natsNode.appendChild(natNode)
-
-		castsNode = self.__doc.createElement('casts')
-		i = 0
-		while i < len(d['actors']):
-			g = d['actors'][i]
-			h = d['actors'][i+1]
-			castNode = self.__doc.createElement('cast')
-			col1Node = self.__doc.createElement('column')
-			col2Node = self.__doc.createElement('column')
-			col1Node.appendChild(self.__doc.createTextNode(g))
-			col2Node.appendChild(self.__doc.createTextNode(h))
-			castNode.appendChild(col1Node)
-			castNode.appendChild(col2Node)
-			castsNode.appendChild(castNode)
-			i = i + 2
-
-		dirsNode = self.__doc.createElement('directors')
-		for g in d['dirs']:
-			dirNode = self.__doc.createElement('director')
-			dirNode.appendChild(self.__doc.createTextNode(g))
-			dirsNode.appendChild(dirNode)
-
-		prodsNode = self.__doc.createElement('producers')
-		for g in d['prods']:
-			prodNode = self.__doc.createElement('producer')
-			prodNode.appendChild(self.__doc.createTextNode(g))
-			prodsNode.appendChild(prodNode)
-
-		scensNode = self.__doc.createElement('writers')
-		for g in d['scens']:
-			scenNode = self.__doc.createElement('writer')
-			scenNode.appendChild(self.__doc.createTextNode(g))
-			scensNode.appendChild(scenNode)
-
-		compsNode = self.__doc.createElement('composers')
-		for g in d['comps']:
-			compNode = self.__doc.createElement('composer')
-			compNode.appendChild(self.__doc.createTextNode(g))
-			compsNode.appendChild(compNode)
-
-		timeNode = self.__doc.createElement('running-time')
-		timeNode.appendChild(self.__doc.createTextNode(d['time']))
-
-		allocineNode = self.__doc.createElement(unicode('allocin�-link', 'latin-1').encode('utf-8'))
-		allocineNode.appendChild(self.__doc.createTextNode(d['allocine']))
-
-		plotNode = self.__doc.createElement('plot')
-		plotNode.appendChild(self.__doc.createTextNode(d['plot']))
-
-		if d['image']:
-			imageNode = self.__doc.createElement('image')
-			imageNode.setAttribute('format', 'JPEG')
-			imageNode.setAttribute('id', d['image'][0])
-			imageNode.setAttribute('width', '120')
-			imageNode.setAttribute('height', '160')
-			imageNode.appendChild(self.__doc.createTextNode(d['image'][1]))
-
-			coverNode = self.__doc.createElement('cover')
-			coverNode.appendChild(self.__doc.createTextNode(d['image'][0]))
-
-		for name in (	'titleNode', 'otitleNode', 'yearNode', 'genresNode', 'studsNode', 'natsNode',
-						'castsNode', 'dirsNode', 'timeNode', 'allocineNode', 'plotNode',
-						'prodsNode', 'compsNode', 'scensNode' ):
-			entryNode.appendChild(eval(name))
-
-		if d['image']:
-			entryNode.appendChild(coverNode)
-			self.__images.appendChild(imageNode)
-
-		self.__collection.appendChild(entryNode)
-		self.__currentId += 1
-
-	def printXML(self):
-		"""
-		Outputs XML content to stdout
-		"""
-		self.__collection.appendChild(self.__images)
-		print(XML_HEADER);
-		print(DOCTYPE)
-		print(self.__root.toxml())
-
-
-class AlloCineParser:
-	def __init__(self):
-		self.__baseURL 	= 'http://www.allocine.fr'
-		self.__basePath = '/film/fichefilm_gen_cfilm'
-		self.__castPath = '/film/casting_gen_cfilm'
-		self.__searchURL= 'http://www.allocine.fr/recherche/?q=%s'
-		self.__movieURL = self.__baseURL + self.__basePath
-		self.__castURL = self.__baseURL + self.__castPath
-
-		# Define some regexps
-		self.__regExps = {
-			'title' 	: '<div id="title.*?<span.*?>(?P<title>.+?)</span>',
-			'dirs'		: """alis.*?par.*?<a.*?><span.*?>(?P<step1>.+?)</span></a>""",
-			'nat'		: 'Nationalit.*?</span>(?P<nat>.+?)</td',
-			'genres' 	: '<span class="lighten">.*?Genre.*?</span>(?P<step1>.+?)</td',
-			'studio' 	: 'Distributeur</div>(?P<step1>.+?)</td',
-			'time' 		: 'Dur.*?e *?:*?.*?(?P<hours>[0-9])h *(?P<mins>[0-9]*).*?Ann',
-			'year' 		: 'Ann.*?e de production.*?<span.*?>(?P<year>[0-9]{4})</span>',
-			'otitle' 	: 'Titre original *?:*?.*?<td>(?P<otitle>.+?)</td>',
-			'plot'		: '<p itemprop="description">(?P<plot>.*?)</p>',
-			'image'		: '<div class="poster">.*?<img src=\'(?P<image>http://.+?)\'.?',
-		}
-
-		self.__castRegExps = {
-#			'roleactor'		: '<li.*?itemprop="actors".*?>.*?<span itemprop="name">(.*?)</span>.*?<p>.*?R.*?le : (?P<role>.*?)</p>.*?</li>',
-			'roleactor'		: '<li.*?\/personne\/.*?">(.*?)</span>.*?<p.*?R.*?le : (?P<role>.*?)</p>.*?</li',
-			'prods'			  : '<td>[\r\n\t]*Producteur[\r\n\t]*</td>.*?<span.*?>(.*?)</span>',
-			'scens'			  : '<td>[\r\n\t]*Sc.*?nariste[\r\n\t]*</td>.*?<span.*?>(.*?)</span>',
-			'comps'			  : '<td>[\r\n\t]*Compositeur[\r\n\t]*</td>.*?<span.*?>(.*?)</span>',
-		}
-
-		self.__domTree = BasicTellicoDOM()
-
-	def run(self, title):
-		"""
-		Runs the allocine.fr parser: fetch movie related links, then fills and prints the DOM tree
-		to stdout (in tellico format) so that tellico can use it.
-		"""
-		# the script needs the search string to be encoded in utf-8
-		try:
-			# first try system encoding
-			title = unicode(title, sys.stdin.encoding or sys.getdefaultencoding())
-		except UnicodeDecodeError:
-			# on failure, fallback to 'latin-1'
-			title = unicode(title, 'latin-1')
-
-		# now encode for urllib
-		title = title.encode('utf-8')
-		self.__getMovie(title)
-		# Print results to stdout
-		self.__domTree.printXML()
-
-	def __getHTMLContent(self, url):
-		"""
-		Fetch HTML data from url
-		"""
-
-		u = urlopen(url)
-		self.__data = u.read()
-		u.close()
-
-	def __fetchMovieLinks(self, title):
-		"""
-		Retrieve all links related to movie
-		@param title Movie title
-		"""
-		tmp = re.findall("""<td.*?class=['"]totalwidth['"]>.*?<a *href=['"]%s=(?P<page>.*?\.html?)['"] *?>(?P<title>.*?)</a>""" % self.__basePath, self.__data, re.S | re.I)
-		matchList = []
-		for match in tmp:
-			name = re.sub(r'([\r\n]+|<b>|</b>)', '', match[1])
-			name = re.sub(r'<.*?>', '', name)
-			name = re.sub(r'^ *', '', name)
-			#if re.search(title, name, re.I):
-			if len(name) > 0:
-				matchList.append((match[0], name))
-
-		if not matchList: return None
-		return matchList
-
-	def __fetchMovieInfo(self, url, url2):
-		"""
-		Looks for movie information
-		"""
-		self.__getHTMLContent(url)
-		matches = data = {}
-
-		for name, regexp in self.__regExps.iteritems():
-			matches[name] = re.search(regexp, self.__data, re.S | re.I)
-
-			if matches[name]:
-				if name == 'title':
-					data[name] = matches[name].group('title').strip()
-				elif name == 'dirs':
-					dirsList = re.sub('</?a.*?>', '', matches[name].group('step1')).split(',')
-					data[name] = []
-					for d in dirsList:
-						data[name].append(d.strip())
-
-				elif name == 'nat':
-					natList = re.findall(r'<span class=".*?">(.*?)</span>', matches[name].group('nat'), re.DOTALL)
-					data[name] = []
-					for d in natList:
-						data[name].append(d.strip().capitalize())
-
-				elif name == 'genres':
-					genresList = re.findall(r'<span itemprop="genre">(.*?)</span>', matches[name].group('step1'), re.DOTALL)
-					data[name] = []
-					for d in genresList:
-						data[name].append(d.strip().capitalize())
-
-				elif name == 'studio':
-					studiosList = re.findall(r'<span itemprop="productionCompany">(.*?)</span>', matches[name].group('step1'))
-					data[name] = []
-					for d in studiosList:
-						data[name].append(d.strip())
-
-				elif name == 'time':
-					h, m = matches[name].group('hours'), matches[name].group('mins')
-					if len(m) == 0:
-						m = 0
-					totmin = int(h)*60+int(m)
-					data[name] = str(totmin)
-
-				elif name == 'year':
-					data[name] = matches[name].group('year').strip()
-
-				elif name == 'otitle':
-					otitle = re.sub(r'([\r\n]+|<em>|</em>)', '', matches[name].group('otitle'))
-					data[name] = otitle.strip()
-
-				elif name == 'plot':
-					data[name] = matches[name].group('plot').strip()
-				# Cleans up any HTML entities
-				data[name] = self.__cleanUp(data[name])
-
-			else:
-				matches[name] = ''
-
-		# Image check
-		try:
-			imgtmp = re.findall(self.__regExps['image'], self.__data, re.S | re.I)
-			matches['image'] = imgtmp[0]
-
-			# Save image to a temporary folder
-			md5 = genMD5()
-			imObj = urlopen(matches['image'].strip())
-			img = imObj.read()
-			imObj.close()
-			imgPath = "/tmp/%s.jpeg" % md5
-			f = open(imgPath, 'w')
-			f.write(img)
-			f.close()
-
-			# Base64 encoding
-			data['image'] = (md5 + '.jpeg', base64.encodestring(img))
-
-			# Delete temporary image
-			os.remove(imgPath)
-		except:
-			data['image'] = None
-
-		# Now looks for casting information
-		self.__getHTMLContent(url2)
-		page = self.__data.split('\n')
-
-		d = zone = 0
-		data['actors'] = []
-		data['prods'] = []
-		data['scens'] = []
-		data['comps'] = []
-
-		# Actors
-		subset = re.search(r'Acteurs et actrices.*$', self.__data, re.S | re.I)
-		if not subset: return data
-		subset = subset.group(0)
-                #print subset
-		roleactor = re.findall(self.__castRegExps['roleactor'], subset, re.S | re.I)
-		for ra in roleactor:
-                        #print ra
-			data['actors'].append(re.sub(r'([\r\n\t]+)', '', ra[0]))
-			data['actors'].append(re.sub(r'([\r\n\t]+)', '', ra[1]))
-
-		# Producers, Scenarists, Composers
-		for kind in ('prods', 'scens', 'comps'):
-			data[kind] = [re.sub(r'([\r\n\t]+)', '', k).strip() for k in re.findall(self.__castRegExps[kind], subset, re.S | re.I)]
-
-		return data
-
-	def __cleanUp(self, data):
-		"""
-		Cleans up the string(s), replacing raw HTML entities with their
-		ISO Latin-1 replacement text.
-		@param data string or list of strings
-		"""
-		if type(data) == types.ListType:
-			for s in data:
-				for k, v in htmlents.entitydefs.iteritems():
-					s = s.replace("&%s;" % k, v)
-		elif type(data) == types.StringType or type(data) == types.UnicodeType:
-			for k, v in htmlents.entitydefs.iteritems():
-				data = data.replace("&%s;" % k, v)
-		return data
-
-	def __getMovie(self, title):
-		if not len(title): return
-
-		self.__title = title
-		self.__getHTMLContent(self.__searchURL % urllib.quote(self.__title))
-
-		# Get all links
-		links = self.__fetchMovieLinks(title)
-
-		# Now retrieve info
-		if links:
-			for entry in links:
-				data = self.__fetchMovieInfo( url = "%s=%s" % (self.__movieURL, entry[0]), url2 = "%s=%s" % (self.__castURL, entry[0]) )
-				# Add allocine link (custom field)
-				data['allocine'] = "%s=%s" % (self.__movieURL, entry[0])
-				self.__domTree.addEntry(data)
-		else:
-			return None
-
-
-def showUsage():
-	print("Usage: %s movietitle" % sys.argv[0])
-	sys.exit(1)
-
-def main():
-	if len(sys.argv) < 2:
-		showUsage()
-
-	parser = AlloCineParser()
-	parser.run(sys.argv[1])
-
-if __name__ == '__main__':
-	main()
diff --git a/src/fetch/scripts/fr.allocine.py.spec b/src/fetch/scripts/fr.allocine.py.spec
deleted file mode 100644
index 5b3070d06..000000000
--- a/src/fetch/scripts/fr.allocine.py.spec
+++ /dev/null
@@ -1,38 +0,0 @@
-Name=Allocine.fr
-Name[ca]=Allocine.fr
-Name[ca at valencia]=Allocine.fr
-Name[cs]=Allocine.fr
-Name[da]=Allocine.fr
-Name[de]=Allocine.fr
-Name[el]=Allocine.fr
-Name[en_GB]=Allocine.fr
-Name[eo]=Allocine.fr
-Name[es]=Allocine.fr
-Name[et]=Allocine.fr
-Name[eu]=Allocine.fr
-Name[fi]=Allocine.fr
-Name[fr]=Allocine.fr
-Name[gl]=Allocine.fr
-Name[hu]=Allocine.fr
-Name[ia]=Allocine.fr
-Name[it]=Allocine.fr
-Name[ka]=Allocine.fr
-Name[ko]=알로시네(프랑스)
-Name[nl]=Allocine.fr
-Name[nn]=Allocine.fr
-Name[pl]=Allocine.fr
-Name[pt]=Allocine.fr
-Name[pt_BR]=Allocine.fr
-Name[ru]=Allocine.fr
-Name[sk]=Allocine.fr
-Name[sl]=Allocine.fr
-Name[sv]=Allocine.fr
-Name[tr]=Allocine.fr
-Name[uk]=Allocine.fr
-Name[x-test]=xxAllocine.frxx
-Type=data-source
-ArgumentKeys=1
-Arguments=%1
-CollectionType=3
-FormatType=0
-UpdateArgs=%{title}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 6b7d5f679..3fad03583 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -526,20 +526,6 @@ ecm_add_test(adsfetchertest.cpp
     LINK_LIBRARIES fetcherstest ${TELLICO_TEST_LIBS}
 )
 
-ecm_add_test(allocinefetchertest.cpp
-             ../fetch/allocinefetcher.cpp
-             ../fetch/execexternalfetcher.cpp
-             ../translators/bibteximporter.cpp
-             ../translators/risimporter.cpp
-             ../gui/collectiontypecombo.cpp
-    TEST_NAME allocinefetchertest
-    LINK_LIBRARIES fetcherstest
-                   translatorstest
-                   newstuff
-                   ${TELLICO_BTPARSE_LIBS}
-                   ${TELLICO_TEST_LIBS}
-)
-
 ecm_add_test(amazonfetchertest.cpp
              ../fetch/amazonfetcher.cpp
              ../fetch/amazonrequest.cpp
diff --git a/src/tests/allocinefetchertest.cpp b/src/tests/allocinefetchertest.cpp
deleted file mode 100644
index 4dede49f3..000000000
--- a/src/tests/allocinefetchertest.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/***************************************************************************
-    Copyright (C) 2010-2012 Robby Stephenson <robby at periapsis.org>
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or         *
- *   modify it under the terms of the GNU General Public License as        *
- *   published by the Free Software Foundation; either version 2 of        *
- *   the License or (at your option) version 3 or any later version        *
- *   accepted by the membership of KDE e.V. (or its successor approved     *
- *   by the membership of KDE e.V.), which shall act as a proxy            *
- *   defined in Section 14 of version 3 of the license.                    *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
- *                                                                         *
- ***************************************************************************/
-
-#undef QT_NO_CAST_FROM_ASCII
-
-#include "allocinefetchertest.h"
-
-#include "../fetch/execexternalfetcher.h"
-#include "../fetch/allocinefetcher.h"
-#include "../collections/videocollection.h"
-#include "../collectionfactory.h"
-#include "../entry.h"
-#include "../images/imagefactory.h"
-
-#include <KSharedConfig>
-
-#include <QTest>
-
-QTEST_GUILESS_MAIN( AllocineFetcherTest )
-
-AllocineFetcherTest::AllocineFetcherTest() : AbstractFetcherTest() {
-}
-
-void AllocineFetcherTest::initTestCase() {
-  Tellico::RegisterCollection<Tellico::Data::VideoCollection> registerVideo(Tellico::Data::Collection::Video, "video");
-  Tellico::ImageFactory::init();
-
-  m_config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)->group(QStringLiteral("allocine"));
-  m_config.writeEntry("Max Cast", QStringLiteral("5"));
-  m_config.writeEntry("Custom Fields", QStringLiteral("origtitle,allocine"));
-}
-
-void AllocineFetcherTest::cleanupTestCase() {
-  Tellico::ImageFactory::clean(true);
-}
-
-void AllocineFetcherTest::testTitle() {
-  // Allocine script is currently failing
-  return;
-  Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Video, Tellico::Fetch::Title,
-                                       QStringLiteral("Superman Returns"));
-  Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::ExecExternalFetcher(this));
-
-  KConfig config(QFINDTESTDATA("../fetch/scripts/fr.allocine.py.spec"), KConfig::SimpleConfig);
-  KConfigGroup cg = config.group(QStringLiteral("<default>"));
-  cg.writeEntry("ExecPath", QFINDTESTDATA("../fetch/scripts/fr.allocine.py"));
-  fetcher->readConfig(cg);
-  // don't sync() and save the new path
-  cg.deleteEntry("ExecPath");
-
-  Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1);
-
-  QCOMPARE(results.size(), 1);
-
-  Tellico::Data::EntryPtr entry = results.at(0);
-  QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("Superman Returns"));
-  QCOMPARE(entry->field(QStringLiteral("director")), QStringLiteral("Bryan Singer"));
-  QCOMPARE(entry->field(QStringLiteral("producer")), QStringLiteral("Jon Peters; Gilbert Adler; Bryan Singer; Lorne Orleans"));
-  QCOMPARE(entry->field(QStringLiteral("studio")), QStringLiteral("Warner Bros. France"));
-  QCOMPARE(entry->field(QStringLiteral("year")), QStringLiteral("2006"));
-  QCOMPARE(entry->field(QStringLiteral("genre")), QStringLiteral("Fantastique; Action"));
-  QCOMPARE(entry->field(QStringLiteral("nationality")), QString::fromUtf8("Américain; Australien"));
-  QCOMPARE(entry->field(QStringLiteral("running-time")), QStringLiteral("154"));
-  QStringList castList = Tellico::FieldFormat::splitTable(entry->field(QStringLiteral("cast")));
-  QVERIFY(!castList.isEmpty());
-  QCOMPARE(castList.at(0), QStringLiteral("Brandon Routh::Clark Kent / Superman"));
-  QCOMPARE(castList.size(), 8);
-  QVERIFY(!entry->field(QStringLiteral("plot")).isEmpty());
-  QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty());
-  QVERIFY(!entry->field(QStringLiteral("cover")).contains(QLatin1Char('/')));
-}
-
-void AllocineFetcherTest::testTitleAccented() {
-  // Allocine script is currently failing
-  return;
-  Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Video, Tellico::Fetch::Title,
-                                       QStringLiteral("Opération Tonnerre"));
-  Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::ExecExternalFetcher(this));
-
-  KConfig config(QFINDTESTDATA("../fetch/scripts/fr.allocine.py.spec"), KConfig::SimpleConfig);
-  KConfigGroup cg = config.group(QStringLiteral("<default>"));
-  cg.writeEntry("ExecPath", QFINDTESTDATA("../fetch/scripts/fr.allocine.py"));
-  fetcher->readConfig(cg);
-  // don't sync() and save the new path
-  cg.deleteEntry("ExecPath");
-
-  Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1);
-
-  QCOMPARE(results.size(), 1);
-
-  Tellico::Data::EntryPtr entry = results.at(0);
-  QCOMPARE(entry->field(QStringLiteral("title")), QString::fromUtf8("Opération Tonnerre"));
-  QCOMPARE(entry->field(QStringLiteral("titre-original")), QStringLiteral("Thunderball"));
-  QCOMPARE(entry->field(QStringLiteral("studio")), QString());
-}
-
-void AllocineFetcherTest::testTitleAccentRemoved() {
-  // Allocine script is currently failing
-  return;
-  Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Video, Tellico::Fetch::Title,
-                                       QStringLiteral("Operation Tonnerre"));
-  Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::ExecExternalFetcher(this));
-
-  KConfig config(QFINDTESTDATA("../fetch/scripts/fr.allocine.py.spec"), KConfig::SimpleConfig);
-  KConfigGroup cg = config.group(QStringLiteral("<default>"));
-  cg.writeEntry("ExecPath", QFINDTESTDATA("../fetch/scripts/fr.allocine.py"));
-  fetcher->readConfig(cg);
-  // don't sync() and save the new path
-  cg.deleteEntry("ExecPath");
-
-  Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1);
-
-  QCOMPARE(results.size(), 1);
-
-  Tellico::Data::EntryPtr entry = results.at(0);
-  QCOMPARE(entry->field(QStringLiteral("title")), QString::fromUtf8("Opération Tonnerre"));
-}
-
-void AllocineFetcherTest::testPlotQuote() {
-  // Allocine script is currently failing
-  return;
-  Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Video, Tellico::Fetch::Title,
-                                       QStringLiteral("Goldfinger"));
-  Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::ExecExternalFetcher(this));
-
-  KConfig config(QFINDTESTDATA("../fetch/scripts/fr.allocine.py.spec"), KConfig::SimpleConfig);
-  KConfigGroup cg = config.group(QStringLiteral("<default>"));
-  cg.writeEntry("ExecPath", QFINDTESTDATA("../fetch/scripts/fr.allocine.py"));
-  fetcher->readConfig(cg);
-  // don't sync() and save the new path
-  cg.deleteEntry("ExecPath");
-
-  Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1);
-
-  QCOMPARE(results.size(), 1);
-
-  Tellico::Data::EntryPtr entry = results.at(0);
-  QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("Goldfinger"));
-  QVERIFY(!entry->field(QStringLiteral("plot")).contains(QStringLiteral(""")));
-}
-
-void AllocineFetcherTest::testTitleAPI() {
-  Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Video, Tellico::Fetch::Keyword,
-                                       QStringLiteral("Superman Returns"));
-  Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::AllocineFetcher(this));
-  fetcher->readConfig(m_config);
-  Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1);
-
-  QCOMPARE(results.size(), 1);
-
-  Tellico::Data::EntryPtr entry = results.at(0);
-  QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("Superman Returns"));
-  QCOMPARE(entry->field(QStringLiteral("director")), QStringLiteral("Bryan Singer"));
-  QCOMPARE(entry->field(QStringLiteral("producer")), QStringLiteral("Jon Peters; Gilbert Adler; Bryan Singer; Lorne Orleans"));
-  QCOMPARE(entry->field(QStringLiteral("studio")), QStringLiteral("Warner Bros. France"));
-  QCOMPARE(entry->field(QStringLiteral("year")), QStringLiteral("2006"));
-  QCOMPARE(entry->field(QStringLiteral("genre")), QStringLiteral("Fantastique; Action"));
-  QCOMPARE(entry->field(QStringLiteral("nationality")), QStringLiteral("U.S.A.; Australie"));
-  QCOMPARE(entry->field(QStringLiteral("running-time")), QStringLiteral("154"));
-  QStringList castList = Tellico::FieldFormat::splitTable(entry->field(QStringLiteral("cast")));
-  QVERIFY(!castList.isEmpty());
-  QCOMPARE(castList.at(0), QStringLiteral("Brandon Routh::Clark Kent / Superman"));
-  QCOMPARE(castList.size(), 5);
-  QVERIFY(!entry->field(QStringLiteral("plot")).isEmpty());
-  QVERIFY(!entry->field(QStringLiteral("cover")).isEmpty());
-  QVERIFY(!entry->field(QStringLiteral("cover")).contains(QLatin1Char('/')));
-}
-
-void AllocineFetcherTest::testTitleAPIAccented() {
-  Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Video, Tellico::Fetch::Keyword,
-                                       QStringLiteral("Opération Tonnerre"));
-  Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::AllocineFetcher(this));
-  fetcher->readConfig(m_config);
-  Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1);
-
-  QCOMPARE(results.size(), 1);
-
-  Tellico::Data::EntryPtr entry = results.at(0);
-  QCOMPARE(entry->field(QStringLiteral("title")), QString::fromUtf8("Opération Tonnerre"));
-  QCOMPARE(entry->field(QStringLiteral("origtitle")), QStringLiteral("Thunderball"));
-  QCOMPARE(entry->field(QStringLiteral("studio")), QStringLiteral("United International Pictures (UIP)"));
-  QCOMPARE(entry->field(QStringLiteral("director")), QStringLiteral("Terence Young"));
-  QCOMPARE(entry->field(QStringLiteral("color")), QStringLiteral("Color"));
-  QVERIFY(!entry->field(QStringLiteral("allocine")).isEmpty());
-}
-
-// mentioned in https://bugs.kde.org/show_bug.cgi?id=337432
-void AllocineFetcherTest::testGhostDog() {
-  Tellico::Fetch::FetchRequest request(Tellico::Data::Collection::Video, Tellico::Fetch::Keyword,
-                                       QStringLiteral("Ghost Dog: la voie du samourai"));
-  Tellico::Fetch::Fetcher::Ptr fetcher(new Tellico::Fetch::AllocineFetcher(this));
-  fetcher->readConfig(m_config);
-  Tellico::Data::EntryList results = DO_FETCH1(fetcher, request, 1);
-
-  QCOMPARE(results.size(), 1);
-
-  Tellico::Data::EntryPtr entry = results.at(0);
-  QCOMPARE(entry->field(QStringLiteral("title")), QStringLiteral("Ghost Dog: la voie du samourai"));
-}
diff --git a/src/tests/allocinefetchertest.h b/src/tests/allocinefetchertest.h
deleted file mode 100644
index 9219c94ed..000000000
--- a/src/tests/allocinefetchertest.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/***************************************************************************
-    Copyright (C) 2010-2012 Robby Stephenson <robby at periapsis.org>
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or         *
- *   modify it under the terms of the GNU General Public License as        *
- *   published by the Free Software Foundation; either version 2 of        *
- *   the License or (at your option) version 3 or any later version        *
- *   accepted by the membership of KDE e.V. (or its successor approved     *
- *   by the membership of KDE e.V.), which shall act as a proxy            *
- *   defined in Section 14 of version 3 of the license.                    *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
- *                                                                         *
- ***************************************************************************/
-
-#ifndef ALLOCINEFETCHERTEST_H
-#define ALLOCINEFETCHERTEST_H
-
-#include "abstractfetchertest.h"
-
-#include <KConfigGroup>
-
-class AllocineFetcherTest : public AbstractFetcherTest {
-Q_OBJECT
-public:
-  AllocineFetcherTest();
-
-private Q_SLOTS:
-  void initTestCase();
-  void cleanupTestCase();
-
-  void testTitle();
-  void testTitleAccented();
-  void testTitleAccentRemoved();
-  void testPlotQuote();
-
-  void testTitleAPI();
-  void testTitleAPIAccented();
-  void testGhostDog();
-
-private:
-  KConfigGroup m_config;
-};
-
-#endif



More information about the kde-doc-english mailing list