From 0d2ba42deaced1d05d813d12155a3742ce934698 Mon Sep 17 00:00:00 2001
From: snow flurry <snow@datagirl.xyz>
Date: Sat, 1 Mar 2025 15:04:58 -0800
Subject: [PATCH] New plugins!

- Media BBCode tags
- Use youtube-nocookie.com for YouTube embeds
- Topic muting
---
 plugin/Makefile                               |   5 +-
 plugin/f9_theme/src/css/index.css             |   8 +-
 .../src/css/jquery.sceditor.default.css       |   6 +-
 .../src/css/jquery.sceditor.theme.css         |   4 +
 plugin/media_bbc/Makefile                     |   3 +
 plugin/media_bbc/src/Subs-MediaCode.php       |  68 +++++++
 plugin/media_bbc/src/asset/icon_audio.svg     |   1 +
 plugin/media_bbc/src/asset/icon_video.svg     |   1 +
 plugin/media_bbc/src/package-info.xml         |  33 ++++
 plugin/media_bbc/src/readme.txt               |   3 +
 plugin/media_bbc/src/sceditor.mediabbc.css    |  11 ++
 plugin/media_bbc/src/sceditor.mediabbc.js     | 176 ++++++++++++++++++
 plugin/topic_mute/src/Subs-TopicMute.php      |   5 +
 plugin/topic_mute/src/TopicMute.php           |   5 +-
 plugin/topic_mute/src/dbinstall.php           |   2 +-
 plugin/topic_mute/src/package-info.xml        |   4 +
 plugin/topic_mute/src/topic-mute.js           |  15 ++
 plugin/yt_nocookie/Makefile                   |   3 +
 plugin/yt_nocookie/src/Subs-YtNoOrigin.php    |  19 ++
 plugin/yt_nocookie/src/package-info.xml       |  19 ++
 plugin/yt_nocookie/src/readme.txt             |   3 +
 21 files changed, 388 insertions(+), 6 deletions(-)
 create mode 100644 plugin/media_bbc/Makefile
 create mode 100644 plugin/media_bbc/src/Subs-MediaCode.php
 create mode 100644 plugin/media_bbc/src/asset/icon_audio.svg
 create mode 100644 plugin/media_bbc/src/asset/icon_video.svg
 create mode 100644 plugin/media_bbc/src/package-info.xml
 create mode 100644 plugin/media_bbc/src/readme.txt
 create mode 100644 plugin/media_bbc/src/sceditor.mediabbc.css
 create mode 100644 plugin/media_bbc/src/sceditor.mediabbc.js
 create mode 100644 plugin/topic_mute/src/topic-mute.js
 create mode 100644 plugin/yt_nocookie/Makefile
 create mode 100644 plugin/yt_nocookie/src/Subs-YtNoOrigin.php
 create mode 100644 plugin/yt_nocookie/src/package-info.xml
 create mode 100644 plugin/yt_nocookie/src/readme.txt

diff --git a/plugin/Makefile b/plugin/Makefile
index 536d339..e058c01 100644
--- a/plugin/Makefile
+++ b/plugin/Makefile
@@ -1,7 +1,10 @@
 MODS :=		\
 	f9_buttons	\
 	f9_emotes	\
-	f9_theme
+	f9_theme	\
+	media_bbc	\
+	yt_nocookie	\
+	topic_mute
 
 PKGDIR := $(PWD)/../packages
 
diff --git a/plugin/f9_theme/src/css/index.css b/plugin/f9_theme/src/css/index.css
index 2eb587a..09a53fb 100644
--- a/plugin/f9_theme/src/css/index.css
+++ b/plugin/f9_theme/src/css/index.css
@@ -4172,7 +4172,7 @@ tr[id^='list_news_lists_'] textarea {
 }
 
 /* Responsive Youtube embed */
