Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added custom Sphinx extension for OpenGraph data #39

Merged
merged 3 commits into from
Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions docs/_ext/ogtag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""Automatically generates Open Graph tags for Sphinx html docs.
Based on https://sphinx-users.jp/cookbook/ogp/index.html
"""

from docutils import nodes
from sphinx import addnodes
from urllib.parse import urljoin


class Visitor:
def __init__(self, document):
self.document = document
self.text_list = []
self.images = []
self.n_sections = 0

def dispatch_visit(self, node):
# Skip toctree
if isinstance(node, addnodes.compact_paragraph) and node.get("toctree"):
raise nodes.SkipChildren

# Collect images
if isinstance(node, nodes.image):
self.images.append(node)

# Collect text (first three sections)
if self.n_sections < 3:

# Collect paragraphs
if isinstance(node, nodes.paragraph):
self.text_list.append(node.astext().replace("\n", " "))

# Include only paragraphs
if isinstance(node, nodes.section):
self.n_sections += 1

def dispatch_departure(self, node):
pass

def get_og_description(self):
# TODO: Find optimal length for description text
text = " ".join(self.text_list)
if len(text) > 200:
text = text[:197] + "..."
return text

def get_og_image_url(self, page_url):
# TODO: Check if picking first image makes sense
# TODO: Return fallback image if no image found on page
if self.images:
return urljoin(page_url, self.images[0]["uri"])
else:
return None


def get_og_tags(context, doctree, config):
# page_url
site_url = config.og_site_url
page_url = urljoin(site_url, context["pagename"] + context["file_suffix"])

# collection
visitor = Visitor(doctree)
doctree.walkabout(visitor)

# og:description
og_desc = visitor.get_og_description()

# og:image
og_image = visitor.get_og_image_url(page_url)

# OGP
tags = """
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="{cfg[og_twitter_site]}" />
<meta property="og:site_name" content="{ctx[shorttitle]}">
<meta property="og:title" content="{ctx[title]}">
<meta property="og:description" content="{desc}">
<meta property='og:url' content="{page_url}">
""".format(
ctx=context, desc=og_desc, page_url=page_url, cfg=config
)
# Add image if present, use default image if no image is found
if og_image:
tags += f'<meta property="og:image" content="{og_image}">'
elif config.og_fallback_image:
tags += f'<meta property="og:image" content="{config.og_fallback_image}">'
return tags


def html_page_context(app, pagename, templatename, context, doctree):
if not doctree:
return

context["metatags"] += get_og_tags(context, doctree, app.config)


def setup(app):
app.add_config_value("og_site_url", None, "html")
app.add_config_value("og_twitter_site", None, "html")
app.add_config_value("og_fallback_image", None, "html")
app.connect("html-page-context", html_page_context)
return {
"version": "0.1",
"parallel_read_safe": True,
"parallel_write_safe": True,
}
32 changes: 21 additions & 11 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# -*- coding: utf-8 -*-
#
# complexity documentation build configuration file, created by
# sphinx-quickstart on Tue Jul 9 22:26:36 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

"""Complexity documentation build configuration file, created by
sphinx-quickstart on Tue Jul 9 22:26:36 2013.

This file is execfile()d with the current directory set to its containing dir.

Note that not all possible configuration values are present in this
autogenerated file.

All configuration values have a default; values that are commented out
serve to show the default.
"""

import os
import sys
Expand All @@ -23,6 +24,9 @@
parent = os.path.dirname(cwd)
sys.path.insert(0, parent)

# Add path for _ext/ogtag.py extension
sys.path.append(os.path.abspath("_ext"))

import pyzillow # noqa

# -- General configuration -----------------------------------------------------
Expand All @@ -35,6 +39,7 @@
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.viewcode",
"ogtag",
# "sphinx.ext.autosummary"
]
# autosummary_generate = True
Expand Down Expand Up @@ -104,6 +109,11 @@

# -- Options for HTML output ---------------------------------------------------

# Constants for _ext/ogtag.py extension
og_site_url = "https://pyzillow.readthedocs.io/en/latest/"
og_twitter_site = "@tcmetzger"
og_fallback_image = "https://www.tcmetzger.de/STATIC/pyzillow_default.png"

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "sphinx_rtd_theme"
Expand Down