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  <ro...@periapsis.org>
+
+       * Removed data source for Allocine.
+
 2024-01-24  Robby Stephenson  <ro...@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 <ro...@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 <ro...@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                : tell...@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-de...@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.tell...@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@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 <ro...@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("&quot;")));
-}
-
-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 <ro...@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

Reply via email to