-.videocontainer {
+.videocontainer, .media-video, .media-audio {
 	max-width: 560px;
 }
 .centertext .videocontainer,
@@ -4196,11 +4196,15 @@ tr[id^='list_news_lists_'] textarea {
 	width: 100% !important;
 	height: 100% !important;
 }
-.videocontainer video {
+.videocontainer video, .media-video video {
 	object-fit: contain;
 	background: black;
 	max-width: 100%;
 }
+.media-video video, .media-audio audio {
+    width: 100%;
+}
+
 
 .backtrace:not(:last-child) {
 	padding-bottom: 0.5em;
diff --git a/plugin/f9_theme/src/css/jquery.sceditor.default.css b/plugin/f9_theme/src/css/jquery.sceditor.default.css
index b32703c..b7d019d 100644
--- a/plugin/f9_theme/src/css/jquery.sceditor.default.css
+++ b/plugin/f9_theme/src/css/jquery.sceditor.default.css
@@ -113,7 +113,7 @@ img[data-sceditor-emoticon] {
 }
 
 /* Responsive Youtube embed */
-.videocontainer {
+.videocontainer, .media-video, .media-audio {
 	max-width: 560px;
 }
 .videocontainer div {
@@ -128,6 +128,10 @@ img[data-sceditor-emoticon] {
 	height: 100% !important;
 }
 
+.media-video video, .media-audio audio {
+    width: 100%;
+}
+
 .floatleft, .floatright {
 	max-width: 45%;
 	border: 1px dashed var(--separator);
diff --git a/plugin/f9_theme/src/css/jquery.sceditor.theme.css b/plugin/f9_theme/src/css/jquery.sceditor.theme.css
index 7377a93..7d6bffe 100644
--- a/plugin/f9_theme/src/css/jquery.sceditor.theme.css
+++ b/plugin/f9_theme/src/css/jquery.sceditor.theme.css
@@ -26,6 +26,10 @@ div.sceditor-dropdown a:link {
 	color: var(--bold-body-text);
 }
 
+div.sceditor-dropdown label {
+    color: var(--bold-body-text);
+}
+
 div.sceditor-dropdown .button {
 	background: var(--main-background);
 	color: var(--bold-body-text);
diff --git a/plugin/media_bbc/Makefile b/plugin/media_bbc/Makefile
new file mode 100644
index 0000000..6de3400
--- /dev/null
+++ b/plugin/media_bbc/Makefile
@@ -0,0 +1,3 @@
+PROJECT := media_bbc
+
+include ../plugin.mk
diff --git a/plugin/media_bbc/src/Subs-MediaCode.php b/plugin/media_bbc/src/Subs-MediaCode.php
new file mode 100644
index 0000000..deffef1
--- /dev/null
+++ b/plugin/media_bbc/src/Subs-MediaCode.php
@@ -0,0 +1,68 @@
+<?php
+
+function hook_media_bbcode(&$codes, &$no_autolink_tags) {
+    $codes[] = array(
+        'tag' => 'video',
+        'type' => 'unparsed_content',
+        'content' => '<div class="media-video"><video data-src="$1" controls><source src="$1" /></video></div>',
+        'disabled_content' => '<a href="$1" target="_blank" rel="noopener">$1</a>',
+        'block_level' => true,
+    );
+    $codes[] = array(
+        'tag' => 'audio',
+        'type' => 'unparsed_content',
+        'content' => '<div class="media-audio"><audio data-src="$1" controls><source src="$1" /></audio></div>',
+        'disabled_content' => '<a href="$1" target="_blank" rel="noopener">$1</a>',
+        'block_level' => true,
+    );
+
+    $no_autolink_tags[] = 'video';
+    $no_autolink_tags[] = 'audio';
+}
+
+function hook_media_bbcode_buttons(&$bbc_tags) {
+    $group_idx = 0;
+    $idx = 0;
+    // We want to put our media buttons next to the yt/image/etc group, so find
+    // the image button
+    foreach ($bbc_tags as $group) {
+        $idx = 0;
+        foreach ($group as $item) {
+            if (isset($item['code']) && $item['code'] == 'image') {
+                // done!
+                break 2;
+            }
+            $idx++;
+        }
+        $group_idx++;
+    }
+
+    $media_btns = array(
+        array(
+            'code' => 'video',
+            'description' => 'Insert a video',
+        ),
+        array(
+            'code' => 'audio',
+            'description' => 'Insert audio',
+        ),
+    );
+
+    $bbc_tags[$group_idx] = array_merge(
+        array_slice($bbc_tags[$group_idx], 0, $idx, true),
+        $media_btns,
+        array_slice($bbc_tags[$group_idx], $idx, null, true),
+    );
+}
+
+function media_sce_options(&$sce_options) {
+    loadJavaScriptFile('sceditor.mediabbc.js', array('minimize' => true), 'smf_sceditor_media');
+    loadCSSFile('sceditor.mediabbc.css', array('minimize' => true));
+}
+
+function media_bbc_credits() {
+    global $context;
+    $context['credits_modifications'][] = 'Silk SVG icons by <a href="https://github.com/frhun">@frhun</a>, licensed under CC-BY-SA';
+}
+
+?>
diff --git a/plugin/media_bbc/src/asset/icon_audio.svg b/plugin/media_bbc/src/asset/icon_audio.svg
new file mode 100644
index 0000000..92a9b7a
--- /dev/null
+++ b/plugin/media_bbc/src/asset/icon_audio.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="64" height="64" viewBox="0 0 64 64" version="1.1" id="svg8" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"><defs id="defs2"><linearGradient id="linearGradient1267"><stop style="stop-color:#3f3f3f;stop-opacity:1" offset="0" id="stop1263"/><stop style="stop-color:#838383;stop-opacity:1" offset="1" id="stop1265"/></linearGradient><linearGradient id="linearGradient1259"><stop style="stop-color:#646460;stop-opacity:1" offset="0" id="stop1255"/><stop style="stop-color:#838381;stop-opacity:1" offset="1" id="stop1257"/></linearGradient><linearGradient id="linearGradient1251"><stop style="stop-color:#858580;stop-opacity:1" offset="0" id="stop1247"/><stop style="stop-color:#c3c3c2;stop-opacity:1" offset="1" id="stop1249"/></linearGradient><linearGradient xlink:href="#linearGradient1251" id="linearGradient1253" x1="32" y1="44" x2="16" y2="20" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient1259" id="linearGradient1261" x1="4" y1="52" x2="4" y2="16" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient1267" id="linearGradient1269" x1="24" y1="40" x2="24" y2="24" gradientUnits="userSpaceOnUse"/></defs><metadata id="metadata5"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g id="layer1"><path style="fill:url(#linearGradient1253);fill-opacity:1;stroke:url(#linearGradient1261);stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;paint-order:markers fill stroke" d="M 2,22 V 42 H 14 L 30,52 V 12 L 14,22 Z" id="path1182"/><path id="path1184" style="fill:#e1293b;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;paint-order:markers fill stroke" d="m 35.999996,27.999998 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4"/><path id="path1184-5" style="fill:#e1293b;stroke:#e1293b;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;paint-order:markers fill stroke" d="m 46.392301,25.999998 a 12,12 0 0 1 0,12"/><path id="path1184-5-6" style="fill:#e1293b;stroke:#e1293b;stroke-width:6;stroke-linecap:round;stroke-linejoin:round;paint-order:markers fill stroke" d="m 56.784605,17.999997 a 24,28 0 0 1 10e-7,28.000001"/><path id="path1182-2" style="fill:url(#linearGradient1269);stroke-width:4;stroke-linecap:round;stroke-linejoin:round;paint-order:markers fill stroke" d="m 24,22.824219 -6.820312,4.263672 A 6.0006,6.0006 0 0 1 14,28 H 8 v 8 h 6 a 6.0006,6.0006 0 0 1 3.179688,0.912109 L 24,41.175781 Z"/></g></svg>
\ No newline at end of file
diff --git a/plugin/media_bbc/src/asset/icon_video.svg b/plugin/media_bbc/src/asset/icon_video.svg
new file mode 100644
index 0000000..308b2df
--- /dev/null
+++ b/plugin/media_bbc/src/asset/icon_video.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg width="64" height="64" viewBox="0 0 64 64" version="1.1" id="svg8" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"><defs id="defs2"><linearGradient id="linearGradient1063"><stop style="stop-color:#5a5a5a;stop-opacity:1" offset="0" id="stop1059"/><stop style="stop-color:#9d9d9d;stop-opacity:1" offset="1" id="stop1061"/></linearGradient><linearGradient id="linearGradient1049"><stop style="stop-color:#424242;stop-opacity:1" offset="0" id="stop1045"/><stop style="stop-color:#686868;stop-opacity:1" offset="1" id="stop1047"/></linearGradient><linearGradient id="linearGradient1037"><stop style="stop-color:#909090;stop-opacity:1" offset="0" id="stop1033"/><stop style="stop-color:#b4b4b4;stop-opacity:1" offset="1" id="stop1035"/></linearGradient><linearGradient id="linearGradient1027"><stop style="stop-color:#676767;stop-opacity:1" offset="0" id="stop1023"/><stop style="stop-color:#c8c8c8;stop-opacity:1" offset="1" id="stop1025"/></linearGradient><linearGradient id="linearGradient1019"><stop style="stop-color:#2b2b2b;stop-opacity:0.99215686" offset="0" id="stop1015"/><stop style="stop-color:#8b8b8b;stop-opacity:0.81568629" offset="1" id="stop1017"/></linearGradient><linearGradient id="linearGradient940"><stop style="stop-color:#f3be41;stop-opacity:1" offset="0" id="stop936"/><stop style="stop-color:#f9e0a4;stop-opacity:1" offset="1" id="stop938"/></linearGradient><linearGradient id="linearGradient900"><stop style="stop-color:#639bd7;stop-opacity:1" offset="0" id="stop896"/><stop style="stop-color:#5e96d5;stop-opacity:1" offset="1" id="stop898"/></linearGradient><linearGradient id="linearGradient890"><stop style="stop-color:#939393;stop-opacity:1" offset="0" id="stop886"/><stop style="stop-color:#dddddd;stop-opacity:1" offset="1" id="stop888"/></linearGradient><linearGradient id="linearGradient882"><stop style="stop-color:#454545;stop-opacity:1" offset="0" id="stop878"/><stop style="stop-color:#9f9f9f;stop-opacity:1" offset="1" id="stop880"/></linearGradient><linearGradient xlink:href="#linearGradient882" id="linearGradient884" x1="36" y1="48" x2="12" y2="24" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient890" id="linearGradient892" x1="32" y1="48" x2="12" y2="28" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient900" id="linearGradient902" x1="30" y1="43" x2="17" y2="28" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient940" id="linearGradient942" x1="35" y1="14" x2="29" y2="14" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient1019" id="linearGradient1021" x1="48" y1="52" x2="20" y2="4" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient1027" id="linearGradient1029" x1="8" y1="52" x2="-2" y2="17" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient1037" id="linearGradient1039" x1="48" y1="52" x2="48" y2="20" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient1049" id="linearGradient1043" x1="57" y1="47" x2="57" y2="25" gradientUnits="userSpaceOnUse"/><linearGradient xlink:href="#linearGradient1063" id="linearGradient1065" x1="59" y1="50" x2="54" y2="21" gradientUnits="userSpaceOnUse"/></defs><metadata id="metadata5"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g id="layer1"><path id="rect1007" style="opacity:1;fill:url(#linearGradient1029);fill-opacity:1;stroke:url(#linearGradient1021);stroke-width:8;stroke-linecap:round;paint-order:markers stroke fill" d="m 12,12 c -4.432,0 -8,3.568 -8,8 v 8 8 16 H 44 60 V 20 a 6,4 0 0 0 -6,-4 6,4 0 0 0 -6,4 h -4 c 0,-4.432 -3.568,-8 -8,-8 z"/><path id="rect1053" style="opacity:1;fill:url(#linearGradient1065);fill-opacity:1;stroke:none;stroke-width:4;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" d="M 53.908203,16 A 6,3.5 0 0 0 48,19.5 6,3.5 0 0 0 48.0625,20 H 48 V 52 H 60 V 20 H 59.9375 A 6,3.5 0 0 0 60,19.5 6,3.5 0 0 0 54,16 6,3.5 0 0 0 53.9082,16 Z"/><path id="path876" style="fill:url(#linearGradient892);stroke:url(#linearGradient884);stroke-width:4;stroke-linecap:square;paint-order:markers fill stroke" d="M 42,36 A 18,18 0 0 1 24,54 18,18 0 0 1 6,36 18,18 0 0 1 24,18 18,18 0 0 1 42,36 Z"/><path id="path894" style="fill:#73a5dc;stroke:url(#linearGradient902);stroke-width:4;stroke-linecap:square;paint-order:markers fill stroke" d="M 34,36 A 10,10 0 0 1 24,46 10,10 0 0 1 14,36 10,10 0 0 1 24,26 10,10 0 0 1 34,36 Z"/><path style="fill:#ff00ff;fill-opacity:1;stroke:url(#linearGradient942);stroke-width:4;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" d="m 29,14 h 6" id="path934"/><path id="rect1031" style="opacity:1;fill:url(#linearGradient1039);stroke-width:8;stroke-linecap:round;paint-order:markers stroke fill" d="m 44,20 h 4 v 32 h -4 z"/><path style="opacity:1;fill:#676767;fill-opacity:1;stroke:url(#linearGradient1043);stroke-width:4;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" d="M 54,26 V 46" id="path1041"/></g></svg>
\ No newline at end of file
diff --git a/plugin/media_bbc/src/package-info.xml b/plugin/media_bbc/src/package-info.xml
new file mode 100644
index 0000000..413c056
--- /dev/null
+++ b/plugin/media_bbc/src/package-info.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!DOCTYPE package-info SYSTEM "http://www.simplemachines.org/xml/package-info">
+<package-info xmlns="http://www.simplemachines.org/xml/package-info" xmlns:smf="http://www.simplemachines.org/">
+    <id>@flurry:media_bbc</id>
+    <name>Media BBCode Tags</name>
+    <version>1.0</version>
+    <type>modification</type>
+
+    <install for="2.1.* - 2.1.99">
+        <readme parsebbc="true">readme.txt</readme>
+        <require-file name="Subs-MediaCode.php" destination="$sourcedir" />
+        <require-file name="sceditor.mediabbc.css" destination="Themes/default/css" />
+        <require-file name="sceditor.mediabbc.js" destination="Themes/default/scripts" />
+        <require-file name="asset/icon_audio.svg" destination="Themes/default/images" />
+        <require-file name="asset/icon_video.svg" destination="Themes/default/images" />
+        <hook hook="integrate_bbc_codes" function="hook_media_bbcode" file="$sourcedir/Subs-MediaCode.php" />
+        <hook hook="integrate_bbc_buttons" function="hook_media_bbcode_buttons" file="$sourcedir/Subs-MediaCode.php" />
+        <hook hook="integrate_sceditor_options" function="media_sce_options" file="$sourcedir/Subs-MediaCode.php" />
+        <hook hook="integrate_credits" function="media_bbc_credits" file="$sourcedir/Subs-MediaCode.php" />
+    </install>
+
+    <uninstall for="2.1.* - 2.1.99">
+        <remove-file name="$sourcedir/Subs-MediaCode.php" />
+        <remove-file name="Themes/default/scripts/sceditor.mediabbc.js" />
+        <remove-file name="Themes/default/css/sceditor.mediabbc.css" />
+        <remove-file name="Themes/default/images/icon_audio.svg" />
+        <remove-file name="Themes/default/images/icon_video.svg" />
+        <hook hook="integrate_bbc_codes" function="hook_media_bbcode" file="$sourcedir/Subs-MediaCode.php" reverse="true" />
+        <hook hook="integrate_bbc_buttons" function="hook_media_bbcode_buttons" file="$sourcedir/Subs-MediaCode.php" reverse="true" />
+        <hook hook="integrate_sceditor_options" function="media_sce_options" file="$sourcedir/Subs-MediaCode.php" reverse="true" />
+        <hook hook="integrate_credits" function="media_bbc_credits" file="$sourcedir/Subs-MediaCode.php" reverse="true" />
+    </uninstall>
+</package-info>
diff --git a/plugin/media_bbc/src/readme.txt b/plugin/media_bbc/src/readme.txt
new file mode 100644
index 0000000..98a66ae
--- /dev/null
+++ b/plugin/media_bbc/src/readme.txt
@@ -0,0 +1,3 @@
+[size=x-large][b]BBCode Media Tags[/b][/size]
+
+This adds the [nobbc][video][/nobbc] and [nobbc][audio][/nobbc] tags to SMF.
diff --git a/plugin/media_bbc/src/sceditor.mediabbc.css b/plugin/media_bbc/src/sceditor.mediabbc.css
new file mode 100644
index 0000000..4fadd3a
--- /dev/null
+++ b/plugin/media_bbc/src/sceditor.mediabbc.css
@@ -0,0 +1,11 @@
+.sceditor-button-video div {
+    background-image: url('../../default/images/icon_video.svg');
+    background-size: contain;
+    background-repeat: no-repeat;
+}
+
+.sceditor-button-audio div {
+    background-image: url('../../default/images/icon_audio.svg');
+    background-size: contain;
+    background-repeat: no-repeat;
+}
diff --git a/plugin/media_bbc/src/sceditor.mediabbc.js b/plugin/media_bbc/src/sceditor.mediabbc.js
new file mode 100644
index 0000000..f8bd3ee
--- /dev/null
+++ b/plugin/media_bbc/src/sceditor.mediabbc.js
@@ -0,0 +1,176 @@
+(function (sceditor) {
+    // Checks if the provided input is a URL we can use for our media tags.
+    function isValidURL(candidate) {
+        // technically URL.canParse exists, but I'm not sure if other browsers
+        // I expect users to use (e.g. Pale Moon) support it. So let's do the
+        // old method.
+        try {
+            const url = new URL(candidate);
+            if (url.protocol == 'http:' || url.protocol == 'https:') {
+                return true;
+            }
+
+            throw "Invalid protocol";
+        } catch (e) {
+            return false;
+        }
+    }
+
+    function makeMediaHtml(url, mediatype) {
+        if (!isValidUrl(url)) {
+            return '';
+        }
+        return '<div class="media-' + mediatype + '">' +
+            '<' + mediatype + ' data-src="' + url + '" controls>' +
+            '<source src="' + url + '" />' +
+            '</' + mediatype + '></div>';
+    }
+
+    // This creates a dropdown, similar to the existing YouTube button
+    function mediaDropDown(editor, caller, mediatype, urlCallback) {
+        // e.g. 'video' -> 'Video'
+        const mediaTitle = mediatype.charAt(0).toUpperCase() + mediatype.substring(1).toLowerCase();
+
+        // Container for the text input
+        const inputForm = document.createElement("form");
+
+        function clickAction(ev) {
+            const medialink = document.getElementById('medialink');
+            if (medialink != null && medialink.value != null) {
+                // At this point, medialink.value is either a string, or something is very wrong
+                if (isValidURL(medialink.value)) {
+                    urlCallback(medialink.value);
+                }
+            }
+            editor.closeDropDown(true);
+            ev.preventDefault();
+        }
+        inputForm.addEventListener('submit', clickAction);
+
+        const inputLabel = document.createElement('label');
+        inputLabel.htmlFor = 'medialink';
+        inputLabel.innerText = mediaTitle + ' URL:';
+        inputForm.appendChild(inputLabel);
+
+        const inputElem = document.createElement('input');
+        inputElem.id = 'medialink';
+        /*
+         * It's unlikely users will be repeatedly sending the same audio, and
+         * the dropdown will just get in the way.
+         */
+        inputElem.autocomplete = 'off';
+        inputElem.type = 'text';
+        inputElem.dir = 'ltr';
+        inputElem.placeholder = 'https://';
+        inputForm.appendChild(inputElem);
+
+        // "INSERT" button
+        const insertDiv = document.createElement("div");
+        const insertBtn = document.createElement("input");
+        insertBtn.className = 'button';
+        insertBtn.type = 'button';
+        insertBtn.value = 'Insert';
+        insertDiv.appendChild(insertBtn);
+        insertBtn.addEventListener('click', clickAction);
+
+        // div to tie the elements together
+        const containerDiv = document.createElement("div");
+        containerDiv.appendChild(inputForm);
+        containerDiv.appendChild(insertDiv);
+
+        editor.createDropDown(caller, 'insertlink', containerDiv);
+    }
+
+    // "Converts" the HTML back, by finding the data-src attribute of the media tag
+    function htmlToBBCode(element, content, mediatype) {
+        const media = element.getElementsByTagName(mediatype);
+
+        if (media.length == 0 || !media[0].attributes.hasOwnProperty('data-src')) {
+            return content;
+        }
+
+        return '[' + mediatype + ']' + media[0].attributes['data-src'].value + '[/' + mediatype + ']';
+    }
+
+    sceditor.formats.bbcode.set(
+        'video', {
+            tags: {
+                div: {
+                    class: 'media-video'
+                }
+            },
+            isInline: false,
+            allowedChildren: ['#'],
+            breakBefore: true,
+            breakAfter: true,
+            skipLastLineBreak: true,
+            format: function (element, content) {
+                return htmlToBBCode(element, content, 'video');
+            },
+            html: function (token, attrs, content) {
+                makeMediaHtml(content, 'video');
+            }
+    });
+
+    sceditor.formats.bbcode.set(
+        'audio', {
+            tags: {
+                div: {
+                    class: 'media-audio'
+                }
+            },
+            isInline: false,
+            allowedChildren: ['#'],
+            breakBefore: true,
+            breakAfter: true,
+            skipLastLineBreak: true,
+            format: function (element, content) {
+                return htmlToBBCode(element, content, 'audio');
+            },
+            html: function (token, attrs, content) {
+                makeMediaHtml(content, 'audio');
+            }
+    });
+
+    sceditor.command.set(
+        'video', {
+            exec: function (caller) {
+                const editor = this;
+                mediaDropDown(this, caller, 'video', function (url) {
+                    editor.wysiwygEditorInsertHtml(makeMediaHtml(url, 'video'));
+                });
+            },
+            txtExec: function (caller, selected) {
+                const editor = this;
+                if (isValidURL(selected)) {
+                    editor.insertText('[video]' + selected + '[/video]');
+                } else {
+                    mediaDropDown(this, caller, 'video', function (url) {
+                        editor.insertText('[video]' + url + '[/video]');
+                    });
+                }
+            }
+        }
+    );
+
+    sceditor.command.set(
+        'audio', {
+            exec: function (caller) {
+                const editor = this;
+                mediaDropDown(this, caller, 'audio', function (url) {
+                    editor.wysiwygEditorInsertHtml(makeMediaHtml(url, 'audio'));
+                });
+            },
+            txtExec: function (caller, selected) {
+                const editor = this;
+                if (isValidURL(selected)) {
+                    editor.insertText('[audio]' + selected + '[/audio]');
+                } else {
+                    mediaDropDown(this, caller, 'audio', function (url) {
+                        editor.insertText('[audio]' + url + '[/audio]');
+                    });
+                }
+            }
+        }
+    );
+})(sceditor);
diff --git a/plugin/topic_mute/src/Subs-TopicMute.php b/plugin/topic_mute/src/Subs-TopicMute.php
index 0602ce0..559ee66 100644
--- a/plugin/topic_mute/src/Subs-TopicMute.php
+++ b/plugin/topic_mute/src/Subs-TopicMute.php
@@ -25,6 +25,7 @@ function topic_is_muted($topic, $user = -1)
 {
     global $context, $smcFunc, $user_info;
     if ($user_info['is_guest']) {
+        die('lol');
         return false;
     }
 
@@ -126,4 +127,8 @@ function mute_theme_option()
     );
 }
 
+function add_topic_mute_js() {
+    loadJavaScriptFile('topic-mute.js', array('minimize' => true), 'topic_mute_ajax');
+}
+
 ?>
diff --git a/plugin/topic_mute/src/TopicMute.php b/plugin/topic_mute/src/TopicMute.php
index 73c8659..d2c21f3 100644
--- a/plugin/topic_mute/src/TopicMute.php
+++ b/plugin/topic_mute/src/TopicMute.php
@@ -7,7 +7,7 @@
  */
 function TopicMute()
 {
-    global $smcFunc, $user_info, $topic, $scripturl;
+    global $smcFunc, $user_info, $topic, $scripturl, $context;
 
     is_not_guest();
     checkSession('get');
@@ -43,6 +43,7 @@ function TopicMute()
     // Handle AJAX requests
     if (isset($_GET['xml']))
     {
+        loadTemplate('Xml');
         $context['xml_data']['errors'] = array(
             'identifier' => 'error',
             'children' => array(
@@ -52,6 +53,8 @@ function TopicMute()
             ),
         );
         $context['sub_template'] = 'generic_xml';
+        // TODO: is this the best way to do it?
+        obExit(false, false);
     } else {
         redirectexit('topic=' . $topic . '.' . $_REQUEST['start']);
     }
diff --git a/plugin/topic_mute/src/dbinstall.php b/plugin/topic_mute/src/dbinstall.php
index eefcf39..2e2ec59 100644
--- a/plugin/topic_mute/src/dbinstall.php
+++ b/plugin/topic_mute/src/dbinstall.php
@@ -26,7 +26,7 @@ $columns = array(
 $indexes = array(
     array(
         'type' => 'primary',
-        'columns' => array('id_member'),
+        'columns' => array('id_member', 'id_topic'),
     ),
 );
 
diff --git a/plugin/topic_mute/src/package-info.xml b/plugin/topic_mute/src/package-info.xml
index a1ddc9c..06d3d6f 100644
--- a/plugin/topic_mute/src/package-info.xml
+++ b/plugin/topic_mute/src/package-info.xml
@@ -10,21 +10,25 @@
         <readme parsebbc="true">readme.txt</readme>
         <require-file name="Subs-TopicMute.php" destination="$sourcedir" />
         <require-file name="languages/TopicMute.english.php" destination="$languagedir" />
+        <require-file name="topic-mute.js" destination="Themes/default/scripts" />
         <require-file name="TopicMute.php" destination="$sourcedir" />
         <database>dbinstall.php</database>
         <hook hook="integrate_message_index" function="hide_muted_topics" file="$sourcedir/Subs-TopicMute.php" />
         <hook hook="integrate_theme_options" function="mute_theme_option" file="$sourcedir/Subs-TopicMute.php" />
         <hook hook="integrate_display_buttons" function="add_mute_button" file="$sourcedir/Subs-TopicMute.php" />
+        <hook hook="integrate_load_theme" function="add_topic_mute_js" file="$sourcedir/Subs-TopicMute.php" />
         <hook hook="integrate_actions" function="add_topicmute_action" file="$sourcedir/Subs-TopicMute.php" />
     </install>
 
     <uninstall for="2.1.* - 2.1.99">
         <remove-file name="$sourcedir/Subs-TopicMute.php" />
         <remove-file name="$sourcedir/TopicMute.php" />
+        <remove-file name="Themes/default/scripts/topic-mute.js" />
         <remove-file name="$languagedir/TopicMute.english.php" />
         <hook hook="integrate_message_index" function="hide_muted_topics" file="$sourcedir/Subs-TopicMute.php" reverse="true" />
         <hook hook="integrate_theme_options" function="mute_theme_option" file="$sourcedir/Subs-TopicMute.php" reverse="true" />
         <hook hook="integrate_display_buttons" function="add_mute_button" file="$sourcedir/Subs-TopicMute.php" reverse="true" />
+        <hook hook="integrate_load_theme" function="add_topic_mute_js" file="$sourcedir/Subs-TopicMute.php" reverse="true" />
         <hook hook="integrate_actions" function="add_topicmute_action" file="$sourcedir/Subs-TopicMute.php" reverse="true" />
     </uninstall>
 </package-info>
diff --git a/plugin/topic_mute/src/topic-mute.js b/plugin/topic_mute/src/topic-mute.js
new file mode 100644
index 0000000..411e322
--- /dev/null
+++ b/plugin/topic_mute/src/topic-mute.js
@@ -0,0 +1,15 @@
+$(function() {
+    $('.button_strip_mute_topic').click(function (e) {
+        var $obj = $(this);
+        e.preventDefault();
+        ajax_indicator(true);
+        $.get($obj.attr('href') + ';xml', function () {
+            ajax_indicator(false);
+            let text = 'Unmute Topic';
+            if ($obj.text() == text) {
+                text = 'Mute Topic';
+            }
+            $('.button_strip_mute_topic').text(text);
+        });
+    });
+});
diff --git a/plugin/yt_nocookie/Makefile b/plugin/yt_nocookie/Makefile
new file mode 100644
index 0000000..42bd70e
--- /dev/null
+++ b/plugin/yt_nocookie/Makefile
@@ -0,0 +1,3 @@
+PROJECT := yt_nocookie
+
+include ../plugin.mk
diff --git a/plugin/yt_nocookie/src/Subs-YtNoOrigin.php b/plugin/yt_nocookie/src/Subs-YtNoOrigin.php
new file mode 100644
index 0000000..9b2d33b
--- /dev/null
+++ b/plugin/yt_nocookie/src/Subs-YtNoOrigin.php
@@ -0,0 +1,19 @@
+<?php
+
+function hook_yt_noorigin(&$codes, &$no_autolink_tags) {
+    $found = false;
+    $idx = 0;
+    foreach ($codes as $code) {
+        if ($code['tag'] == 'youtube') {
+            $found = true;
+            break;
+        }
+        $idx++;
+    }
+    if ($found) {
+        // Everything except ?origin=
+        $codes[$idx]['content'] = '<div class="videocontainer"><div><iframe frameborder="0" src="https://www.youtube-nocookie.com/embed/$1?wmode=opaque" data-youtube-id="$1" allowfullscreen loading="lazy"></iframe></div></div>';
+    }
+}
+
+?>
diff --git a/plugin/yt_nocookie/src/package-info.xml b/plugin/yt_nocookie/src/package-info.xml
new file mode 100644
index 0000000..ba963b9
--- /dev/null
+++ b/plugin/yt_nocookie/src/package-info.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!DOCTYPE package-info SYSTEM "http://www.simplemachines.org/xml/package-info">
+<package-info xmlns="http://www.simplemachines.org/xml/package-info" xmlns:smf="http://www.simplemachines.org/">
+    <id>@flurry:yt_nocookie</id>
+    <name>Use youtube-nocookie for YouTube</name>
+    <version>1.0</version>
+    <type>modification</type>
+
+    <install for="2.1.* - 2.1.99">
+        <readme parsebbc="true">readme.txt</readme>
+        <require-file name="Subs-YtNoOrigin.php" destination="$sourcedir" />
+        <hook hook="integrate_bbc_codes" function="hook_yt_noorigin" file="$sourcedir/Subs-YtNoOrigin.php" />
+    </install>
+
+    <uninstall for="2.1.* - 2.1.99">
+        <remove-file name="$sourcedir/Subs-YtNoOrigin.php" />
+        <hook hook="integrate_bbc_codes" function="hook_yt_noorigin" file="$sourcedir/Subs-YtNoOrigin.php" reverse="true" />
+    </uninstall>
+</package-info>
diff --git a/plugin/yt_nocookie/src/readme.txt b/plugin/yt_nocookie/src/readme.txt
new file mode 100644
index 0000000..cdf44c2
--- /dev/null
+++ b/plugin/yt_nocookie/src/readme.txt
@@ -0,0 +1,3 @@
+[size=x-large][b]Use youtube-nocookie for YouTube[/b][/size]
+
+This removes the [b]origin=[/b] query parameter from YouTube embeds, and uses https://www.youtube-nocookie.com for embeds.