From ffb22165da408d653dec3baeed2a5aca972eaea6 Mon Sep 17 00:00:00 2001 From: BordedDev <> Date: Sat, 17 May 2025 13:23:32 +0200 Subject: [PATCH 1/4] Fix YouTube embed parsing and add support for start time; handle missing channel attachments --- src/snek/system/template.py | 99 +++++++++++++++++++++++++++---------- src/snek/view/channel.py | 4 ++ 2 files changed, 78 insertions(+), 25 deletions(-) diff --git a/src/snek/system/template.py b/src/snek/system/template.py index 8bd1ca3..ff3b4c8 100644 --- a/src/snek/system/template.py +++ b/src/snek/system/template.py @@ -1,4 +1,5 @@ import re +from urllib.parse import urlparse, parse_qs from types import SimpleNamespace import mimetypes @@ -90,16 +91,59 @@ def set_link_target_blank(text): def embed_youtube(text): soup = BeautifulSoup(text, "html.parser") for element in soup.find_all("a"): - if element.attrs["href"].startswith("https://www.you"): - video_name = element.attrs["href"].split("/")[-1] - if "v=" in element.attrs["href"]: - video_name = element.attrs["href"].split("?v=")[1].split("&")[0] - # if "si=" in element.attrs["href"]: - # video_name = "?v=" + element.attrs["href"].split("/")[-1] - # if "t=" in element.attrs["href"]: - # video_name += "&t=" + element.attrs["href"].split("&t=")[1].split("&")[0] - embed_template = f'<iframe width="560" height="315" style="display:block" src="https://www.youtube.com/embed/{video_name}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>' + # Check if the link is a YouTube link + url = urlparse(element["href"]) + if ( + url.hostname in ["www.youtu.be", "youtu.be"] + or url.hostname + in [ + "www.youtube.com", + "youtube.com", + "www.youtube-nocookie.com", + "youtube-nocookie.com", + ] + and any(url.path.startswith(p) for p in ["/watch", "/embed"]) + ): + queries = parse_qs(url.query) + if "v" in queries: + video_name = queries["v"][0] + else: + video_name = url.path.split("/")[-1] + + queries.pop("v", None) + + start_time = queries.get("t", None) + if start_time: + queries.pop("t", None) + queries["start"] = [] + for t in start_time: + if t.endswith("s"): + t = start_time[:-1] + if t.isdigit(): + queries["start"].append(t) + else: + queries["start"].append( + str( + sum( + int(x) * 60**i + for i, x in enumerate(reversed(t.split(":"))) + ) + ) + ) + + new_queries = "&".join( + [f"{key}={v}" for key, value in queries.items() for v in value] + ) + + base_url = ( + "youtube-nocookie.com" + if "youtube-nocookie" in url.hostname + else "youtube.com" + ) + + embed_template = f'<iframe width="560" height="315" style="display:block" src="https://www.{base_url}/embed/{video_name}?{new_queries}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>' element.replace_with(BeautifulSoup(embed_template, "html.parser")) + return str(soup) @@ -108,29 +152,35 @@ def embed_image(text): for element in soup.find_all("a"): file_mime = mimetypes.guess_type(element.attrs["href"])[0] - if file_mime and file_mime.startswith("image/") or any( - ext in element.attrs["href"].lower() for ext in [ - ".png", - ".jpg", - ".jpeg", - ".gif", - ".webp", - ".svg", - ".bmp", - ".tiff", - ".ico", - ".heif", - ".heic", - ] + if ( + file_mime + and file_mime.startswith("image/") + or any( + ext in element.attrs["href"].lower() + for ext in [ + ".png", + ".jpg", + ".jpeg", + ".gif", + ".webp", + ".svg", + ".bmp", + ".tiff", + ".ico", + ".heif", + ".heic", + ] + ) ): embed_template = f'<img src="{element.attrs["href"]}" title="{element.attrs["href"]}?width=420" alt="{element.attrs["href"]}" />' element.replace_with(BeautifulSoup(embed_template, "html.parser")) return str(soup) + def enrich_image_rendering(text): soup = BeautifulSoup(text, "html.parser") for element in soup.find_all("img"): - if element.attrs["src"].startswith("/" ): + if element.attrs["src"].startswith("/"): element.attrs["src"] += "?width=240&height=240" picture_template = f''' <picture> @@ -245,7 +295,6 @@ class PythonExtension(Extension): ).set_lineno(line_number) def _to_html(self, md_file, caller): - def fn(source): import subprocess diff --git a/src/snek/view/channel.py b/src/snek/view/channel.py index 7580642..84ee2cd 100644 --- a/src/snek/view/channel.py +++ b/src/snek/view/channel.py @@ -17,6 +17,9 @@ class ChannelAttachmentView(BaseView): relative_url=relative_path ) + if not channel_attachment: + return web.HTTPNotFound() + original_format = mimetypes.guess_type(channel_attachment["path"])[0] format_ = self.request.query.get("format") width = self.request.query.get("width") @@ -88,6 +91,7 @@ class ChannelAttachmentView(BaseView): response.headers["Content-Disposition"] = ( f'attachment; filename="{channel_attachment["name"]}"' ) + response.headers["Content-Type"] = original_format return response async def post(self): From 1bed47fbf59f3fb9bfeeae955272f6b2442d92b3 Mon Sep 17 00:00:00 2001 From: BordedDev <> Date: Sat, 17 May 2025 13:29:25 +0200 Subject: [PATCH 2/4] Re-added webp fallback --- src/snek/system/template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snek/system/template.py b/src/snek/system/template.py index ff3b4c8..6460ff1 100644 --- a/src/snek/system/template.py +++ b/src/snek/system/template.py @@ -181,7 +181,7 @@ def enrich_image_rendering(text): soup = BeautifulSoup(text, "html.parser") for element in soup.find_all("img"): if element.attrs["src"].startswith("/"): - element.attrs["src"] += "?width=240&height=240" + element.attrs["src"] += "?width=240&height=240&format=webp" picture_template = f''' <picture> <source srcset="{element.attrs["src"]}" type="{mimetypes.guess_type(element.attrs["src"])[0]}" /> From 53811ca9b2259cd24dcada84816c3e622b801835 Mon Sep 17 00:00:00 2001 From: BordedDev <> Date: Sat, 17 May 2025 13:55:46 +0200 Subject: [PATCH 3/4] Re-added webp fallback --- src/snek/system/template.py | 6 +++--- src/snek/view/channel.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/snek/system/template.py b/src/snek/system/template.py index 6460ff1..fa8a749 100644 --- a/src/snek/system/template.py +++ b/src/snek/system/template.py @@ -181,12 +181,12 @@ def enrich_image_rendering(text): soup = BeautifulSoup(text, "html.parser") for element in soup.find_all("img"): if element.attrs["src"].startswith("/"): - element.attrs["src"] += "?width=240&height=240&format=webp" + element.attrs["src"] += "?width=240&height=240" picture_template = f''' <picture> <source srcset="{element.attrs["src"]}" type="{mimetypes.guess_type(element.attrs["src"])[0]}" /> - <source srcset="{element.attrs["src"]}" type="image/webp" /> - <img src="{element.attrs["src"]}" title="{element.attrs["src"]}" alt="{element.attrs["src"]}" /> + <source srcset="{element.attrs["src"]}&format=webp" type="image/webp" /> + <img src="{element.attrs["src"]}&format=png" title="{element.attrs["src"]}" alt="{element.attrs["src"]}" /> </picture>''' element.replace_with(BeautifulSoup(picture_template, "html.parser")) return str(soup) diff --git a/src/snek/view/channel.py b/src/snek/view/channel.py index 84ee2cd..90d7c59 100644 --- a/src/snek/view/channel.py +++ b/src/snek/view/channel.py @@ -1,5 +1,6 @@ import asyncio import mimetypes +from os.path import isfile from PIL import Image import pillow_heif.HeifImagePlugin @@ -17,7 +18,7 @@ class ChannelAttachmentView(BaseView): relative_url=relative_path ) - if not channel_attachment: + if not channel_attachment or not isfile(channel_attachment["path"]): return web.HTTPNotFound() original_format = mimetypes.guess_type(channel_attachment["path"])[0] From 0f337e569fba59018d41628e9e471cf0c088113e Mon Sep 17 00:00:00 2001 From: BordedDev <> Date: Sun, 18 May 2025 14:51:38 +0200 Subject: [PATCH 4/4] Fixed gif resizing --- src/snek/view/channel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snek/view/channel.py b/src/snek/view/channel.py index 90d7c59..960605a 100644 --- a/src/snek/view/channel.py +++ b/src/snek/view/channel.py @@ -79,7 +79,7 @@ class ChannelAttachmentView(BaseView): setattr(response, "write", sync_writer) - image.save(response, format=format_) + image.save(response, format=format_, quality=100, optimize=True, save_all=True) setattr(response, "write", naughty_steal)