Voici un début de générateur de catalogue OPDS pour Wikisource. N’hésitez pas à le modifier, le transformer et l’utiliser sur votre propre serveur.

OPDS Creator 0.1 modifier

opds.php modifier

<?php

$infos = array(
        'fr' => array(
                'namespaces' => array(
                        'category' => 'Category',
                        'catégorie' => 'Category'
                        ),
                'mainCategories' => array(
                        array(
                                'title' => 'Catégorie:Thèmes‎',
                                'content' => 'Livres par thèmes'
                                )
                        )
                ),
        'en' => array(
                'namespaces' => array(
                        'category' => 'Category'
                        ),
                'mainCategories' => array()
                )
        );

$i18n = array(
        'fr' => array(
                'opds.see-on-wikisource' => 'Voir sur Wikisource',
                'opds.search-on-wikisource' => 'Rechercher sur Wikisource',
                'opds.mainpage' => 'Page d\'Accueil',
                'opds.wiki' => 'Wikisource'
                ),
        'en' => array(
                'opds.see-on-wikisource' => 'See on Wikisource',
                'opds.search-on-wikisource' => 'Search on Wikisource',
                'opds.mainpage' => 'Main page',
                'opds.wiki' => 'Wikisource'
                )
        );

$myPath = 'http://genewiki.legtux.org/opds/opds.php'; //Placer ici l’url du fichier.
date_default_timezone_set('UTC');


class OPDS {
        protected $lang = '';
        protected $page = '';
        protected $id = '';
        protected $space = 'main';
        protected $url = '';
        protected $info = null;
        protected $i18n = null;
        protected $myPath = '';


        public function __construct($infos, $i18n, $myPath) {
                $this->info = $infos;
                $this->i18n = $i18n;
                $this->lang = isset($_GET['lang']) ? strtolower(substr($_GET['lang'], 0, 2)) : $this->getLang();
                if(!array_key_exists($this->lang, $this->info))
                        $this::error(404);
                $this->id = isset($_GET['page']) ? htmlspecialchars(urldecode($_GET['page'])) : '';
                $page = explode(':', $this->id, 2);
                if(isset($page[1])) {
                        $namespace = strtolower($page[0]);
                        if(!$this->info[$this->lang]['namespaces'][$namespace])
                                $this::error(404);
                        $this->space = $this->info[$this->lang]['namespaces'][$namespace];
                        $this->page = $page[1];
                        $this->url = 'http://' . $this->lang . '.wikisource.org/wiki/' . urlencode($this->space) . ':' . urlencode($this->page);
                } else {
                        $this->page = $page[0];
                        $this->url = 'http://' . $this->lang . '.wikisource.org/wiki/' . urlencode($this->page);
                }
                $this->myPath = $myPath;
        }

        protected function getLang() {
                if(!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
                        $langs = explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']);
                        foreach($langs as $lang) {
                                $sLang = strtolower(substr($lang, 0, 2));
                                if(array_key_exists($lang, $this->info)) {
                                        return $lang;
                                }
                        }
                }
                return '';
        }

        protected function getApiData($params) {
                $data = 'action=query&format=php';
                foreach($params as $param_name => $param_value) {
                        $data .= '&' . $param_name . '=' . urlencode($param_value);
                }
                $ch = curl_init($this->lang . '.wikisource.org/w/api.php?' . $data);
                curl_setopt($ch, CURLOPT_USERAGENT, 'OPDS Creator 0.1');
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                $response = curl_exec($ch);
                if (curl_errno($ch)) {
                        return curl_error($ch);
                }
                curl_close($ch);
                return unserialize($response);
        }

        protected function feed($data) {
                require('views/feed.php');
        }

        protected function page() {
                $data = array(
                        'categories' => array()
                        );
                $response = $this->getApiData(array('titles' => $this->page, 'prop' => 'categories', '!hidden' => 'true'));
                foreach($response['query']['pages'] as $list) {
                        if(isset($list['missing'])) {
                                $this::error(404);
                        } else if(isset($list['categories'])) {
                                $data['categories'] = $list['categories'];
                        }
                }
                require('views/page.php');
        }

