Skip to content

Commit

Permalink
Add support for media services like YouTube, etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
facelessuser committed Nov 10, 2021
1 parent 4bda1cf commit e33d122
Showing 1 changed file with 120 additions and 9 deletions.
129 changes: 120 additions & 9 deletions pymdownx/embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,77 @@
import copy


RE_YOUTUBE = re.compile(
r"""(?ix)^
(?:https://(?:www\.)?youtube\.com/embed/|https://youtu\.be/|https://www.youtube.com/watch?v=)
(?P<id>[a-z0-9-]+)(?P<extra>[?&].*)?$
"""
)

RE_DAILYMOTION = re.compile(
r"""(?ix)^
(?:https://(?:www\.)?dailymotion\.com/(?:embed/)?video/)
(?P<id>[a-z0-9]+)(?P<extra>[?&].*)?$
"""
)

RE_VIMEO = re.compile(
r"""(?ix)^
(?:https://(?:www\.)?vimeo\.com/|https://player\.vimeo\.com/video/)
(?P<id>[0-9]+)(?P<extra>[?&].*)?$
"""
)


def youtube(url):
"""Match YouTube source and return a suitable URL."""

src = None
m = RE_YOUTUBE.match(url)
if m:
key = m.group('id')
src = 'https://www.youtube.com/embed/{}'.format(key)
return src


def dailymotion(url):
"""Match Dailymotion source and return a suitable URL."""

src = None
m = RE_DAILYMOTION.match(url)
if m:
key = m.group('id')
src = 'https://www.dailymotion.com/embed/video/{}'.format(key)
return src


def vimeo(url):
"""Match Vimeo source and return a suitable URL."""

src = None
m = RE_VIMEO.match(url)
if m:
key = m.group('id')
src = 'https://player.vimeo.com/video/{}'.format(key)
return src


SERVICES = {
"youtube": {
"handler": youtube,
"defaults": {"allowfullscreen": '', "frameborder": '0'}
},
"dailymotion": {
"handler": dailymotion,
"defaults": {"allowfullscreen": '', "frameborder": '0'}
},
"vimeo": {
"handler": vimeo,
"defaults": {"allowfullscreen": '', "frameborder": '0'}
}
}


class EmbedMediaTreeprocessor(Treeprocessor):
"""
Find video links and parse them up.
Expand All @@ -32,20 +103,22 @@ class EmbedMediaTreeprocessor(Treeprocessor):
'flac': 'audio/flac'
}

def __init__(self, md, video_defaults, audio_defaults):
def __init__(self, md, video_defaults, audio_defaults, services):
"""Initialize."""

self.services = copy.deepcopy(SERVICES)
for k, v in services.items():
if k not in self.services:
self.services[k] = copy.deepcopy(v)
else:
self.services[k] = {**self.services[k], **copy.deepcopy(v)}
self.video_defaults = video_defaults
self.audio_defaults = audio_defaults

super().__init__(md)

def run(self, root):
"""Shorten popular git repository links."""

# Grab the elements of interest and form a parent mapping
links = [e for e in root.iter() if e.tag.lower() in ('img',)]
parent_map = {c: p for p in root.iter() for c in p}
def process_embedded_media(self, links, parent_map):
"""Process embedded video and audio files."""

# Evaluate links
for link in reversed(links):
Expand Down Expand Up @@ -146,6 +219,42 @@ def run(self, root):
# Remove the old link
parent.remove(link)

def process_embedded_media_service(self, links, parent_map):
"""Process links to embedded media services like YouTube, etc."""

for link in reversed(links):
for service in self.services.values():
src = service['handler'](link.attrib.get('href', ''))
if src:
orig = copy.copy(link.attrib)
orig['src'] = src
del orig['href']
attrib = {**copy.copy(service['defaults']), **orig}
el = etree.Element('iframe', attrib)
parent = parent_map[link]
for index, c in enumerate(list(parent), 0):
if c is el:
break
parent.insert(index, el)
parent.remove(link)

def run(self, root):
"""Shorten popular git repository links."""

# Grab the elements of interest and form a parent mapping
images = []
anchors = []
parent_map = {c: p for p in root.iter() for c in p}
for e in root.iter():
tag = e.tag.lower()
if tag == 'img':
images.append(e)
elif tag == 'a':
anchors.append(e)

self.process_embedded_media(images, parent_map)
self.process_embedded_media_service(anchors, parent_map)

return root


Expand All @@ -163,7 +272,8 @@ def __init__(self, *args, **kwargs):
"audio_defaults": [
{'controls': '', 'preload': 'metadata'},
"Video default attributes - Default: {}"
]
],
"services": [{}, "Additional services and service overrides."]
}
super().__init__(*args, **kwargs)

Expand All @@ -175,7 +285,8 @@ def extendMarkdown(self, md):
media = EmbedMediaTreeprocessor(
md,
config['video_defaults'],
config['audio_defaults']
config['audio_defaults'],
config['services']
)
md.treeprocessors.register(media, 'embed', 7.9)

Expand Down

0 comments on commit e33d122

Please sign in to comment.