Search by

glitchr / omnischolar

GlitchArt

Omnischolar: one contract for a researcher's publications - author profiles, works, books and their editions, citations - read from OpenAlex, HAL, Crossref, ORCID, Open Library, arXiv and INSPIRE, merged and deduplicated, exported as BibTeX, RIS or CSL-JSON; and its Symfony bundle.

1.x-dev 2026-10-03 16:45 UTC

This package is auto-updated.

Last update: 2026-10-03 16:46:46 UTC


README

One contract for a researcher's publications: their profile, their works, their books and the editions of each, their citations - read from the services that know them, merged into one list, exported as BibTeX, RIS or CSL-JSON.

$works = $collector->collect([
    'openalex' => 'A5108007452',             // Keitaro Nakatani on OpenAlex
    'hal' => 'Keitaro Nakatani',             // his deposits in HAL, by the name he signs
    'crossref' => '0009-0005-1387-7295',     // the works deposited with his ORCID
]);
$works[0]->title;                            // one record per work, each field from the source trusted for it
$works[0]->pdfUrl;                           // the full text deposited in HAL
$export->bibtex($works);                     // @article{chocron2024acid, ...}

$books = (new Merger())->merge($openlibrary->works('Monica Neagoy'));
$books[0]->editions;                         // the editions of one book, newest first

This package holds the contract (Source\SourceInterface, Source\SourceFactory, Registry), the models (Work, Author, Contributor, Identifier, Venue, Metrics, Affiliation), the Merger, the Collector, the Export and the Symfony bundle. It requires nothing but symfony/http-client-contracts. Each source is a package of its own:

Package Source Key
omnischolar/openalex OpenAlex: profiles and counts (h-index), works, citations, abstracts none (mailto; a free key raises the daily budget)
omnischolar/hal HAL: French open archive, full texts, filter by domain (shs.droit) none
omnischolar/crossref Crossref: reference metadata by DOI, works by ORCID none (mailto)
omnischolar/orcid ORCID: identity, CV (positions, degrees, distinctions), declared works none (public API)
omnischolar/openlibrary Open Library: books, one record per edition, covers none
omnischolar/arxiv arXiv: preprints none
omnischolar/inspire INSPIRE-HEP: physics literature, citation summary none

A source answers what it can - capabilities() says what - and throws NotSupportedException for the rest. Unknown is null or an empty page; a service down or rate limited is an UnavailableException (RateLimitedException), which a caller never caches as "nothing".

The Merger takes one record per work: same DOI, then same ISBN (books), arXiv id, HAL id, then same title in the same year - a different DOI on both sides always keeps two records apart. Each field comes from the source preferred for it (configurable), identifiers are united, and the editions of a book are grouped under the newest one.

Documentation

Symfony

omnischolar:
    sources:
        openalex: { factory: openalex, options: { mailto: '%env(OMNISCHOLAR_MAILTO)%' } }
        hal: { factory: hal }
        droit: { factory: hal, options: { domains: [shs.droit] } }
        openlibrary: { factory: openlibrary, options: { mailto: '%env(OMNISCHOLAR_MAILTO)%' } }
    merger:
        preferences: { abstract: [hal, openalex] }
public function __construct(SourceInterface $openalex, Collector $collector, Export $export) {}

Docker: every source, for real

cd docker && cp .env.dist .env
docker compose run --rm omnischolar sources
docker compose run --rm omnischolar works openalex A5108007452 --from 2024 --to 2024
docker compose run --rm omnischolar merge openlibrary:"Monica Neagoy" crossref:"Monica Neagoy"
docker compose run --rm omnischolar test

License: LGPL-3.0-or-later.