        protected function category() {
                 $data = array(
                        'categories' => array(),
                        'pages' => array(),
                        'subcategories' => array(),
                        'langlinks' => array()
                        );

                $response = $this->getApiData(array('prop' => 'categories', 'titles' => $this->id, '!hidden' => 'true'));
                foreach($response['query']['pages'] as $list) {
                        if(isset($list['missing'])) {
                                $this::error(404);
                        } else if(isset($list['categories'])) {
                                $data['categories'] = $list['categories'];
                        }
                }

                $response = $this->getApiData(array('list' => 'categorymembers', 'cmtitle' => $this->id, 'cmnamespace' => '0', 'cmlimit' => '200'));
                if(isset($response['query']['categorymembers'])) {
                        $data['pages'] = $response['query']['categorymembers'];
                }

                $response = $this->getApiData(array('list' => 'categorymembers', 'cmtitle' => $this->id, 'cmnamespace' => '14', 'cmlimit' => '200'));
                if(isset($response['query']['categorymembers'])) {
                        $data['subcategories'] = $response['query']['categorymembers'];
                }

                $response = $this->getApiData(array('prop' => 'langlinks', 'titles' => $this->id, 'lllimit' => '100'));
                foreach($response['query']['pages'] as $list) {
                        if(isset($list['langlinks'])) {
                                $data['langlinks'] = $list['langlinks'];
                        }
                }
                $this->feed($data);
        }

        protected function mainPage() {
                 $data = array(
                        'categories' => array(),
                        'pages' => array(),
                        'subcategories' => $this->info[$this->lang]['mainCategories'],
                        'langlinks' => array()
                        );

                 foreach($this->info as $lang) {
                        $data['langlinks'][] = array('lang' => $lang, '*' => '');
                }
                $this->feed($data);
        }

        protected static function error($id) {
                switch($id){
                        case 404:
                                header('HTTP/1.0 404 Not Found');
                                exit;
                }
        }

        public function run() {
                if($this->page == '') {
                        $this->mainPage();
                } else {
                        switch($this->space) {
                                case 'main':
                                        $this->page();
                                        break;
                                case 'Category':
                                        $this->category();
                                        break;
                        }
                }
        }
        
        protected function getLink($page, $lang = '') {
                if($lang == '')
                        $lang = $this->lang;
                return $this->myPath . '?lang=' . $lang . '&amp;page=' . urlencode($page);
        }
}

$opds = new OPDS($infos, $i18n, $myPath);
$opds->run();

views/feed.php modifier

<?php

if($data['pages'] == array()) {
        header('Content-Type: application/atom+xml;profile=opds-catalog;kind=navigation');
} else {
        header('Content-Type: application/atom+xml;profile=opds-catalog;kind=acquisition');
}

$totalResults = count($data['pages']);
$updated = date(DATE_ATOM);
$text = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="{$this->lang}" xmlns:app="http://www.w3.org/2007/app" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:opds="http://opds-spec.org/2010/catalog" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns="http://www.w3.org/2005/Atom">
  <title>{$this->page}</title>
  <id>{$this->url}</id>
  <updated>{$updated}</updated>
  <link type="text/html" title="{$this->i18n[$this->lang]['opds.see-on-wikisource']}" rel="alternate" href="{$this->url}" />
  <link type="application/atom+xml" rel="self" href="{$this->getLink($this->id)}"/>
  <icon>http://assets2.feedbooks.net/images/favicon.ico?t=1303221755</icon>
  <author>
    <name>Wikisource</name>
    <uri>http://{$this->lang}.wikisource.org</uri>
  </author>
  <link type="application/atom+xml;profile=opds-catalog;kind=navigation" rel="start" title="{$this->i18n[$this->lang]['opds.mainpage']}" href="{$this->getLink('')}" />
  <link type="application/opensearchdescription+xml" rel="search" title="{$this->i18n[$this->lang]['opds.search-on-wikisource']}" href="http://{$this->lang}.wikisource.org/w/opensearch_desc.php" />
  <opensearch:totalResults>{$totalResults}</opensearch:totalResults>
  <opensearch:itemsPerPage>200</opensearch:itemsPerPage>
  <link type="application/atom+xml;profile=opds-catalog;kind=acquisition" rel="next" title="Page Suivante" href="http://www.feedbooks.com/books/top.atom?page=2&amp;range=month" />
