Sfoglia il codice sorgente

Improve video embed overlay and proxy behavior

Zed 4 settimane fa
parent
commit
5fa4eefb9d
5 ha cambiato i file con 82 aggiunte e 32 eliminazioni
  1. 21 5
      public/js/embedResize.js
  2. 47 22
      public/js/widgets.js
  3. 12 3
      src/sass/tweet/embed.scss
  4. 1 1
      src/views/embed.nim
  5. 1 1
      src/views/general.nim

+ 21 - 5
public/js/embedResize.js

@@ -1,25 +1,41 @@
-(function() {
-  var embedElement = document.querySelector('.embed-wrapper, .tweet-embed, .embed-video');
+(function () {
+  var embedElement = document.querySelector(
+    ".embed-wrapper, .tweet-embed, .embed-video",
+  );
   if (!embedElement) return;
   if (!embedElement) return;
 
 
+  // Video play state for overlay (hidden while playing, visible on hover/pause)
+  var video = embedElement.querySelector("video");
+  if (video) {
+    video.onplay = function () {
+      embedElement.classList.add("video-playing");
+    };
+    video.onpause = video.onended = function () {
+      embedElement.classList.remove("video-playing");
+    };
+  }
+
   var lastHeight = 0;
   var lastHeight = 0;
 
 
   function sendHeight() {
   function sendHeight() {
     var currentHeight = embedElement.offsetHeight;
     var currentHeight = embedElement.offsetHeight;
     if (currentHeight !== lastHeight && currentHeight > 0) {
     if (currentHeight !== lastHeight && currentHeight > 0) {
       lastHeight = currentHeight;
       lastHeight = currentHeight;
-      window.parent.postMessage(['resizeIframe', { h: currentHeight, url: location.href }], '*');
+      window.parent.postMessage(
+        ["resizeIframe", { h: currentHeight, url: location.href }],
+        "*",
+      );
     }
     }
   }
   }
 
 
   // Respond to height requests from parent via MessageChannel
   // Respond to height requests from parent via MessageChannel
-  window.addEventListener('message', function(event) {
+  window.addEventListener("message", function (event) {
     if (event.source === window.parent && event.ports && event.ports[0]) {
     if (event.source === window.parent && event.ports && event.ports[0]) {
       event.ports[0].postMessage(embedElement.offsetHeight);
       event.ports[0].postMessage(embedElement.offsetHeight);
     }
     }
   });
   });
 
 
-  window.addEventListener('load', sendHeight);
+  window.addEventListener("load", sendHeight);
   new ResizeObserver(sendHeight).observe(embedElement);
   new ResizeObserver(sendHeight).observe(embedElement);
 
 
   // Expose for embedTweet.js
   // Expose for embedTweet.js

+ 47 - 22
public/js/widgets.js

@@ -8,10 +8,7 @@
   if (window.__nitterWidgets) return;
   if (window.__nitterWidgets) return;
   window.__nitterWidgets = true;
   window.__nitterWidgets = true;
 
 
-  var scripts = document.querySelectorAll('script[src*="widgets.js"]');
-  var NITTER = scripts.length
-    ? new URL(scripts[scripts.length - 1].src).origin
-    : location.origin;
+  var NITTER = new URL(document.currentScript.src).origin;
 
 
   var TWEET_RE = /(?:twitter\.com|x\.com)\/([^\/]+)\/status\/(\d+)/i;
   var TWEET_RE = /(?:twitter\.com|x\.com)\/([^\/]+)\/status\/(\d+)/i;
   var SELECTOR = "blockquote.twitter-tweet, blockquote.twitter-video";
   var SELECTOR = "blockquote.twitter-tweet, blockquote.twitter-video";
@@ -21,11 +18,15 @@
   var isReady = false;
   var isReady = false;
 
 
   function safeCall(fn, arg) {
   function safeCall(fn, arg) {
-    try { fn(arg); } catch (e) {}
+    try {
+      fn(arg);
+    } catch (e) { }
   }
   }
 
 
   function fireEvent(name, data) {
   function fireEvent(name, data) {
-    (eventCallbacks[name] || []).forEach(function (cb) { safeCall(cb, data); });
+    (eventCallbacks[name] || []).forEach(function (cb) {
+      safeCall(cb, data);
+    });
   }
   }
 
 
   function parseTweetUrl(url) {
   function parseTweetUrl(url) {
@@ -44,8 +45,12 @@
       var path = tweet.user ? "/" + tweet.user : "/i";
       var path = tweet.user ? "/" + tweet.user : "/i";
       url = NITTER + path + "/status/" + tweet.id + "/embed";
       url = NITTER + path + "/status/" + tweet.id + "/embed";
       if (opts.theme) {
       if (opts.theme) {
-        var theme = opts.theme === "dark" ? "nitter" :
-                    opts.theme === "light" ? "twitter" : opts.theme;
+        var theme =
+          opts.theme === "dark"
+            ? "nitter"
+            : opts.theme === "light"
+              ? "twitter"
+              : opts.theme;
         url += "?theme=" + encodeURIComponent(theme);
         url += "?theme=" + encodeURIComponent(theme);
       }
       }
     }
     }
@@ -60,11 +65,18 @@
     if (opts.videoOnly) iframe.setAttribute("allowfullscreen", "true");
     if (opts.videoOnly) iframe.setAttribute("allowfullscreen", "true");
 
 
     var width = opts.width || 550;
     var width = opts.width || 550;
-    var margin = opts.align === "center" ? "10px auto" :
-                 opts.align === "right" ? "10px 0 10px auto" : "10px 0";
+    var margin =
+      opts.align === "center"
+        ? "10px auto"
+        : opts.align === "right"
+          ? "10px 0 10px auto"
+          : "10px 0";
     iframe.style.cssText =
     iframe.style.cssText =
-      "width:100%;max-width:" + width + "px;height:250px;" +
-      "border:none;display:block;margin:" + margin;
+      "width:100%;max-width:" +
+      width +
+      "px;height:300px;" +
+      "border:none;display:block;margin:" +
+      margin;
 
 
     iframe.addEventListener("load", function () {
     iframe.addEventListener("load", function () {
       fireEvent("rendered", { target: iframe });
       fireEvent("rendered", { target: iframe });
@@ -89,7 +101,7 @@
       width: d.mediaMaxWidth || d.width,
       width: d.mediaMaxWidth || d.width,
       align: d.align,
       align: d.align,
       theme: d.theme,
       theme: d.theme,
-      videoOnly: d.mediaMaxWidth !== undefined
+      videoOnly: d.mediaMaxWidth !== undefined,
     });
     });
 
 
     bq.style.display = "none";
     bq.style.display = "none";
@@ -98,7 +110,9 @@
   }
   }
 
 
   function processEmbeds(root) {
   function processEmbeds(root) {
-    var bqs = (root || document).querySelectorAll(SELECTOR + ":not([data-nitter-processed])");
+    var bqs = (root || document).querySelectorAll(
+      SELECTOR + ":not([data-nitter-processed])",
+    );
     for (var i = 0; i < bqs.length; i++) processBlockquote(bqs[i]);
     for (var i = 0; i < bqs.length; i++) processBlockquote(bqs[i]);
   }
   }
 
 
@@ -147,7 +161,7 @@
       createTweet: embedTweet,
       createTweet: embedTweet,
       createTweetEmbed: embedTweet,
       createTweetEmbed: embedTweet,
       createVideo: embedTweet,
       createVideo: embedTweet,
-      loaded: true
+      loaded: true,
     },
     },
     events: {
     events: {
       bind: function (name, cb) {
       bind: function (name, cb) {
@@ -158,33 +172,44 @@
       unbind: function (name, cb) {
       unbind: function (name, cb) {
         if (!eventCallbacks[name]) return;
         if (!eventCallbacks[name]) return;
         eventCallbacks[name] = cb
         eventCallbacks[name] = cb
-          ? eventCallbacks[name].filter(function (f) { return f !== cb; })
+          ? eventCallbacks[name].filter(function (f) {
+            return f !== cb;
+          })
           : [];
           : [];
-      }
+      },
     },
     },
     ready: function (cb) {
     ready: function (cb) {
       if (typeof cb !== "function") return;
       if (typeof cb !== "function") return;
       if (isReady) cb(window.twttr);
       if (isReady) cb(window.twttr);
       else readyCallbacks.push(cb);
       else readyCallbacks.push(cb);
     },
     },
-    _e: []
+    _e: [],
   };
   };
 
 
   // Process callbacks queued before load (twttr._e pattern)
   // Process callbacks queued before load (twttr._e pattern)
   if (prevTwttr && prevTwttr._e) {
   if (prevTwttr && prevTwttr._e) {
-    prevTwttr._e.forEach(function (cb) { safeCall(cb); });
+    prevTwttr._e.forEach(function (cb) {
+      safeCall(cb);
+    });
   }
   }
 
 
   // Remove any Twitter scripts that snuck through
   // Remove any Twitter scripts that snuck through
