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

Modernize Youtube embeds and exempt from Bleach cleaning, abandon Imgur embeds #384

Merged
merged 3 commits into from
Aug 8, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 12 additions & 2 deletions KerbalStuff/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,22 @@
from .database import db, Base
from .objects import Game, Mod, Featured, ModVersion, ReferralEvent, DownloadEvent, FollowEvent
from .search import search_mods
from .kerbdown import EmbedInlineProcessor

TRUE_STR = ('true', 'yes', 'on')
PARAGRAPH_PATTERN = re.compile('\n\n|\r\n\r\n')

cleaner = bleach.Cleaner(tags=bleach_allowlist.markdown_tags,
attributes=bleach_allowlist.markdown_attrs,
def allow_iframe_attr(tagname: str, attrib: str, val: str) -> bool:
return (any(val.startswith(prefix) for prefix in EmbedInlineProcessor.IFRAME_SRC_PREFIXES)
if attrib == 'src' else
attrib in EmbedInlineProcessor.IFRAME_ATTRIBS)


cleaner = bleach.Cleaner(tags=bleach_allowlist.markdown_tags + ['iframe'],
attributes={ # type: ignore[arg-type]
**bleach_allowlist.markdown_attrs,
'iframe': allow_iframe_attr
},
filters=[bleach.linkifier.LinkifyFilter])


Expand Down
74 changes: 40 additions & 34 deletions KerbalStuff/kerbdown.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,75 @@
import urllib.parse
from urllib.parse import parse_qs, urlparse
from typing import Dict, Any, Match
from typing import Dict, Any, Match, Tuple

from markdown import Markdown
from markdown.extensions import Extension
from markdown.inlinepatterns import Pattern
from markdown.inlinepatterns import InlineProcessor
from markdown.util import etree

EMBED_RE = r'\[\[(?P<url>.+?)\]\]'

class EmbedInlineProcessor(InlineProcessor):
# Don't worry about re.compiling this, markdown.inlinepatterns.Pattern.__init__ does that for us
EMBED_RE = r'\[\[(?P<url>.+?)\]\]'

def embed_youtube(link: urllib.parse.ParseResult) -> etree.Element:
q = parse_qs(link.query)
v = q['v'][0]
el = etree.Element('iframe')
el.set('width', '100%')
el.set('height', '600')
el.set('frameborder', '0')
el.set('allowfullscreen', '')
el.set('src', '//www.youtube-nocookie.com/embed/' + v + '?rel=0')
return el
# Prefixes of the iframe src attributes we generate
YOUTUBE_SRC_PREFIX = '//www.youtube-nocookie.com/embed/'
IMGUR_SRC_PREFIX = '//imgur.com/a/'
IFRAME_SRC_PREFIXES = [YOUTUBE_SRC_PREFIX, IMGUR_SRC_PREFIX]

# Other iframe attributes we generate
IFRAME_ATTRIBS = ['width', 'height', 'frameborder', 'allowfullscreen']

def embed_imgur(link: urllib.parse.ParseResult) -> etree.Element:
a = link.path.split('/')[2]
el = etree.Element('iframe')
el.set('width', '100%')
el.set('height', '550')
el.set('frameborder', '0')
el.set('allowfullscreen', '')
el.set('src', '//imgur.com/a/' + a + '/embed')
return el


class EmbedPattern(Pattern):
def __init__(self, pattern: str, m: Markdown, configs: Dict[str, Any]) -> None:
super(EmbedPattern, self).__init__(pattern, m)
def __init__(self, md: Markdown, configs: Dict[str, Any]) -> None:
super().__init__(self.EMBED_RE, md)
self.config = configs

def handleMatch(self, m: Match[str]) -> etree.Element:
def handleMatch(self, m: Match[str], data: str) -> Tuple[etree.Element, int, int]: # type: ignore[override]
d = m.groupdict()
url = d.get('url')
if not url:
el = etree.Element('span')
el.text = "[[]]"
return el
return el, m.start(0), m.end(0)
try:
link = urlparse(url)
host = link.hostname
except:
el = etree.Element('span')
el.text = "[[" + url + "]]"
return el
return el, m.start(0), m.end(0)
el = None
try:
if host == 'youtube.com' or host == 'www.youtube.com':
el = embed_youtube(link)
el = self._embed_youtube(link)
DasSkelett marked this conversation as resolved.
Show resolved Hide resolved
if host == 'imgur.com' or host == 'www.imgur.com':
el = embed_imgur(link)
el = self._embed_imgur(link)
except:
pass
if el is None:
el = etree.Element('span')
el.text = "[[" + url + "]]"
return el
return el, m.start(0), m.end(0)

def _embed_youtube(self, link: urllib.parse.ParseResult) -> etree.Element:
q = parse_qs(link.query)
v = q['v'][0]
el = etree.Element('iframe')
el.set('width', '100%')
el.set('height', '600')
el.set('frameborder', '0')
el.set('allowfullscreen', '')
el.set('src', self.YOUTUBE_SRC_PREFIX + v + '?rel=0')
return el

def _embed_imgur(self, link: urllib.parse.ParseResult) -> etree.Element:
a = link.path.split('/')[2]
el = etree.Element('iframe')
el.set('width', '100%')
el.set('height', '550')
el.set('frameborder', '0')
el.set('allowfullscreen', '')
el.set('src', self.IMGUR_SRC_PREFIX + a + '/embed')
return el


Expand All @@ -75,5 +81,5 @@ def __init__(self, **kwargs: str) -> None:
# noinspection PyMethodOverriding
def extendMarkdown(self, md: Markdown) -> None:
# BUG: the base method signature is INVALID, it's a bug in flask-markdown
md.inlinePatterns['embeds'] = EmbedPattern(EMBED_RE, md, self.config) # type: ignore[attr-defined]
md.inlinePatterns.register(EmbedInlineProcessor(md, self.config), 'embed', 200)
md.registerExtension(self)