EOT;
foreach($data['categories'] as $categorie) {
        $title = explode(':', $categorie['title'], 2);
        $text .= '<category label="' . $title[1] . '" term="' . sha1($title[1]) . '" />' . "\n";
}
foreach($data['langlinks'] as $langlink) {
       $text .= '<link type="application/atom+xml;profile=opds-catalog;kind=acquisition" rel="http://opds-spec.org/facet" title="' . $langlink['lang'] . '" opds:facetGroup="Langue" href="' . $this->getLink($langlink['*'], $langlink['lang'])  . '" />' . "\n";
}
foreach($data['subcategories'] as $categorie) {
        $url = 'http://' . $this->lang . '.wikisource.org/wiki/' . $categorie['title'];
        $title = explode(':', $categorie['title'], 2);
        $rel = isset($categorie['rel']) ? 'http://opds-spec.org/sort/' . $categorie['rel'] : 'subsection';
        $content = isset($categorie['content']) ? $categorie['content'] : $title[1];
        $text .= <<<EOT
<entry>
  <title>{$title[1]}</title>
  <id>{$url}</id>
  <updated>2011-10-26T13:24:34Z</updated>
  <dcterms:language>{$this->lang}</dcterms:language>
  <summary>{$content}</summary>
  <dcterms:source>Wikisource</dcterms:source>
  <content type="text">{$title[1]}</content>
  <link type="application/atom+xml;profile=opds-catalog" rel="{$rel}" href="{$this->getLink($categorie['title'])}"/>
</entry>
EOT;
}

foreach($data['pages'] as $page) {
        $url = 'http://' . $this->lang . '.wikisource.org/wiki/' . $page['title'];
        $text .= <<<EOT
<entry>
  <title>{$page['title']}</title>
  <id>{$url}</id>
  <author>
    <name>Vatsyayana</name>
    <uri>http://www.feedbooks.com/author/91</uri>
  </author>
  <published>2011-07-08T14:45:05Z</published>
  <updated>2011-10-26T13:24:34Z</updated>
  <dcterms:language>{$this->lang}</dcterms:language>
  <summary>Empty</summary>
  <dcterms:source>Wikisource</dcterms:source>
  <link type="application/atom+xml;profile=opds-catalog;type=entry" rel="alternate" title="Full entry" href="{$this->getLink($page['title'])}" />
  <link type="text/html" title="{$this->i18n[$this->lang]['opds.see-on-wikisource']}" rel="alternate" href="{$url}" />
</entry>
EOT;
}
$text .= '</feed>';
echo $text;

views/page.php modifier

<?php
header('Content-type: application/atom+xml;type=entry;profile=opds-catalog');
$text = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<entry xml:lang="{$this->lang}" xmlns="http://www.w3.org/2005/Atom" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:thr="http://purl.org/syndication/thread/1.0">
  <title>{$this->page}</title>
  <id>{$this->url}</id>
  <author>
    <name>Vatsyayana</name>
    <uri>http://www.feedbooks.com/author/91</uri>
  </author>
  <published>2011-07-08T14:45:05Z</published>
  <updated>2011-07-08T14:45:05Z</updated>
  <dcterms:language>{$this->lang}</dcterms:language>
EOT;
foreach($data['categories'] as $categorie) {
        $title = explode(':', $categorie['title'], 2);
        $text .= '<category label="' . $title[1] . '" term="' . sha1($title[1]) . '" />' . "\n";
}
$text .= <<<EOT
  <summary>Empty</summary>
  <dcterms:source>Wikisource</dcterms:source>
  <link type="text/html" title="{$this->i18n[$this->lang]['opds.see-on-wikisource']}" rel="alternate" href="{$this->url}"/>
  <link type="application/atom+xml;profile=opds-catalog;kind=acquisition" title="Du m&#234;me auteur" rel="related" href="http://www.feedbooks.com/author/91/books/top.atom?lang=fr"/>
</entry>
EOT;
echo $text;