-  document.querySelectorAll('script[src*="platform.twitter.com"], script[src*="platform.x.com"]')
-    .forEach(function (s) { s.remove(); });
+  document
+    .querySelectorAll(
+      'script[src*="platform.twitter.com"], script[src*="platform.x.com"]',
+    )
+    .forEach(function (s) {
+      s.remove();
+    });
 
 
   function init() {
   function init() {
     window.addEventListener("message", handleResize);
     window.addEventListener("message", handleResize);
     processEmbeds();
     processEmbeds();
     observeDOM();
     observeDOM();
     isReady = true;
     isReady = true;
-    readyCallbacks.forEach(function (cb) { safeCall(cb, window.twttr); });
+    readyCallbacks.forEach(function (cb) {
+      safeCall(cb, window.twttr);
+    });
     readyCallbacks = [];
     readyCallbacks = [];
   }
   }
 
 

+ 12 - 3
src/sass/tweet/embed.scss

@@ -88,6 +88,7 @@ html:has(body > .embed-video) {
 // Video-only embed
 // Video-only embed
 .embed-video {
 .embed-video {
   position: relative;
   position: relative;
+  min-height: 300px;
   background-color: black;
   background-color: black;
   border: 1px solid var(--border_grey);
   border: 1px solid var(--border_grey);
 
 
@@ -106,7 +107,7 @@ html:has(body > .embed-video) {
     width: 100%;
     width: 100%;
   }
   }
 
 
-  .gallery-video > .attachment {
+  .gallery-video>.attachment {
     max-height: 560px;
     max-height: 560px;
     width: 100%;
     width: 100%;
   }
   }
@@ -135,7 +136,9 @@ html:has(body > .embed-video) {
     text-decoration: none;
     text-decoration: none;
     border-radius: 9999px;
     border-radius: 9999px;
     border: 1px solid transparent;
     border: 1px solid transparent;
-    transition: background 0.15s, opacity 0.15s;
+    transition:
+      background 0.15s,
+      opacity 0.15s;
     z-index: 10;
     z-index: 10;
 
 
     &:hover {
     &:hover {
@@ -143,8 +146,14 @@ html:has(body > .embed-video) {
     }
     }
   }
   }
 
 
-  &:has(video:playing) .video-overlay-link {
+  // Hide button while playing, show on hover or when paused
+  &.video-playing .video-overlay-link {
     opacity: 0;
     opacity: 0;
     pointer-events: none;
     pointer-events: none;
   }
   }
+
+  &.video-playing:hover .video-overlay-link {
+    opacity: 1;
+    pointer-events: auto;
+  }
 }
 }

