Parcourir la source

Merge branch 'main' into CustomNumberFormat

Dmitrii Selivanov il y a 3 ans
Parent
commit
e97b4a75af

+ 9 - 0
.github/ISSUE_TEMPLATE/bug.yml

@@ -47,3 +47,12 @@ body:
     value: "A bug happened!"
   validations:
     required: true
+- type: textarea
+  attributes:
+    label: How to reproduce/recreate?
+    description: Detailed steps to reproduce/recreate it.
+    placeholder: "We need to be able to reproduce/recreate that bug/event in order to fix it. Please write the steps in detail."
+    value: "Tell us how it happened with detailed steps for us."
+  validations:
+    required: true
+    

+ 40 - 37
Docs/Guide__Installing.md

@@ -1,41 +1,40 @@
-# Downloading, Installing & Using
+
 
 **Contents**
 
-- [Downloading, Installing & Using](#downloading-installing--using)
-  - [Downloading](#downloading)
-    - [Desktop (all OS supported by these browsers)](#desktop-all-os-supported-by-these-browsers)
-      - [Chromium Based Browsers](#chromium-based-browsers)
-      - [Firefox Based Browsers](#firefox-based-browsers)
-    - [Mobile](#mobile)
-      - [Android](#android)
-      - [iOS](#ios)
-      - [Userscript](#userscript)
-  - [Installation](#installation)
-    - [Desktop](#desktop)
-      - [**Chromium based browsers**](#chromium-based-browsers-1)
-        - [From Chrome Webstore](#from-chrome-webstore)
-        - [From crx/zip file](#from-crxzip-file)
-        - [From unzipped folder](#from-unzipped-folder)
-      - [**Firefox Based Browsers**](#firefox-based-browsers-1)
-        - [From addon store](#from-addon-store)
-        - [From xpi/jar/zip file](#from-xpijarzip-file)
-    - [Mobile](#mobile-1)
-      - [Android](#android-1)
-        - [App from Play Store](#app-from-play-store)
-        - [On Firefox](#on-firefox)
-      - [iOS](#ios-1)
-  - [Using](#using)
-  - [Updating](#updating)
-    - [Extension / Addon](#extension--addon)
-  - [Miscellaneous](#miscellaneous)
-    - [Using YouTube website as an app with an extension](#using-youtube-website-as-an-app-with-an-extension)
-      - [Desktop](#desktop-1)
-        - [Chromium Based Browsers](#chromium-based-browsers-2)
-        - [Firefox Based Browsers](#firefox-based-browsers-2)
-      - [Mobile](#mobile-2)
-        - [Firefox Based Browsers](#firefox-based-browsers-3)
-        - [Chromium Based Browsers](#chromium-based-browsers-3)
+- [Downloading](#downloading)
+  - [Desktop (all OS supported by these browsers)](#desktop-all-os-supported-by-these-browsers)
+    - [Chromium Based Browsers](#chromium-based-browsers)
+    - [Firefox Based Browsers](#firefox-based-browsers)
+  - [Mobile](#mobile)
+    - [Android](#android)
+    - [iOS](#ios)
+    - [Userscript](#userscript)
+- [Installation](#installation)
+  - [Desktop](#desktop)
+    - [**Chromium based browsers**](#chromium-based-browsers-1)
+      - [From Chrome Webstore](#from-chrome-webstore)
+      - [From crx/zip file](#from-crxzip-file)
+      - [From unzipped folder](#from-unzipped-folder)
+    - [**Firefox Based Browsers**](#firefox-based-browsers-1)
+      - [From addon store](#from-addon-store)
+      - [From xpi/jar/zip file](#from-xpijarzip-file)
+  - [Mobile](#mobile-1)
+    - [Android](#android-1)
+      - [App from Play Store](#app-from-play-store)
+      - [On Firefox](#on-firefox)
+    - [iOS](#ios-1)
+- [Using](#using)
+- [Updating](#updating)
+  - [Extension / Addon](#extension--addon)
+- [Miscellaneous](#miscellaneous)
+  - [Using YouTube website as an app with an extension](#using-youtube-website-as-an-app-with-an-extension)
+    - [Desktop](#desktop-1)
+      - [Chromium Based Browsers](#chromium-based-browsers-2)
+      - [Firefox Based Browsers](#firefox-based-browsers-2)
+    - [Mobile](#mobile-2)
+      - [Firefox Based Browsers](#firefox-based-browsers-3)
+      - [Chromium Based Browsers](#chromium-based-browsers-3)
 
 <br>
 
@@ -88,6 +87,12 @@ It should be able to work on [all Chromium-based browsers (list here)][4]. But t
 
 - This addon should be able to run on most of the [Firefox-based browsers][5]. But isn't guaranteed.
 
+3. [**Chromium Based browsers**][4]
+
+Most [**Chromium Based browsers**][4] **don't support extensions on Android or iOS**
+
+However, [Kiwi Browser](https://kiwibrowser.com/) does. You can refer to this video - [Google Chrome Extensions on Android with Kiwi Browser!](https://youtu.be/T6J0T_-oim4)
+
 <br>
 
 #### iOS
@@ -291,8 +296,6 @@ You can also refer here (for pictures):
 
 ##### [Chromium Based Browsers][4]
 
-[**Chromium Based browsers**][4] **don't support extensions on Android or iOS**
-
 But still - here are the steps:
 
 1. Go to YouTube

+ 36 - 12
Extensions/UserScript/Return Youtube Dislike.user.js

@@ -30,13 +30,34 @@ let likesvalue = 0;
 let dislikesvalue = 0;
 
 let isMobile = location.hostname == "m.youtube.com";
+let isShorts = () => location.pathname.startsWith("/shorts")
 let mobileDislikes = 0;
 function cLog(text, subtext = "") {
   subtext = subtext.trim() === "" ? "" : `(${subtext})`;
   console.log(`[Return YouTube Dislikes] ${text} ${subtext}`);
 }
 
+function isInViewport(element) {
+  const rect = element.getBoundingClientRect();
+  const height = innerHeight || document.documentElement.clientHeight;
+  const width = innerWidth || document.documentElement.clientWidth;
+  return (
+      rect.top >= 0 &&
+      rect.left >= 0 &&
+      rect.bottom <= height &&
+      rect.right <= width
+  );
+}
+
 function getButtons() {
+  if(isShorts()) {
+    let elements=document.querySelectorAll(isMobile ? "ytm-like-button-renderer" : "#like-button > ytd-like-button-renderer");
+    for(let element of elements) {
+      if(isInViewport(element)) {
+        return element;
+      }
+    }
+  }
   if (isMobile) {
     return document.querySelector(".slim-video-action-bar-actions");
   }
@@ -179,7 +200,7 @@ function createRateBar(likes, dislikes) {
   const widthPercent =
     likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
 
-  if (!rateBar) {
+  if (!rateBar && !isMobile) {
     document.getElementById("menu-container").insertAdjacentHTML(
       "beforeend",
       `
@@ -214,6 +235,7 @@ function createRateBar(likes, dislikes) {
   }
 }
 
+
 function setState() {
   cLog("Fetching votes...");
   let statsSet = false;
@@ -287,6 +309,9 @@ function getVideoId() {
   if (pathname.startsWith("/clip")) {
     return document.querySelector("meta[itemprop='videoId']").content;
   } else {
+    if (pathname.startsWith("/shorts")) {
+      return pathname.substr(8);
+    }
     return urlObject.searchParams.get("v");
   }
 }
@@ -334,27 +359,26 @@ function setEventListeners(evt) {
 
   function checkForJS_Finish(check) {
     console.log();
-    if (getButtons()?.offsetParent && isVideoLoaded()) {
-      clearInterval(jsInitChecktimer);
+    if (isShorts() || getButtons()?.offsetParent && isVideoLoaded()) {
       const buttons = getButtons();
 
       if (!window.returnDislikeButtonlistenersSet) {
         cLog("Registering button listeners...");
-        buttons.children[0].addEventListener("click", likeClicked);
-        buttons.children[1].addEventListener("click", dislikeClicked);
+        try {
+          buttons.children[0].addEventListener("click", likeClicked);
+          buttons.children[1].addEventListener("click", dislikeClicked);
+          buttons.children[0].addEventListener("touchstart", likeClicked);
+          buttons.children[1].addEventListener("touchstart", dislikeClicked);
+        } catch { return } //Don't spam errors into the console
         window.returnDislikeButtonlistenersSet = true;
       }
       setInitialState();
+      clearInterval(jsInitChecktimer);
     }
   }
 
-  if (
-    window.location.href.indexOf("watch?") >= 0 ||
-    (isMobile && evt?.indexOf("watch?") >= 0)
-  ) {
-    cLog("Setting up...");
-    jsInitChecktimer = setInterval(checkForJS_Finish, 111);
-  }
+  cLog("Setting up...");
+  jsInitChecktimer = setInterval(checkForJS_Finish, 111);
 }
 
 (function () {

+ 35 - 0
Extensions/combined/_locales/en/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Return YouTube Dislike"
+    },
+    "extensionDesc": {
+        "message": "Returns ability to see dislikes"
+    },
+    "textDeveloper": {
+        "message": "by Dmitrii Selivanov & Community"
+    },
+    "linkWebsite": {
+        "message": "Website"
+    },
+    "linkFAQ": {
+        "message": "FAQ"
+    },
+    "linkDonate": {
+        "message": "Donate"
+    },
+    "linkHelp": {
+        "message": "Help"
+    },
+    "legendSettings": {
+        "message": "Settings"
+    },
+    "textSettings": {
+        "message": "Disable like/dislike submission"
+    },
+    "textSettingsHover": {
+        "message": "Stops counting your likes and dislikes."
+    },
+    "textUpdate": {
+        "message": "update to"
+    }
+}

+ 35 - 0
Extensions/combined/_locales/en_GB/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Return YouTube Dislike"
+    },
+    "extensionDesc": {
+        "message": "Returns ability to see dislikes"
+    },
+    "textDeveloper": {
+        "message": "by Dmitrii Selivanov & Community"
+    },
+    "linkWebsite": {
+        "message": "Website"
+    },
+    "linkFAQ": {
+        "message": "FAQ"
+    },
+    "linkDonate": {
+        "message": "Donate"
+    },
+    "linkHelp": {
+        "message": "Help"
+    },
+    "legendSettings": {
+        "message": "Settings"
+    },
+    "textSettings": {
+        "message": "Disable like/dislike submission"
+    },
+    "textSettingsHover": {
+        "message": "Stops counting your likes and dislikes."
+    },
+    "textUpdate": {
+        "message": "update to"
+    }
+}

+ 35 - 0
Extensions/combined/_locales/en_US/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Return YouTube Dislike"
+    },
+    "extensionDesc": {
+        "message": "Returns ability to see dislikes"
+    },
+    "textDeveloper": {
+        "message": "by Dmitrii Selivanov & Community"
+    },
+    "linkWebsite": {
+        "message": "Website"
+    },
+    "linkFAQ": {
+        "message": "FAQ"
+    },
+    "linkDonate": {
+        "message": "Donate"
+    },
+    "linkHelp": {
+        "message": "Help"
+    },
+    "legendSettings": {
+        "message": "Settings"
+    },
+    "textSettings": {
+        "message": "Disable like/dislike submission"
+    },
+    "textSettingsHover": {
+        "message": "Stops counting your likes and dislikes."
+    },
+    "textUpdate": {
+        "message": "update to"
+    }
+}

+ 35 - 0
Extensions/combined/_locales/es/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Regresar los Dislikes de YouTube"
+    },
+    "extensionDesc": {
+        "message": "Regresa la posibilidad de ver los dislikes"
+    },
+    "textDeveloper": {
+        "message": "por Dmitrii Selivanov y la Comunidad"
+    },
+    "linkWebsite": {
+        "message": "Página web"
+    },
+    "linkFAQ": {
+        "message": "P+F"
+    },
+    "linkDonate": {
+        "message": "Donar"
+    },
+    "linkHelp": {
+        "message": "Ayuda"
+    },
+    "legendSettings": {
+        "message": "Ajustes"
+    },
+    "textSettings": {
+        "message": "Desactivar los dislikes"
+    },
+    "textSettingsHover": {
+        "message": "Dejar de contar los dislikes."
+    },
+    "textUpdate": {
+        "message": "actualizar a"
+    }
+}

+ 35 - 0
Extensions/combined/_locales/es_419/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Regresar los Dislikes de YouTube"
+    },
+    "extensionDesc": {
+        "message": "Regresa la posibilidad de ver los dislikes"
+    },
+    "textDeveloper": {
+        "message": "por Dmitrii Selivanov y la Comunidad"
+    },
+    "linkWebsite": {
+        "message": "Página web"
+    },
+    "linkFAQ": {
+        "message": "P+F"
+    },
+    "linkDonate": {
+        "message": "Donar"
+    },
+    "linkHelp": {
+        "message": "Ayuda"
+    },
+    "legendSettings": {
+        "message": "Ajustes"
+    },
+    "textSettings": {
+        "message": "Desactivar los dislikes"
+    },
+    "textSettingsHover": {
+        "message": "Dejar de contar los dislikes."
+    },
+    "textUpdate": {
+        "message": "actualizar a"
+    }
+}

+ 35 - 0
Extensions/combined/_locales/fr/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Return YouTube Dislike"
+    },
+    "extensionDesc": {
+        "message": "Ré-affiche les pouces rouges/dislikes des vidées"
+    },
+    "textDeveloper": {
+        "message": "par Dmitrii Selivanov & Communauté"
+    },
+    "linkWebsite": {
+        "message": "Site web"
+    },
+    "linkFAQ": {
+        "message": "Questions fréquentes"
+    },
+    "linkDonate": {
+        "message": "Faire un don"
+    },
+    "linkHelp": {
+        "message": "Aide"
+    },
+    "legendSettings": {
+        "message": "Paramètres"
+    },
+    "textSettings": {
+        "message": "Désactiver l'envoi des likes/dislikes"
+    },
+    "textSettingsHover": {
+        "message": "Arrête de compter les likes et les dislikes mis sur les vidéos."
+    },
+    "textUpdate": {
+        "message": "mettre à jour vers"
+    }
+}

+ 35 - 0
Extensions/combined/_locales/pt_BR/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Devolver Dislikes do YouTube"
+    },
+    "extensionDesc": {
+        "message": "A capacidade de ver os retornos de não gostos"
+    },
+    "textDeveloper": {
+        "message": "por Dmitrii Selivanov e a Comunidade"
+    },
+    "linkWebsite": {
+        "message": "Website"
+    },
+    "linkFAQ": {
+        "message": "FAQ"
+    },
+    "linkDonate": {
+        "message": "Doe"
+    },
+    "linkHelp": {
+        "message": "Ajuda"
+    },
+    "legendSettings": {
+        "message": "Ajustes"
+    },
+    "textSettings": {
+        "message": "Desaproveitar as aversões"
+    },
+    "textSettingsHover": {
+        "message": "Pare de contar as antipatias."
+    },
+    "textUpdate": {
+        "message": "atualização para"
+    }
+}

+ 35 - 0
Extensions/combined/_locales/ru/messages.json

@@ -0,0 +1,35 @@
+{
+    "extensionName": {
+        "message": "Возвращение отметки не нравится YouTube"
+    },
+    "extensionDesc": {
+        "message": "Возвращает способность видеть отметки не нравится"
+    },
+    "textDeveloper": {
+        "message": "Дмитрий Селиванов и сообщество"
+    },
+    "linkWebsite": {
+        "message": "Сайт"
+    },
+    "linkFAQ": {
+        "message": "ЧАВО"
+    },
+    "linkDonate": {
+        "message": "Пожертвовать"
+    },
+    "linkHelp": {
+        "message": "Помощь"
+    },
+    "legendSettings": {
+        "message": "Настройки"
+    },
+    "textSettings": {
+        "message": "Отключить отправку нравится/не нравится"
+    },
+    "textSettingsHover": {
+        "message": "Отключает отправку ваших отметок нравится/не нравится"
+    },
+    "textUpdate": {
+        "message": "обновление до"
+    }
+}

+ 4 - 3
Extensions/combined/manifest-chrome.json

@@ -1,7 +1,8 @@
 {
-  "name": "Return YouTube Dislike",
-  "description": "Returns ability to see dislikes",
-  "version": "2.1.0.3",
+  "name": "__MSG_extensionName__",
+  "description": "__MSG_extensionDesc__",
+  "default_locale": "en",
+  "version": "2.1.0.4",
   "manifest_version": 3,
   "background": {
     "service_worker": "ryd.background.js"

+ 4 - 3
Extensions/combined/manifest-firefox.json

@@ -1,7 +1,8 @@
 {
-  "name": "Return YouTube Dislike",
-  "description": "Returns ability to see dislikes",
-  "version": "2.1.0.3",
+  "name": "__MSG_extensionName__",
+  "description": "__MSG_extensionDesc__",
+  "default_locale": "en",
+  "version": "2.1.0.4",
   "manifest_version": 2,
   "background": {
     "scripts": ["ryd.background.js"]

+ 13 - 13
Extensions/combined/popup.html

@@ -1,8 +1,8 @@
 <!DOCTYPE html>
-<html lang="en">
+<html>
   <head>
     <meta content="text/html; charset=utf-8" />
-    <title>Return YouTube Dislike</title>
+    <title title="__MSG_extensionName__">__MSG_extensionName__</title>
     <link rel="stylesheet" href="popup.css" />
     <link rel="preconnect" href="https://fonts.googleapis.com" />
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@@ -20,16 +20,16 @@
         />
         <path d="m8 12.5 5.1-2.9L8 6.7v5.8z" fill="#fff" />
       </svg>
-      <h1 style="margin-bottom: 0.75rem">Return YouTube Dislike</h1>
-      <p style="color: var(--lightGrey)">by Dmitrii Selivanov & Community</p>
+      <h1 style="margin-bottom: 0.75rem" title="__MSG_extensionName__">__MSG_extensionName__</h1>
+      <p style="color: var(--lightGrey)" title="__MSG_textDeveloper__">__MSG_textDeveloper__</p>
 
-      <button id="link_website">Website</button>
-      <button id="link_github">GitHub</button>
+      <button id="link_website" title="__MSG_linkWebsite__">__MSG_linkWebsite__</button>
+      <button id="link_github" >GitHub</button>
       <button id="link_discord">Discord</button>
       <br />
-      <button style="margin-top: 0.3rem" id="link_faq">FAQ</button>
-      <button style="margin-top: 0.3em" id="link_donate">Donate</button>
-      <button style="margin-top: 0.3em" id="link_help">Help</button>
+      <button style="margin-top: 0.3rem" id="link_faq" title="__MSG_linkFAQ__">__MSG_linkFAQ__</button>
+      <button style="margin-top: 0.3em" id="link_donate" title="__MSG_linkDonate__">__MSG_linkDonate__</button>
+      <button style="margin-top: 0.3em" id="link_help" title="__MSG_linkHelp__">__MSG_linkHelp__</button>
 
       <br />
       <br />
@@ -40,7 +40,7 @@
         src="./icons/server.svg"
         alt=""
       />
-      
+
       <br />
       <br />
     </center>
@@ -70,12 +70,12 @@
 
     <!-- dialog box -->
     <fieldset id="advancedSettings">
-      <legend id="advancedLegend">Settings</legend>
+      <legend id="advancedLegend" title="__MSG_legendSettings__">__MSG_legendSettings__</legend>
 
-      <label class="switch" data-hover="Stops counting your likes and dislikes.">
+      <label class="switch" data-hover="__MSG_textSettingsHover__">
         <input type="checkbox" id="disable_vote_submission" />
         <span class="slider" />
-        <span class="switchLabel">Disable vote submission</span>
+        <span class="switchLabel" title="__MSG_textSettings__">__MSG_textSettings__</span>
       </label>
       <br />
       <label class="switch">

+ 24 - 3
Extensions/combined/popup.js

@@ -4,7 +4,6 @@ const config = {
   disableVoteSubmission: false,
   numberDisplayFormat: 'compactShort',
   numberDisplayRoundDown: true,
-  
   showAdvancedMessage: '<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor"><rect fill="none" height="24" width="24"/><path d="M19.5,12c0-0.23-0.01-0.45-0.03-0.68l1.86-1.41c0.4-0.3,0.51-0.86,0.26-1.3l-1.87-3.23c-0.25-0.44-0.79-0.62-1.25-0.42 l-2.15,0.91c-0.37-0.26-0.76-0.49-1.17-0.68l-0.29-2.31C14.8,2.38,14.37,2,13.87,2h-3.73C9.63,2,9.2,2.38,9.14,2.88L8.85,5.19 c-0.41,0.19-0.8,0.42-1.17,0.68L5.53,4.96c-0.46-0.2-1-0.02-1.25,0.42L2.41,8.62c-0.25,0.44-0.14,0.99,0.26,1.3l1.86,1.41 C4.51,11.55,4.5,11.77,4.5,12s0.01,0.45,0.03,0.68l-1.86,1.41c-0.4,0.3-0.51,0.86-0.26,1.3l1.87,3.23c0.25,0.44,0.79,0.62,1.25,0.42 l2.15-0.91c0.37,0.26,0.76,0.49,1.17,0.68l0.29,2.31C9.2,21.62,9.63,22,10.13,22h3.73c0.5,0,0.93-0.38,0.99-0.88l0.29-2.31 c0.41-0.19,0.8-0.42,1.17-0.68l2.15,0.91c0.46,0.2,1,0.02,1.25-0.42l1.87-3.23c0.25-0.44,0.14-0.99-0.26-1.3l-1.86-1.41 C19.49,12.45,19.5,12.23,19.5,12z M12.04,15.5c-1.93,0-3.5-1.57-3.5-3.5s1.57-3.5,3.5-3.5s3.5,1.57,3.5,3.5S13.97,15.5,12.04,15.5z"/></svg>',
   hideAdvancedMessage: '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor"><path d="M0 0h24v24H0V0z" fill="none" opacity=".87"/><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm4.3 14.3c-.39.39-1.02.39-1.41 0L12 13.41 9.11 16.3c-.39.39-1.02.39-1.41 0-.39-.39-.39-1.02 0-1.41L10.59 12 7.7 9.11c-.39-.39-.39-1.02 0-1.41.39-.39 1.02-.39 1.41 0L12 10.59l2.89-2.89c.39-.39 1.02-.39 1.41 0 .39.39.39 1.02 0 1.41L13.41 12l2.89 2.89c.38.38.38 1.02 0 1.41z"/></svg>',
 
@@ -18,6 +17,29 @@ const config = {
   },
 };
 
+/*   Change language   */
+function localizeHtmlPage()
+{
+    //Localize by replacing __MSG_***__ meta tags
+    var objects = document.getElementsByTagName('html');
+    for (var j = 0; j < objects.length; j++)
+    {
+        var obj = objects[j];
+
+        var valStrH = obj.innerHTML.toString();
+        var valNewH = valStrH.replace(/__MSG_(\w+)__/g, function(match, v1)
+        {
+            return v1 ? chrome.i18n.getMessage(v1) : "";
+        });
+
+        if(valNewH != valStrH)
+        {
+            obj.innerHTML = valNewH;
+        }
+    }
+}
+
+localizeHtmlPage();
 
 /*   Links   */
 createLink(config.links.website,"link_website")
@@ -85,7 +107,7 @@ function initializeVersionNumber() {
     .then((response) => response.json())
     .then((json) => {
       if (version !== json.version) {
-        document.getElementById('ext-update').innerHTML = 'update to v' + json.version;
+        document.getElementById('ext-update').innerHTML = chrome.i18n.getMessage("textUpdate") +' v' + json.version;
         document.getElementById('ext-update').style.padding = '.25rem .5rem';
       }
     });
@@ -210,7 +232,6 @@ function getNumberFormatter(optionSelect) {
   }
 })();
 
-
 /* popup-script.js
 document.querySelector('#login')
 .addEventListener('click', function () {

+ 5 - 6
Extensions/combined/ryd.content-script.js

@@ -9,6 +9,7 @@ import {
 //---   Import State Functions   ---//
 import {
   isMobile,
+  isShorts,
   isVideoDisliked,
   isVideoLiked,
   getState,
@@ -35,18 +36,16 @@ let jsInitChecktimer = null;
 
 function setEventListeners(evt) {
   function checkForJS_Finish() {
-    if (getButtons()?.offsetParent && isVideoLoaded()) {
-      clearInterval(jsInitChecktimer);
-      jsInitChecktimer = null;
+    if (isShorts() || getButtons()?.offsetParent && isVideoLoaded()) {
       addLikeDislikeEventListener();
       setInitialState();
       getBrowser().storage.onChanged.addListener(storageChangeHandler);
+      clearInterval(jsInitChecktimer);
+      jsInitChecktimer = null;
     }
   }
 
-  if (window.location.href.indexOf("watch?") >= 0) {
-    jsInitChecktimer = setInterval(checkForJS_Finish, 111);
-  }
+  jsInitChecktimer = setInterval(checkForJS_Finish, 111);
 }
 
 setEventListeners();

+ 2 - 2
Extensions/combined/src/bar.js

@@ -1,5 +1,5 @@
 import { getButtons } from "./buttons";
-import { likesDisabledState } from "./state";
+import { isMobile, likesDisabledState } from "./state";
 import { cLog } from "./utils";
 
 function createRateBar(likes, dislikes) {
@@ -14,7 +14,7 @@ function createRateBar(likes, dislikes) {
     const widthPercent =
       likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
 
-    if (!rateBar) {
+    if (!rateBar && !isMobile()) {
       (
         document.getElementById("menu-container") ||
         document.querySelector("ytm-slim-video-action-bar-renderer")

+ 14 - 1
Extensions/combined/src/buttons.js

@@ -1,6 +1,19 @@
-import { isMobile } from "./state";
+import { isMobile, isShorts } from "./state";
+import { isInViewport } from "./utils";
 
 function getButtons() {
+  //---   If Watching Youtube Shorts:   ---//
+  if(isShorts()) {
+    let elements=document.querySelectorAll(isMobile() ? "ytm-like-button-renderer" : "#like-button > ytd-like-button-renderer"); 
+    for(let element of elements) {
+      //Youtube Shorts can have multiple like/dislike buttons when scrolling through videos
+      //However, only one of them should be visible (no matter how you zoom)
+      if(isInViewport(element)) {
+        return element;
+      }
+    }
+  }
+  //---   If Watching On Mobile:   ---//
   if (isMobile()) {
     return document.querySelector(".slim-video-action-bar-actions");
   }

+ 2 - 0
Extensions/combined/src/events.js

@@ -100,6 +100,8 @@ function addLikeDislikeEventListener() {
   if (!window.returnDislikeButtonlistenersSet) {
     buttons.children[0].addEventListener("click", likeClicked);
     buttons.children[1].addEventListener("click", dislikeClicked);
+    buttons.children[0].addEventListener("touchstart", likeClicked);
+    buttons.children[1].addEventListener("touchstart", dislikeClicked);
     window.returnDislikeButtonlistenersSet = true;
   }
 }

+ 11 - 1
Extensions/combined/src/state.js

@@ -29,6 +29,10 @@ function isMobile() {
   return location.hostname == "m.youtube.com";
 }
 
+function isShorts() {
+  return location.pathname.startsWith("/shorts")
+}
+
 function isVideoLiked() {
   if (isMobile()) {
     return (
@@ -74,7 +78,7 @@ function setDislikes(dislikesCount) {
     }
     getButtons().children[1].querySelector("#text").innerText = dislikesCount;
   } else {
-    cLog("likes count diabled by creator");
+    cLog("likes count disabled by creator");
     if (isMobile()) {
       getButtons().children[1].querySelector(
         ".button-renderer-text"
@@ -87,6 +91,11 @@ function setDislikes(dislikesCount) {
 }
 
 function getLikeCountFromButton() {
+  if(isShorts()) {
+    //Youtube Shorts don't work with this query. It's not nessecary; we can skip it and still see the results.
+    //It should be possible to fix this function, but it's not critical to showing the dislike count.
+    return 0;
+  }
   let likesStr = getLikeButton()
     .querySelector("button")
     .getAttribute("aria-label")
@@ -181,6 +190,7 @@ function initializeNumberDisplayFormat() {
 
 export {
   isMobile,
+  isShorts,
   isVideoDisliked,
   isVideoLiked,
   getState,

+ 16 - 1
Extensions/combined/src/utils.js

@@ -78,10 +78,25 @@ function getVideoId(url) {
   if (pathname.startsWith("/clip")) {
     return document.querySelector("meta[itemprop='videoId']").content;
   } else {
+    if (pathname.startsWith("/shorts")) {
+      return pathname.substr(8);
+    }
     return urlObject.searchParams.get("v");
   }
 }
 
+function isInViewport(element) {
+  const rect = element.getBoundingClientRect();
+  const height = innerHeight || document.documentElement.clientHeight;
+  const width = innerWidth || document.documentElement.clientWidth;
+  return (
+      rect.top >= 0 &&
+      rect.left >= 0 &&
+      rect.bottom <= height &&
+      rect.right <= width
+  );
+}
+
 function isVideoLoaded() {
   const videoId = getVideoId(window.location.href);
   return (
@@ -100,4 +115,4 @@ function cLog(message, writer) {
   }
 }
 
-export { numberFormat, getBrowser, getVideoId, isVideoLoaded, cLog }
+export { numberFormat, getBrowser, getVideoId, isInViewport, isVideoLoaded, cLog }

+ 1 - 1
README.md

@@ -39,7 +39,7 @@ You can learn more at our website at: [returnyoutubedislike.com](https://www.ret
 Third-party use of this open API is allowed with the following restrictions:
 
 
-- **Attribution**: This project should be clearly attributed with either a link to this repo or a link to [returnyoutubedislike.com](https://returnyoutubedislike.com/).
+- **Attribution**: This project should be clearly attributed with a link to [returnyoutubedislike.com](https://returnyoutubedislike.com/).
 - **Rate Limiting**: There are per client rate limits in place of 100 per minute and 10'000 per day. This will return a *429* status code indicating that your application should back off.
 
 The API is accessible over the following base URL:  

+ 3 - 3
Website/layouts/default.vue

@@ -76,12 +76,12 @@ export default {
       // Chrome < 70 or FF < 60
       if (
         (this.$ua._parsed.name == "Chrome" &&
-          parseInt(this.$ua._parsed.version.slice(0, 2)) < 70) ||
+          parseInt(this.$ua._parsed.version.split(".")[0]) < 70) ||
         (this.$ua._parsed.name == "Firefox" &&
-          parseInt(this.$ua._parsed.version.slice(0, 2)) < 60)
+          parseInt(this.$ua._parsed.version.split(".")[0]) < 60)
       ) {
         this.alert.html = `<b style="background: #222; border-radius: .5rem; padding: .25rem .25rem .25rem .5rem; margin: 0 .25rem;">
-        ${this.$ua._parsed.name} ${this.$ua._parsed.version.slice(0, 2)}
+        ${this.$ua._parsed.name} ${this.$ua._parsed.version.split(".")[0]}
         </b> is not supported. Consider upgrading to the latest version.`;
         this.alert.show = true;
       }

+ 1 - 1
Website/nuxt.config.js

@@ -16,7 +16,7 @@ export default {
         hid: "description",
         name: "description",
         content:
-          "An extension that returns dislike statistics to YouTube. For now, it only works if a video had public display of dislikes enabled before YouTube removed dislike stats. ",
+          "An extension that returns dislike statistics to YouTube using a combination of scraped dislike stats and estimates extrapolated from extension user data.",
       },
       { hid: "og:image", name: "og:image", content: "/logo.png" },
       { hid: "theme-color", name: "theme-color", content: "#ff0000" },

+ 15 - 1
Website/pages/faq.vue

@@ -13,7 +13,7 @@
         <v-expansion-panel-content class="text-left">
           <hr style="border-color: #444" />
           <br />
-          {{ item.answer }}
+          <span v-html="item.answer" />
         </v-expansion-panel-content>
       </v-expansion-panel>
     </v-expansion-panels>
@@ -54,6 +54,20 @@ export default {
         answer:
           "Coming soon. We are looking into using Oauth or a different read only API with a limited scope so creators can share their dislike counts verifiability. ",
       },
+      {
+        question:
+          "What data do you collect and how is it treated?",
+        answer:
+          "The extension only collects data that is strictly necessary for it to function properly, such as IP address or ID of the video you're watching. None of your data will ever be sold to 3rd parties. If you would like to know more about how we handle security and privacy check out our <a href='https://github.com/Anarios/return-youtube-dislike/blob/main/Docs/SECURITY-FAQ.md'>security FAQ</a>.",
+      },
+      {
+        question: "How does the API/Backend work?",
+        answer: "The backend is using archived data from when the youtube api was still returning the dislike count, extension users like/discount count and extrapolation. In the near future we will be allowing content creators to submit their dislike count easily and safely and we will be adding ArchiveTeam's archived data (4.56 billion videos) into our current database. <a href='https://www.youtube.com/watch?v=GSmmtv-0yYQ'>You can also view a video on the topic.</a>",
+      },
+      {
+        question: "Why does the dislike count show 'DISLIKES DISABLED'?",
+        answer: "At the time of writing we aren't showing dislikes for videos that disabled their likes and dislikes count. The extension displays 'DISLIKES DISABLED' for these videos. We will be showing dislikes on all videos soon, this is just a temporary workaround so people don't think the extension is broken (which isn't working well). Sometimes a recently uploaded video might show 'DISLIKES DISABLED' even if the creator hasn't disabled it, this is due to how we are detecting if dislikes are disabled, it should go away in a few hours or by liking or disliking the video and refreshing the page (hopefully).",
+      },
     ],
   }),
 };

+ 28 - 1
Website/pages/index.vue

@@ -54,9 +54,20 @@
       </v-btn>
     </div>
 
+<!--    <div class="mb-4" style="color: #999">-->
+<!--      Get dislikes manually: <input placeholder=" Video URL">-->
+<!--      <p id="output"></p>-->
+<!--    </div>-->
+
     <v-spacer />
+    <div id="support-ukraine" class="d-flex flex-column items-center py-2">
+      <h3 class="mb-2">
+        <v-img src="/ukraine-flag-xs.png" width="40px"></v-img>
+        <a href="https://helpukrainewin.org/">Support Ukraine</a>
+      </h3>
+    </div>
 
-    <div id="sponsors" class="d-flex flex-column items-center py-8">
+    <div id="cool-people" class="d-flex flex-column items-center py-8">
       <h3 class="mb-4">
         <v-icon class="mb-2">mdi-heart</v-icon>
         Sponsors
@@ -111,6 +122,18 @@ export default {
       ],
     };
   },
+  mounted() {
+    const YOUTUBE_REGEX = /(?:http:|https:)*?\/\/(?:www\.|)(?:youtube\.com|m\.youtube\.com|youtu\.|youtube-nocookie\.com).*(?:v=|v%3D|v\/|(?:a|p)\/(?:a|u)\/\d.*\/|watch\?|vi(?:=|\/)|\/embed\/|oembed\?|be\/|e\/)([^&?%#\/\n]*)/;
+    let lastVideoId = "";
+    window.oninput = (e) => {
+      const videoId = (e.target.value.match(YOUTUBE_REGEX) || {})[1] || e.target.value;
+      if (videoId !== lastVideoId && videoId.length === 11) {
+        fetch("https://returnyoutubedislikeapi.com/votes?videoId=" + (lastVideoId = videoId))
+          .then(resp => resp.json())
+          .then(data => document.getElementById("output").innerText = "Likes=" + data.likes + " Dislikes=" + data.dislikes);
+      }
+    };
+  },
 };
 </script>
 
@@ -120,6 +143,10 @@ export default {
   height: max-content;
 }
 
+input {
+  background-color: #999999;
+}
+
 @media (max-width: 767px) {
   .sponsor {
     margin: 0.5rem;

+ 10 - 0
Website/pages/install.vue

@@ -65,6 +65,14 @@
         No liability on our side, use at your own risk.
       </p>
     </div>
+    <v-btn class="mainAltButton" :href="androidNewPipe" target="_blank">
+      <v-icon style="margin-right: 0.5em">mdi-android</v-icon>
+      Android (NewPipe fork)
+    </v-btn>
+    <v-btn class="mainAltButton" :href="androidVueTube" target="_blank">
+      <v-icon style="margin-right: 0.5em">mdi-android</v-icon>
+      Android (VueTube)
+    </v-btn>
     <v-btn class="mainAltButton" :href="iosJailbreakLink" target="_blank">
       <v-icon style="margin-right: 0.5em">mdi-apple</v-icon>
       iOS (Jailbroken)
@@ -93,6 +101,8 @@ export default {
         "https://github.com/Anarios/return-youtube-dislike/raw/main/Extensions/UserScript/Return%20Youtube%20Dislike.user.js",
 
       iosJailbreakLink: "https://chariz.com/get/return-youtube-dislike/",
+      androidNewPipe: "https://github.com/polymorphicshade/NewPipe",
+      androidVueTube: "https://vuetube.app",
     };
   },
 };

BIN
Website/static/ukraine-flag-xs.png


+ 1 - 1
webpack.config.js

@@ -2,7 +2,7 @@ const path = require("path");
 const CopyPlugin = require("copy-webpack-plugin");
 const FileManagerPlugin = require("filemanager-webpack-plugin");
 
-const entries = ['ryd.content-script', 'ryd.background', 'popup', 'debug'];
+const entries = ['ryd.content-script', 'ryd.background', 'popup'];
 
 const ignorePatterns = [
   "**/manifest-**",