Creating a new plugin

To extend the functionality of doi_downloader, you can create a new plugin for retrieving PDFs related to DOI from a specific website. A plugin is a Python module that implements the Plugin interface. Below is a step-by-step guide to creating a new plugin.

Step 1: Create a new Python file

Create a new Python file in the doi_downloader/plugins directory or (for testing only) in the directory doi_downloader/extra_plugins. The name of the file should be descriptive of the plugin's functionality, for example, my_plugin.py. Plugins stored in the extra_plugins directory, will not be stored on Github.

Step 2: Implement the Plugin interface

In your new Python file, you need to implement the Plugin interface. This involves creating a class that inherits from Plugin and implementing the required methods. Here is an example:

import requests
from doi_downloader.plugins import Plugin
from doi_downloader import article_dataobject as ado

MY_API_URL = "https://example.com/{doi}"

class MyPlugin(Plugin):
    def test(self):
        return True

    def fetch_metadata(self, doi):
        url = MY_API_URL.format(doi=doi)
        try:
            response = requests.get(url, headers=headers, params=params)
            if response.status_code == 200:
                paper = response.json()
                title = paper.get("title", "N/A")
                download_link = paper.get("downloadUrl", "N/A")
                data_object = ado.ArticleDataObject(None)
                data_object.set_title(title)
                data_object.set_doi(doi)
                if download_link:
                    data_object.add_pdf_link(download_link)
                return data_object

        except requests.exceptions.RequestException as e:
            print(f"An error occurred: {e}")
            return None

The plugin needs to implement two functions: fetch_metadata and get_pdf_url. The fetch_metadata function should return an ArticleDataObject containing the metadata of the article, while the get_pdf_url function should return the URL of the PDF file. fetch_metadata should handle the API request and parse the response to extract the necessary information.

Step 3: Loading and testing the plugin

The doi_downloader loader module will automtically load all plugin files in the plugins or extra_plugins directory. You can test your plugin by loading your plugin withthis script:

from doi_downloader import loader as ld

doi = "10.1000/xyz123"
metadata = ld.plugins["MyPlugin"].fetch_metadata(doi)
pdf_urls = ld.plugins["MyPlugin"].get_pdf_urls(doi)

Step 4: Caching API results

Caching is handled centrally by the Plugin base class, so a new plugin does not need to implement it. Plugin.__init__ already sets up self.cache = Cache("database.db", self.plugin_name), and the inherited get_pdf_urls(doi, cache_mode=CacheMode.CACHE_FIRST, ttl=10) method reads from and writes to that cache around your fetch_metadata call. You only need to implement fetch_metadata; get_pdf_urls is inherited as-is.

cache_mode (from doi_downloader.plugins.CacheMode) controls how the cache is used:

  • CacheMode.REFRESH: skip the cache, call fetch_metadata, and store the result.
  • CacheMode.CACHE_ONLY: read from the cache only; return an empty list if there is no cached data.
  • CacheMode.CACHE_FIRST (default): try the cache first, falling back to REFRESH behavior if there is no cached data.
from doi_downloader import loader as ld
from doi_downloader.plugins import CacheMode

doi = "10.1000/xyz123"
pdf_urls = ld.plugins["MyPlugin"].get_pdf_urls(doi, cache_mode=CacheMode.CACHE_FIRST)

The available plugins in the doi_downloader/plugins directory can be inspected for more example plugins code.