+ 1 - 1
src/views/embed.nim

@@ -14,7 +14,7 @@ proc renderVideoEmbed*(tweet: Tweet; cfg: Config; req: Request): string =
     video = tweet.getVideos()[0]
     video = tweet.getVideos()[0]
     thumb = video.thumb
     thumb = video.thumb
     vidUrl = getVideoEmbed(cfg, tweet.id)
     vidUrl = getVideoEmbed(cfg, tweet.id)
-    prefs = Prefs(hlsPlayback: true, mp4Playback: true)
+    prefs = Prefs(hlsPlayback: true, mp4Playback: true, proxyVideos: true)
     tweetUrl = getLink(tweet)
     tweetUrl = getLink(tweet)
 
 
   let node = buildHtml(html(lang="en")):
   let node = buildHtml(html(lang="en")):

+ 1 - 1
src/views/general.nim

@@ -50,7 +50,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
   let opensearchUrl = getUrlPrefix(cfg) & "/opensearch"
   let opensearchUrl = getUrlPrefix(cfg) & "/opensearch"
 
 
   buildHtml(head):
   buildHtml(head):
-    link(rel="stylesheet", type="text/css", href="/css/style.css?v=101")
+    link(rel="stylesheet", type="text/css", href="/css/style.css?v=106")
     link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=7")
     link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=7")
 
 
     if theme.len > 0:
     if theme.len > 0: