Merge pull request #2 from SimonBrazell/master

force update
This commit is contained in:
Austin Huang 2020-10-23 19:15:38 -04:00 committed by GitHub
commit c668913842
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 2394 additions and 1142 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
liberapay: SimonBrazell
custom: https://www.buymeacoffee.com/SimonBrazell

View File

@ -1,9 +1,10 @@
# ![privacy-redirect](images/icon32.png) Privacy Redirect
# ![privacy-redirect](assets/images/logo-small.png)
[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/SimonBrazell/donate) [![Buy me a coffee](images/buy-me-a-coffee.png)](https://www.buymeacoffee.com/SimonBrazell)
[![Awesome Humane Tech](https://raw.githubusercontent.com/humanetech-community/awesome-humane-tech/main/humane-tech-badge.svg?sanitize=true)](https://github.com/humanetech-community/awesome-humane-tech)
- [Chrome Extension](https://chrome.google.com/webstore/detail/privacy-redirect/pmcmeagblkinmogikoikkdjiligflglb)
- [Firefox Add-on](https://addons.mozilla.org/en-US/firefox/addon/privacy-redirect/)
[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/SimonBrazell/donate) [![Buy me a coffee](assets/images/buy-me-a-coffee.png)](https://www.buymeacoffee.com/SimonBrazell)
[![Firefox Add-on](assets/images/badge-amo.png)](https://addons.mozilla.org/en-US/firefox/addon/privacy-redirect/) [![Chrome Extension](assets/images/badge-chrome.png)](https://chrome.google.com/webstore/detail/privacy-redirect/pmcmeagblkinmogikoikkdjiligflglb) [![Edge Extension](assets/images/badge-ms.png)](https://microsoftedge.microsoft.com/addons/detail/privacy-redirect/elnabkhcgpajchapppkhiaifkgikgihj)
A web extension that redirects Twitter, YouTube, Instagram & Google Maps requests to privacy friendly alternatives - [Nitter](https://github.com/zedeus/nitter), [Invidious](https://github.com/omarroth/invidious), [Bibliogram](https://github.com/cloudrac3r/bibliogram) & [OpenStreetMap](https://www.openstreetmap.org/).
@ -12,9 +13,13 @@ Allows for setting custom [Nitter](https://github.com/zedeus/nitter/wiki/Instanc
## Build
1. `npm install --global web-ext`
2. `web-ext build`
2. `web-ext build --overwrite-dest`
3. See `web-ext-artifacts/` for outputs.
## License
Code released under [the MIT license](LICENSE.txt).
## Privacy Policy
See the [Project Wiki](https://github.com/SimonBrazell/privacy-redirect/wiki/Privacy-Policy).

110
_locales/de/messages.json Normal file
View File

@ -0,0 +1,110 @@
{
"extensionName": {
"message": "Privacy Redirect",
"description": "Name of the extension."
},
"extensionDescription": {
"message": "Leitet Anfragen von Twitter, YouTube, Instagram & Google Maps auf datenschutzfreundliche Alternativen weiter.",
"description": "Description of the extension."
},
"nitterInstance": {
"message": "Nitter-Instanz",
"description": "Label for Nitter instance field option (options)."
},
"invidiousInstance": {
"message": "Invidious-Instanz",
"description": "Label for Invidious instance field option (options)."
},
"bibliogramInstance": {
"message": "Bibliogram-Instanz",
"description": "Label for Bibliogram instance field option (options)."
},
"osmInstance": {
"message": "OpenStreetMap-Instanz",
"description": "Label for OSM instance field option (options)."
},
"disableNitter": {
"message": "Nitter-Weiterleitungen",
"description": "Label for enable/disable Nitter redirects option (options & pop-up)."
},
"disableInvidious": {
"message": "Invidious-Weiterleitungen",
"description": "Label for enable/disable Invidious redirects option (options & pop-up)."
},
"disableBibliogram": {
"message": "Bibliogram-Weiterleitungen",
"description": "Label for enable/disable Bibliogram redirects option (options & pop-up)."
},
"disableOsm": {
"message": "OpenStreetMap-Weiterleitungen",
"description": "Label for enable/disable OSM redirects option (options & pop-up)."
},
"alwaysProxy": {
"message": "Videos immer durch Invidious-Proxy leiten",
"description": "Label for 'Always proxy videos through Invidious' option (options)."
},
"onlyEmbeddedVideo": {
"message": "Nur eingebettete Videos zu Invidious weiterleiten",
"description": "Label for 'Only redirect embedded video to Invidious' option (options)."
},
"videoQuality": {
"message": "Videoqualität bei Invidious",
"description": "Label for 'Invidious Video Quality' option (options)."
},
"removeTwitterSW": {
"message": "Twitter-Serviceworker proaktiv entfernen",
"description": "Label for 'Proactively remove Twitter service worker' option (options)."
},
"invidiousDarkMode": {
"message": "Dunklen Modus auf Invidious immer anschalten",
"description": "Label for 'Invidious dark mode always on' option (options)."
},
"persistInvidiousPrefs": {
"message": "Invidious-Einstellungen dauerhaft beibehalten (als Cookie)",
"description": "Label for 'Persist Invidious preferences (as cookie)' option (options)."
},
"generalTab": {
"message": "Allgmein",
"description": "General tab (options)."
},
"advancedTab": {
"message": "Erweitert",
"description": "Advanced tab (options)."
},
"exceptionsTab": {
"message": "Ausnahmen",
"description": "Exceptions tab (options)."
},
"exceptionsDescriptionP1": {
"message": "Gib eine URL oder einen regulären Ausdruck (Regex) ein, die/der von Weiterleitungen ausgeschlossen werden soll.",
"description": "A description of the 'Exceptions' feature paragraph 1 (options)."
},
"exceptionsDescriptionP2": {
"message": "Alle Anfragen für oder ausgehend von einer URL, die auf die Ausnahme zutrifft, werden von Weiterleitungen ausgeschlossen.",
"description": "A description of the 'Exceptions' feature paragraph 2 (options)."
},
"exceptionsDescriptionP3": {
"message": "Hinweis Unterstützt reguläre JavaScript-Ausdrücke (Regex), mit Ausnahme der einschließenden Schrägstriche.",
"description": "A description of the 'Exceptions' feature paragraph 3 (options)."
},
"addException": {
"message": "Ausnahme hinzufügen",
"description": "'Add Exceptions' button (options)."
},
"moreOptions": {
"message": "Weitere Optionen",
"description": "More Options button (pop-up)."
},
"privacy": {
"message": "Privacy",
"description": "Extension title - Privacy (pop-up)."
},
"redirect": {
"message": "Redirect",
"description": "Extension title - Redirect (pop-up)."
},
"version": {
"message": "Version",
"description": "Version"
}
}

36
_locales/de/store.md Normal file
View File

@ -0,0 +1,36 @@
# Extension Store (AMO & Chrome Web Store) Listing
## Summary:
```
Eine einfache Browser-Erweiterung, die Anfragen an Twitter, YouTube, Instagram & Google Maps zu datenschutzfreundlichen Alternativen weiterleitet.
```
## Description:
```
Leitet Anfragen an Twitter, YouTube, Instagram & Google Maps zu datenschutzfreundlichen Alternativen weiter <a href='https://nitter.net/'>Nitter</a>, <a href='https://invidio.us/'>Invidious</a>, <a href='https://bibliogram.art/'>Bibliogram</a>, & <a href='https://www.openstreetmap.org'>OpenStreetMap</a>.
Erlaubt das Einstellen benutzerdefinierter Instanzen, das Ein- und Ausschalten aller Weiterleitungen und vieles mehr.
<b>★ Weitere Infos: </b>
<ul>
<li><a href='https://github.com/zedeus/nitter#nitter-wip'>Nitter</a></li>
<li><a href='https://github.com/omarroth/invidious#invidious'>Invidious</a></li>
<li><a href='https://github.com/cloudrac3r/bibliogram#bibliogram'>Bibliogram</a></li>
<li><a href='https://wiki.openstreetmap.org/'>OpenStreetMap</a></li>
</ul>
Der Code dieser Browser-Erweiterung ist verfügbar auf <a href='https://github.com/SimonBrazell/privacy-redirect'>Github</a>.
<b>★ Spenden: 👨🏻‍💻</b>
Wenn Ihnen diese Erweiterung gefällt und Sie finanziell in der Lage sind, erwägen Sie bitte <a href='https://www.buymeacoffee.com/SimonBrazell'> mir auf BuyMeACoffee einen Kaffee zu kaufen</a> ☕️ um Ihre Wertschätzung zu zeigen und die Fortsetzung des Projekts zu unterstützen.
<b>★ Was ist neu in dieser Version (v1.1.36) 🆕</b>
<ul>
<li>Russische Übersetzung hinzugefügt</li>
<li>Invidious-Autoplay-Parameter gefixt</li>
</ul>
<b>★ Berechtigungen: </b>
<ul>
<li>Bitte beachten Sie, dass der Zugriff auf alle Website-Navigationsereignisse ( alle URLs), nicht nur auf die Zieldomains, erforderlich ist, damit eingebettete Video-Weiterleitungen stattfinden können. Zur Zeit kenne ich keine andere Möglichkeit, Iframe-Weiterleitungen zu realisieren, freue mich aber über Vorschläge dazu 🙂</li>
</ul>
```

110
_locales/en/messages.json Normal file
View File

@ -0,0 +1,110 @@
{
"extensionName": {
"message": "Privacy Redirect",
"description": "Name of the extension."
},
"extensionDescription": {
"message": "Redirects Twitter, YouTube, Instagram & Google Maps requests to privacy friendly alternatives.",
"description": "Description of the extension."
},
"nitterInstance": {
"message": "Nitter Instance",
"description": "Label for Nitter instance field option (options)."
},
"invidiousInstance": {
"message": "Invidious Instance",
"description": "Label for Invidious instance field option (options)."
},
"bibliogramInstance": {
"message": "Bibliogram Instance",
"description": "Label for Bibliogram instance field option (options)."
},
"osmInstance": {
"message": "OpenStreetMap Instance",
"description": "Label for OSM instance field option (options)."
},
"disableNitter": {
"message": "Nitter Redirects",
"description": "Label for enable/disable Nitter redirects option (options & pop-up)."
},
"disableInvidious": {
"message": "Invidious Redirects",
"description": "Label for enable/disable Invidious redirects option (options & pop-up)."
},
"disableBibliogram": {
"message": "Bibliogram Redirects",
"description": "Label for enable/disable Bibliogram redirects option (options & pop-up)."
},
"disableOsm": {
"message": "OpenStreetMap Redirects",
"description": "Label for enable/disable OSM redirects option (options & pop-up)."
},
"alwaysProxy": {
"message": "Always proxy videos through Invidious",
"description": "Label for 'Always proxy videos through Invidious' option (options)."
},
"onlyEmbeddedVideo": {
"message": "Only redirect embedded video to Invidious",
"description": "Label for 'Only redirect embedded video to Invidious' option (options)."
},
"videoQuality": {
"message": "Invidious Video Quality",
"description": "Label for 'Invidious Video Quality' option (options)."
},
"removeTwitterSW": {
"message": "Proactively remove Twitter service worker",
"description": "Label for 'Proactively remove Twitter service worker' option (options)."
},
"invidiousDarkMode": {
"message": "Invidious dark mode always on",
"description": "Label for 'Invidious dark mode always on' option (options)."
},
"persistInvidiousPrefs": {
"message": "Persist Invidious preferences (as cookie)",
"description": "Label for 'Persist Invidious preferences (as cookie)' option (options)."
},
"generalTab": {
"message": "General",
"description": "General tab (options)."
},
"advancedTab": {
"message": "Advanced",
"description": "Advanced tab (options)."
},
"exceptionsTab": {
"message": "Exceptions",
"description": "Exceptions tab (options)."
},
"exceptionsDescriptionP1": {
"message": "Enter a URL or Regular Expression to be excluded from redirects.",
"description": "A description of the 'Exceptions' feature paragraph 1 (options)."
},
"exceptionsDescriptionP2": {
"message": "All requests for or initiating from a URL that matches the exception will be excluded from redirects.",
"description": "A description of the 'Exceptions' feature paragraph 2 (options)."
},
"exceptionsDescriptionP3": {
"message": "Note - Supports JavaScript regular expressions, excluding the enclosing forward slashes.",
"description": "A description of the 'Exceptions' feature paragraph 3 (options)."
},
"addException": {
"message": "Add Exception",
"description": "'Add Exceptions' button (options)."
},
"moreOptions": {
"message": "More Options",
"description": "More Options button (pop-up)."
},
"privacy": {
"message": "Privacy",
"description": "Extension title - Privacy (pop-up)."
},
"redirect": {
"message": "Redirect",
"description": "Extension title - Redirect (pop-up)."
},
"version": {
"message": "Version",
"description": "Version"
}
}

36
_locales/en/store.md Normal file
View File

@ -0,0 +1,36 @@
# Extension Store (AMO & Chrome Web Store) Listing
## Summary:
```
A simple web extension that redirects Twitter, YouTube, Instagram & Google Maps requests to privacy friendly alternatives.
```
## Description:
```
Redirects Twitter, YouTube, Instagram, & Google Maps requests to privacy friendly alternatives - <a href='https://nitter.net/'>Nitter</a>, <a href='https://invidio.us/'>Invidious</a>, <a href='https://bibliogram.art/'>Bibliogram</a>, & <a href='https://www.openstreetmap.org'>OpenStreetMap</a>.
Allows for setting custom instances, toggling all redirects on/off and more.
<b>★ More Info: </b>
<ul>
<li><a href='https://github.com/zedeus/nitter#nitter-wip'>Nitter</a></li>
<li><a href='https://github.com/omarroth/invidious#invidious'>Invidious</a></li>
<li><a href='https://github.com/cloudrac3r/bibliogram#bibliogram'>Bibliogram</a></li>
<li><a href='https://wiki.openstreetmap.org/'>OpenStreetMap</a></li>
</ul>
The code for this web extension is available on <a href='https://github.com/SimonBrazell/privacy-redirect'>Github</a>.
<b>★ Donate: 👨🏻‍💻</b>
If you like this extension and are financially able please consider <a href='https://www.buymeacoffee.com/SimonBrazell'>buying me a coffee</a> ☕️ to show your appreciation and support the continuation of the project.
<b>★ What's New in This Version (v1.1.36) 🆕</b>
<ul>
<li>Added Russian language translation.</li>
<li>Fix Invidious autoplay parameter.</li>
</ul>
<b>★ Permissions: </b>
<ul>
<li>Please note, access to all website navigation events ( all URLs), not just the target domains, is required to allow embedded video redirects to occur. At this time I know of no other way to achieve iframe redirects, happy to hear some suggestions on this though 🙂</li>
</ul>
```

110
_locales/fr/messages.json Normal file
View File

@ -0,0 +1,110 @@
{
"extensionName": {
"message": "Privacy Redirect",
"description": "Nom du module complémentaire."
},
"extensionDescription": {
"message": "Redirige les requêtes les demandes Twitter, YouTube, Instagram et Google Maps vers des alternatives respectueuses de la vie privée. pour Twitter, YouTube, Instagram et Google Maps vers des alternatives respectueuses de la vie privée.",
"description": "Description du module complémentaire."
},
"nitterInstance": {
"message": "Instance de Nitter",
"description": "Étiquette pour l'option de champ d'instance Nitter (options)."
},
"invidiousInstance": {
"message": "Instance de Invidious",
"description": "Étiquette pour l'option de champ d'instance Invidious (options)."
},
"bibliogramInstance": {
"message": "Instance de Bibliogram",
"description": "Étiquette pour l'option de champ d'instance Bibliogram (options)."
},
"osmInstance": {
"message": "Instance de OpenStreetMap",
"description": "Étiquette pour l'option de champ d'instance OpenStreetMap (options)."
},
"disableNitter": {
"message": "Redirection vers Nitter",
"description": "Étiquette pour activer / désactiver l'option de redirection vers Nitter (options et pop-up)."
},
"disableInvidious": {
"message": "Redirection vers Invidious",
"description": "Étiquette pour activer / désactiver l'option de redirection vers Invidious (options et pop-up)."
},
"disableBibliogram": {
"message": "Redirection vers Bibliogram",
"description": "Étiquette pour activer / désactiver l'option de redirection vers Bibliogram (options et pop-up)."
},
"disableOsm": {
"message": "Redirection vers OpenStreetMap",
"description": "Étiquette pour activer / désactiver l'option de redirection vers OpenStreetMap (options et pop-up)."
},
"alwaysProxy": {
"message": "Toujours transiter par proxy les vidéos via Invidious",
"description": "Libellé pour l'option 'Toujours transiter par proxy les vidéos via Invidious' (options)."
},
"onlyEmbeddedVideo": {
"message": "Rediriger uniquement les vidéos intégrées vers Invidious",
"description": "Libellé pour l'option 'Rediriger uniquement les vidéos intégrées vers Invidious' (options)."
},
"videoQuality": {
"message": "Qualité des vidéos Invidious",
"description": "Libellé pour l'option 'Qualité des vidéos Invidious' (options)."
},
"removeTwitterSW": {
"message": "Supprimer proactivement le service worker de Twitter",
"description": "Libellé pour l'option 'Supprimer proactivement le service worker de Twitter' (options)."
},
"invidiousDarkMode": {
"message": "Mode sombre toujours activé pour Invidious",
"description": "Libellé pour l'option 'Mode sombre toujours activé pour Invidious' (options)."
},
"persistInvidiousPrefs": {
"message": "Conserver les préférences dInvidious (sous forme de cookie)",
"description": "Libellé pour 'Conserver les préférences dInvidious (sous forme de cookie)' option (options)."
},
"generalTab": {
"message": "Général",
"description": "Onglet général (options)."
},
"advancedTab": {
"message": "Avancé",
"description": "Onglet avancé (options)."
},
"exceptionsTab": {
"message": "Exceptions",
"description": "Onglet des Exceptions dans les options."
},
"exceptionsDescriptionP1": {
"message": "Entrez une adresse URL ou une expression régulière qui sera exclue des redirections.",
"description": "Description pour la rubrique 'Exceptions' dans les options."
},
"exceptionsDescriptionP2": {
"message": "Toutes les demandes émanant d'une adresse URL et correspondant à l'exception seront exclues des redirections.",
"description": "Description pour la rubrique 'Exceptions' dans les options."
},
"exceptionsDescriptionP3": {
"message": "Remarque - Prend en charge les expressions régulières JavaScript, à l'exclusion des barres slash.",
"description": "Description pour la rubrique 'Exceptions' dans les options."
},
"addException": {
"message": "Ajoutez une exception",
"description": "boutton 'Ajoutez une exception' dans les options."
},
"moreOptions": {
"message": "Options supplémentaires",
"description": "Boutton des options supplémentaires (pop-up)."
},
"privacy": {
"message": "Vie privée",
"description": "Titre du module complémentaire - Vie privée (pop-up)."
},
"redirect": {
"message": "Redirection",
"description": "Titre du module complémentaire - Redirection (pop-up)."
},
"version": {
"message": "Version",
"description": "Version"
}
}

36
_locales/fr/store.md Normal file
View File

@ -0,0 +1,36 @@
# Extension Store (AMO & Chrome Web Store) Listing
## Summary:
```
Redirige les requêtes les demandes Twitter, YouTube, Instagram et Google Maps vers des alternatives respectueuses de la vie privée. pour Twitter, YouTube, Instagram et Google Maps vers des alternatives respectueuses de la vie privée.
```
## Description:
```
Redirige les requètes pour Twitter, YouTube, Instagram et Google Maps vers des alternatives respectueuses de la confidentialité - <a href="https://nitter.net/">Nitter</a>, <a href="https://invidio.us/">Invidious</a>, <a href="https://bibliogram.art/">Bibliogram</a>, & <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
Permet de définir des instances personnalisées et d'activer ou désactiver toutes les redirections.
<b>★ Plus d'informations: </b>
<ul>
<li><a href="https://github.com/zedeus/nitter#nitter-wip">Nitter</a></li>
<li><a href="https://github.com/omarroth/invidious#invidious">Invidious</a></li>
<li><a href="https://github.com/cloudrac3r/bibliogram#bibliogram">Bibliogram</a></li>
<li><a href="https://wiki.openstreetmap.org/">OpenStreetMap</a></li>
</ul>
Le code de cette extension Web est disponible sur <a href="https://github.com/SimonBrazell/privacy-redirect">Github</a>.
<b>★ Faire un don: 👨🏻‍💻</b>
Si vous aimez ce module complémentaire et si vous avez une bonne situation financière, pensez à <a href="https://www.buymeacoffee.com/SimonBrazell">m'acheter un café</a> ☕️ pour montrer que vous appréciez et soutenez la poursuite du projet.
<b>★ Nouveautés de cette version (v1.1.36) 🆕</b>
<ul>
<li>Added Russian language translation.</li>
<li>Fix Invidious autoplay parameter.</li>
</ul>
<b>★ Autorisations: </b>
<ul>
<li>Veuillez noter que l'accès à tous les événements de navigation sur le site Web (toutes les adresses URL), et pas seulement aux domaines cibles, est requis pour permettre aux redirections vidéo intégrées de se faire correctement. Pour le moment, je ne connais aucun autre moyen de réaliser des redirections iframe, je serais heureux d'entendre quelques suggestions à ce sujet cependant 🙂</li>
</ul>
```

110
_locales/pl/messages.json Normal file
View File

@ -0,0 +1,110 @@
{
"extensionName": {
"message": "Privacy Redirect",
"description": "Nazwa rozszerzenia."
},
"extensionDescription": {
"message": "Przekierowuje serwisy takie jak: Twitter, YouTube, Instagram i Google Maps do alternatyw sprzyjających prywatności.",
"description": "Opis rozszerzenia."
},
"nitterInstance": {
"message": "Instancja Nitter",
"description": "Etykieta dla pola wyboru instancji Nitter (opcje)."
},
"invidiousInstance": {
"message": "Instancja Invidious",
"description": "Etykieta dla pola wyboru instancji Invidious (opcje)."
},
"bibliogramInstance": {
"message": "Instancja Bibliogram",
"description": "Etykieta dla pola wyboru instancji Bibliogram (opcje)."
},
"osmInstance": {
"message": "Instancja OpenStreetMap",
"description": "Etykieta dla pola wyboru instancji OpenStreetMap (opcje)."
},
"disableNitter": {
"message": "Przekierowanie Nitter",
"description": "Etykieta dla włączenia/wyłączenia opcji przekierowania Nitter (opcje i okno pop-up)."
},
"disableInvidious":
"message": "Przekierowanie Invidious ",
"description": "Etykieta dla włączenia/wyłączenia opcji przekierowania Invidious (opcje i okno pop-up)."
},
"disableBibliogram": {
"message": "Przekierowanie Bibliogram",
"description": "Etykieta dla włączenia/wyłączenia opcji przekierowania Bibliogram (opcje i okno pop-up)."
},
"disableOsm": {
"message": "Przekierowanie OpenStreetMap",
"description": "Etykieta dla włączenia/wyłączenia opcji przekierowania OpenStreetMap (opcje i okno pop-up)."
},
"alwaysProxy": {
"message": "Zawsze buforuj i wyświetlaj odnośniki wideo z YouTube poprzez Invidious",
"description": "Etykieta dla opcji 'Zawsze buforuj i wyświetlaj odnośniki wideo poprzez Invidious'."
},
"onlyEmbeddedVideo": {
"message": "Jedynie przekieruj odnośniki wideo do instancji Invidious",
"description": "Etykieta dla opcji 'Jedynie przekieruj odnośniki wideo do instancji Invidious'."
},
"videoQuality": {
"message": "Jakość wideo Invidious",
"description": "Etykieta dla opcji 'Jakość wideo Invidious'."
},
"removeTwitterSW": {
"message": "Proaktywnie usuwaj skrypty serwisowe (service worker) Twittera",
"description": "Etykieta dla opcji 'Proaktywnie usuwaj skrypty serwisowe (service worker) Twittera'."
},
"invidiousDarkMode": {
"message": "Tryb ciemny dla Invidious zawsze włączony",
"description": "Etykieta dla opcji 'Tryb ciemny dla Invidious zawsze włączony'."
},
"persistInvidiousPrefs": {
"message": "Zapisz ustawienia Invidious (jako plik cookie)",
"description": "Etykieta dla 'Zapisz ustawienia Invidious (jako plik cookie)'."
},
"generalTab": {
"message": "Główne",
"description": "Zakładka Główne (opcje)."
},
"advancedTab": {
"message": "Advanced",
"description": "Zakładka zaawansowane (opcje)."
},
"exceptionsTab": {
"message": "Wyjątki",
"description": "Zakładka wyjątki (opcje)."
},
"exceptionsDescriptionP1": {
"message": "Wprowadź adres URL lub wyrażenie regularne, które zostanie wyłączone z przekierowania. ",
"description": "Opis funkcji 'Wyjątki' paragraf 1 (opcje)."
},
"exceptionsDescriptionP2": {
"message": "Wszystkie żądania dla lub inicjalizujące z adresu URL które spełniają wyjątek zostaną wyłączone z przekierowania.",
"description": "Opis funkcji 'Wyjątki' paragraf 2 (opcje)."
},
"exceptionsDescriptionP3": {
"message": "Informacja - Wspierane są wyrażenia regularne JavaScript, wyłączając ukośniki lewe zamykające.",
"description": "Opis funkcji 'Wyjątki' paragraf 3 (opcje)."
},
"addException": {
"message": "Dodaj wyjątek",
"description": "Przycisk 'Dodaj wyjątek' (opcje)."
},
"moreOptions": {
"message": "Więcej opcji",
"description": "Przycisk 'Więcej opcji' (okno pop-up)."
},
"privacy": {
"message": "Prywatność",
"description": "Tytuł rozszerzenia - Privacy (okno pop-up)."
},
"redirect": {
"message": "Redirect",
"description": "Tytuł rozszerzenia - Redirect (pop-up)."
},
"version": {
"message": "Version",
"description": "Wersja"
}
}

130
_locales/ru/messages.json Normal file
View File

@ -0,0 +1,130 @@
{
"extensionName": {
"message": "Privacy Redirect",
"description": "Название расширения."
},
"extensionDescription": {
"message": "Перенаправляет запросы к Twitter, YouTube, Instagram и Google Maps на альтернативные сервисы, дружелюбные к приватности.",
"description": "Описание расширения."
},
"nitterInstance": {
"message": "Сервис Nitter",
"description": "Название настройки (в настройках) поля сервиса Nitter."
},
"invidiousInstance": {
"message": "Сервис Invidious",
"description": "Название настройки (в настройках) поля сервиса Invidious."
},
"bibliogramInstance": {
"message": "Сервис Bibliogram",
"description": "Название настройки (в настройках) поля сервиса Bibliogram."
},
"osmInstance": {
"message": "Сервис OpenStreetMap",
"description": "Название настройки (в настройках) поля сервиса OSM."
},
"disableNitter": {
"message": "Перенаправление на Nitter",
"description": "Название настройки для включения/выключения перенаправления на Nitter (в настройках и всплывающем окне)."
},
"disableInvidious": {
"message": "Перенаправление на Invidious",
"description": "Название настройки для включения/выключения перенаправления на Invidious redirects option (в настройках и всплывающем окне)."
},
"disableBibliogram": {
"message": "Перенаправление на Bibliogram",
"description": "Название настройки для включения/выключения перенаправления на Bibliogram (в настройках и всплывающем окне)."
},
"disableOsm": {
"message": "Перенаправление на OpenStreetMap",
"description": "Название настройки для включения/выключения перенаправления на OSM (в настройках и всплывающем окне)."
},
"theme": {
"message": "Тема",
"description": "Название настройки для 'Тема' (в настройках)."
},
"alwaysProxy": {
"message": "Всегда проксировать видео через Invidious",
"description": "Название настройки для 'Всегда проксировать видео через Invidious' (в настройках)."
},
"onlyEmbeddedVideo": {
"message": "Перенаправлять только встроенные видео на Invidious",
"description": "Название настройки для 'Перенаправлять только встроенные видео на Invidious' (в настройках)."
},
"videoQuality": {
"message": "Качество видео Invidious",
"description": "Название настройки для 'Качество видео Invidious' (в настройках)."
},
"removeTwitterSW": {
"message": "Проактивно удалять service worker для Twitter",
"description": "Название настройки для 'Проактивно удалять service worker для Twitter' (в настройках)."
},
"invidiousDarkMode": {
"message": "Всегда включать темный режим Invidious",
"description": "Название настройки для 'Всегда включать темный режим Invidious' (в настройках)."
},
"invidiousVolume": {
"message": "Громкость Invidious",
"description": "Название настройки для 'Громкость Invidious' (в настройках)."
},
"invidiousPlayerStyle": {
"message": "Стиль плеера Invidious",
"description": "Название настройки для 'Стиль плеера Invidious' (в настройках)."
},
"invidiousSubtitles": {
"message": "Субтитры Invidious - коды языков (разделяются запятой)",
"description": "Название настройки для 'Субтитры Invidious - коды языков (разделяются запятой)' (в настройках)."
},
"invidiousAutoplay": {
"message": "Автоматически воспроизводить видео Invidious при загрузке",
"description": "Название настройки для 'Автоматически воспроизводить видео Invidious при загрузке' (в настройках)."
},
"persistInvidiousPrefs": {
"message": "Сохранять настройки Invidious (в файле cookie)",
"description": "Название настройки для 'Сохранять настройки Invidious (в файле cookie)' (в настройках)."
},
"generalTab": {
"message": "Общие",
"description": "Вкладка 'Общие' (в настройках)."
},
"advancedTab": {
"message": "Дополнительно",
"description": "Вкладка 'Дополнительно' (в настройках)."
},
"exceptionsTab": {
"message": "Исключения",
"description": "Вкладка 'Исключения' (в настройках)."
},
"exceptionsDescriptionP1": {
"message": "Введите URL или регулярное выражение для исключения из перенаправлений.",
"description": "Описание функции 'Исключения' (в настройках)."
},
"exceptionsDescriptionP2": {
"message": "Все запросы на URL, совпадающие с исключениями, или инициированные с них будут исключены из перенаправлений.",
"description": "Описание функции 'Исключения' (в настройках)."
},
"exceptionsDescriptionP3": {
"message": "Примечание: Поддерживает регулярные выражения JavaScript, кроме закрывающих обратных слэшей.",
"description": "Описание функции 'Исключения' (в настройках)."
},
"addException": {
"message": "Добавить исключение",
"description": "Кнопка 'Добавить исключения' (в настройках)."
},
"moreOptions": {
"message": "Другие настройки",
"description": "Кнопка 'Другие настройки' (во всплывающем окне)."
},
"privacy": {
"message": "Privacy",
"description": "Название расширения - Privacy (во всплывающем окне)."
},
"redirect": {
"message": "Redirect",
"description": "Название расширения - Redirect (во всплывающем окне)."
},
"version": {
"message": "Версия",
"description": "Версия."
}
}

36
_locales/ru/store.md Normal file
View File

@ -0,0 +1,36 @@
# Extension Store (AMO & Chrome Web Store) Listing
## Summary:
```
Простое расширение для браузера, которое перенаправляет запросы к Twitter, YouTube, Instagram & Google Maps на альтернативные сервисы, дружелюбные к приватности.
```
## Description:
```
Перенаправляет запросы к Twitter, YouTube, Instagram, & Google Maps на альтернативные сервисы, дружелюбные к приватности - <a href='https://nitter.net/'>Nitter</a>, <a href='https://invidio.us/'>Invidious</a>, <a href='https://bibliogram.art/'>Bibliogram</a> и <a href='https://www.openstreetmap.org'>OpenStreetMap</a>.
Позволяет настраивать пользовательские сервисы, включать/выключать все перенаправления и т.д.
<b>★ Дополнительная информация: </b>
<ul>
<li><a href='https://github.com/zedeus/nitter#nitter-wip'>Nitter</a></li>
<li><a href='https://github.com/omarroth/invidious#invidious'>Invidious</a></li>
<li><a href='https://github.com/cloudrac3r/bibliogram#bibliogram'>Bibliogram</a></li>
<li><a href='https://wiki.openstreetmap.org/'>OpenStreetMap</a></li>
</ul>
Исходный код данного расширения доступен на <a href='https://github.com/SimonBrazell/privacy-redirect'>Github</a>.
<b>★ Пожертвовать: 👨🏻‍💻</b>
Если вам нравится это расширение и вы можете помочь финансово, пожалуйста, <a href='https://www.buymeacoffee.com/SimonBrazell'>купите мне кофе</a> ☕ и покажите ваше одобрение и поддержку развития проекта.
<b>★ Что нового в этой версии (v1.1.36) 🆕</b>
<ul>
<li>Добавлен перевод на русский язык.</li>
<li>Исправлен параметр автоматического воспроизведения Invidious.</li>
</ul>
<b>★ Разрешения: </b>
<ul>
<li>Важно: доступ ко всем сайтам (URL), не только к целевым, требуется для разрешения перенаправления встроенных видео. В данный момент я не знаю, как осуществить перенаправление iframe, буду рад выслушать ваши предложения 🙂</li>
</ul>
```

35
_locales/store.md Normal file
View File

@ -0,0 +1,35 @@
# Extension Store (AMO & Chrome Web Store) Listing
## Summary:
```
Prosta wtyczka która przekierowuje żądania Twitter, YouTube, Instagram oraz Google Maps na odpowiedniki przyjazne dla prywatności.
```
## Description:
```
Przekierowuje żądania Twitter, YouTube, Instagram oraz Google Maps na odpowiedniki przyjazne dla prywatności - <a href='https://nitter.net/'>Nitter</a>, <a href='https://invidio.us/'>Invidious</a>, <a href='https://bibliogram.art/'>Bibliogram</a>, & <a href='https://www.openstreetmap.org'>OpenStreetMap</a>.
Umożliwia ustawienie niestandardowych instancji usług, przełączania przekierowania jako aktywne/nieaktwne i o wiele więcej.
<b>★ Więcej informacji: </b>
<ul>
<li><a href='https://github.com/zedeus/nitter#nitter-wip'>Nitter</a></li>
<li><a href='https://github.com/omarroth/invidious#invidious'>Invidious</a></li>
<li><a href='https://github.com/cloudrac3r/bibliogram#bibliogram'>Bibliogram</a></li>
<li><a href='https://wiki.openstreetmap.org/'>OpenStreetMap</a></li>
</ul>
Kod źródłowy tego rozszerzenia jest dostępny na: <a href='https://github.com/SimonBrazell/privacy-redirect'>Github</a>.
<b>★ Donate: 👨🏻‍💻</b>
Jeżeli lubisz to rozszerzenie i chcesz wesprzeć autora finanosowo, proszę pomyśl o <a href='https://www.buymeacoffee.com/SimonBrazell'>zaserwowaniu małej czarnej</a> ☕️ aby pokazać swoją wdzięczność i wesprzeć możliwości kontynuowania projektu.
<b>★ Co nowego w tej wersji (v1.1.36) 🆕</b>
<ul>
<li>Dodano tłumaczenie w wersji Rosyjskiej</li>
<li>Naprawiono parametr autoodtwarzania Invidious</li>
</ul>
<b>★ Uprawnienia: </b>
<ul>
<li>Zwróć uwagę, że dostęp do wszystkich zdarzeń dotyczących nawigacji po stronach (wszystkie adresy URL) jest wymagany dla poprawnego odtwarzania osadzonych plików wideo. Obecnie nie znam innych możliwości aby obsłużyć przekierowania ramek iFrame, będę wdzięczny za sugestie 🙂</li>
</ul>
```

View File

@ -1,5 +0,0 @@
/*
Retrieved February 19, 2020, from https://www.youtube.com/iframe_api
*/
if (!window['YT']) { var YT = { loading: 0, loaded: 0 }; } if (!window['YTConfig']) { var YTConfig = { 'host': 'http://www.youtube.com' }; } if (!YT.loading) { YT.loading = 1; (function () { var l = []; YT.ready = function (f) { if (YT.loaded) { f(); } else { l.push(f); } }; window.onYTReady = function () { YT.loaded = 1; for (var i = 0; i < l.length; i++) { try { l[i](); } catch (e) { } } }; YT.setConfig = function (c) { for (var k in c) { if (c.hasOwnProperty(k)) { YTConfig[k] = c[k]; } } }; var a = document.createElement('script'); a.type = 'text/javascript'; a.id = 'www-widgetapi-script'; a.src = 'https://s.ytimg.com/yts/jsbin/www-widgetapi-vflYl14TA/www-widgetapi.js'; a.async = true; var c = document.currentScript; if (c) { var n = c.nonce || c.getAttribute('nonce'); if (n) { a.setAttribute('nonce', n); } } var b = document.getElementsByTagName('script')[0]; b.parentNode.insertBefore(a, b); })(); }

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

BIN
assets/images/badge-amo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
assets/images/badge-ms.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 512 512'>
<polyline points='112 184 256 328 400 184' style='fill:none;stroke:#FF5B56;stroke-linecap:round;stroke-linejoin:round;stroke-width:48px'/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 976 B

After

Width:  |  Height:  |  Size: 976 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -0,0 +1,19 @@
window.browser = window.browser || window.chrome;
function localisePage() {
var data = document.querySelectorAll("[data-localise]");
for (var i in data)
if (data.hasOwnProperty(i)) {
var obj = data[i];
var tag = obj.getAttribute("data-localise").toString();
var msg = tag.replace(/__MSG_(\w+)__/g, function (_match, v1) {
return v1 ? browser.i18n.getMessage(v1) : null;
});
if (msg && msg !== tag) obj.textContent = msg;
}
}
localisePage();

View File

@ -0,0 +1,91 @@
"use strict";
const nitterInstances = [
"https://nitter.net",
"https://nitter.snopyta.org",
"https://nitter.42l.fr",
"https://nitter.nixnet.services",
"https://nitter.13ad.de",
"https://nitter.pussthecat.org",
"https://nitter.mastodont.cat",
"https://nitter",
"https://nitter.tedomum.net",
"https://nitter.cattube.org",
"https://nitter.fdn.fr",
"https://nitter.1d4.us",
"https://nitter.kavin.rocks",
];
let disableNitter;
let nitterInstance;
let redirectBypassFlag;
let exceptions;
window.browser = window.browser || window.chrome;
function getRandomInstance() {
return nitterInstances[~~(nitterInstances.length * Math.random())];
}
function isNotException(url) {
return !exceptions.some((regex) => regex.test(url.href));
}
function shouldRedirect(url) {
return (
!redirectBypassFlag &&
isNotException(url) &&
!disableNitter &&
url.host !== nitterInstance &&
!url.pathname.includes("/home")
);
}
function redirectTwitter(url) {
if (url.host.split(".")[0] === "pbs") {
return `${nitterInstance}/pic/${encodeURIComponent(url.href)}`;
} else if (url.host.split(".")[0] === "video") {
return `${nitterInstance}/gif/${encodeURIComponent(url.href)}`;
} else {
return `${nitterInstance}${url.pathname}${url.search}`;
}
}
browser.storage.sync.get(
[
"nitterInstance",
"disableNitter",
"removeTwitterSW",
"redirectBypassFlag",
"exceptions",
],
(result) => {
redirectBypassFlag = result.redirectBypassFlag;
browser.storage.sync.set({
redirectBypassFlag: false,
});
if (!result.removeTwitterSW) {
disableNitter = result.disableNitter;
nitterInstance = result.nitterInstance || getRandomInstance();
exceptions = result.exceptions
? result.exceptions.map((e) => {
return new RegExp(e);
})
: [];
navigator.serviceWorker.getRegistrations().then((registrations) => {
for (let registration of registrations) {
if (registration.scope === "https://twitter.com/") {
registration.unregister();
console.log("Unregistered Twitter SW", registration);
}
}
});
const url = new URL(window.location);
if (shouldRedirect()) {
const redirect = redirectTwitter(url);
console.info("Redirecting", `"${url.href}"`, "=>", `"${redirect}"`);
window.location = redirect;
}
}
}
);

View File

@ -1,44 +0,0 @@
'use strict';
const nitterDefault = 'https://nitter.net';
let disableNitter;
let nitterInstance;
window.browser = window.browser || window.chrome;
function redirectTwitter(url) {
if (url.host.split('.')[0] === 'pbs') {
return `${nitterInstance}/pic/${encodeURIComponent(url.href)}`;
} else if (url.host.split('.')[0] === 'video') {
return `${nitterInstance}/gif/${encodeURIComponent(url.href)}`;
} else {
return `${nitterInstance}${url.pathname}${url.search}`;
};
}
browser.storage.sync.get(
['nitterInstance', 'disableNitter', 'removeTwitterSW'],
(result) => {
if (!result.removeTwitterSW) {
disableNitter = result.disableNitter;
nitterInstance = result.nitterInstance || nitterDefault;
navigator.serviceWorker.getRegistrations().then(registrations => {
for (let registration of registrations) {
if (registration.scope === 'https://twitter.com/') {
registration.unregister();
console.log('Unregistered Twitter SW', registration);
}
}
});
const url = new URL(window.location);
if (!disableNitter && url.host !== nitterInstance) {
const redirect = redirectTwitter(url);
console.info(
'Redirecting', `"${url.href}"`, '=>', `"${redirect}"`
);
window.location = redirect;
}
}
}
);

View File

@ -1,268 +0,0 @@
/*
Retrieved February 19, 2020, from https://s.ytimg.com/yts/jsbin/www-widgetapi-vflYl14TA/www-widgetapi.js
*/
(function () {/*
Copyright The Closure Library Authors.
SPDX-License-Identifier: Apache-2.0
*/
var k; function aa() { var a = l, b = 0; return function () { return b < a.length ? { done: !1, value: a[b++] } : { done: !0 } } }
var ba = "function" == typeof Object.create ? Object.create : function (a) {
function b() { }
b.prototype = a; return new b
}, p;
if ("function" == typeof Object.setPrototypeOf) p = Object.setPrototypeOf; else { var q; a: { var ca = { K: !0 }, da = {}; try { da.__proto__ = ca; q = da.K; break a } catch (a) { } q = !1 } p = q ? function (a, b) { a.__proto__ = b; if (a.__proto__ !== b) throw new TypeError(a + " is not extensible"); return a } : null } var ea = p;
function fa(a, b) { a.prototype = ba(b.prototype); a.prototype.constructor = a; if (ea) ea(a, b); else for (var c in b) if ("prototype" != c) if (Object.defineProperties) { var d = Object.getOwnPropertyDescriptor(b, c); d && Object.defineProperty(a, c, d) } else a[c] = b[c]; a.J = b.prototype }
var ha = "function" == typeof Object.defineProperties ? Object.defineProperty : function (a, b, c) { a != Array.prototype && a != Object.prototype && (a[b] = c.value) };
function ia(a) { a = ["object" == typeof window && window, "object" == typeof self && self, "object" == typeof global && global, a]; for (var b = 0; b < a.length; ++b) { var c = a[b]; if (c && c.Math == Math) return c } return globalThis }
var ja = ia(this); function ka(a, b) { if (b) { for (var c = ja, d = a.split("."), e = 0; e < d.length - 1; e++) { var f = d[e]; f in c || (c[f] = {}); c = c[f] } d = d[d.length - 1]; e = c[d]; f = b(e); f != e && null != f && ha(c, d, { configurable: !0, writable: !0, value: f }) } }
var la = "function" == typeof Object.assign ? Object.assign : function (a, b) { for (var c = 1; c < arguments.length; c++) { var d = arguments[c]; if (d) for (var e in d) Object.prototype.hasOwnProperty.call(d, e) && (a[e] = d[e]) } return a };
ka("Object.assign", function (a) { return a || la });
var r = this || self; function v(a) { a = a.split("."); for (var b = r, c = 0; c < a.length; c++)if (b = b[a[c]], null == b) return null; return b }
function ma() { }
function w(a) {
var b = typeof a; if ("object" == b) if (a) { if (a instanceof Array) return "array"; if (a instanceof Object) return b; var c = Object.prototype.toString.call(a); if ("[object Window]" == c) return "object"; if ("[object Array]" == c || "number" == typeof a.length && "undefined" != typeof a.splice && "undefined" != typeof a.propertyIsEnumerable && !a.propertyIsEnumerable("splice")) return "array"; if ("[object Function]" == c || "undefined" != typeof a.call && "undefined" != typeof a.propertyIsEnumerable && !a.propertyIsEnumerable("call")) return "function" } else return "null";
else if ("function" == b && "undefined" == typeof a.call) return "object"; return b
}
function x(a) { var b = typeof a; return "object" == b && null != a || "function" == b }
function na(a) { return Object.prototype.hasOwnProperty.call(a, y) && a[y] || (a[y] = ++oa) }
var y = "closure_uid_" + (1E9 * Math.random() >>> 0), oa = 0; function pa(a, b, c) { return a.call.apply(a.bind, arguments) }
function qa(a, b, c) { if (!a) throw Error(); if (2 < arguments.length) { var d = Array.prototype.slice.call(arguments, 2); return function () { var e = Array.prototype.slice.call(arguments); Array.prototype.unshift.apply(e, d); return a.apply(b, e) } } return function () { return a.apply(b, arguments) } }
function z(a, b, c) { Function.prototype.bind && -1 != Function.prototype.bind.toString().indexOf("native code") ? z = pa : z = qa; return z.apply(null, arguments) }
var ra = Date.now || function () { return +new Date };
function A(a, b) { var c = a.split("."), d = r; c[0] in d || "undefined" == typeof d.execScript || d.execScript("var " + c[0]); for (var e; c.length && (e = c.shift());)c.length || void 0 === b ? d[e] && d[e] !== Object.prototype[e] ? d = d[e] : d = d[e] = {} : d[e] = b }
function sa(a, b) {
function c() { }
c.prototype = b.prototype; a.J = b.prototype; a.prototype = new c; a.prototype.constructor = a
}
; var ta = Array.prototype.indexOf ? function (a, b) { return Array.prototype.indexOf.call(a, b, void 0) } : function (a, b) {
if ("string" === typeof a) return "string" !== typeof b || 1 != b.length ? -1 : a.indexOf(b, 0);
for (var c = 0; c < a.length; c++)if (c in a && a[c] === b) return c; return -1
}, B = Array.prototype.forEach ? function (a, b, c) { Array.prototype.forEach.call(a, b, c) } : function (a, b, c) { for (var d = a.length, e = "string" === typeof a ? a.split("") : a, f = 0; f < d; f++)f in e && b.call(c, e[f], f, a) }, ua = Array.prototype.reduce ? function (a, b, c) { return Array.prototype.reduce.call(a, b, c) } : function (a, b, c) {
var d = c;
B(a, function (e, f) { d = b.call(void 0, d, e, f, a) });
return d
};
function va(a, b) { a: { var c = a.length; for (var d = "string" === typeof a ? a.split("") : a, e = 0; e < c; e++)if (e in d && b.call(void 0, d[e], e, a)) { c = e; break a } c = -1 } return 0 > c ? null : "string" === typeof a ? a.charAt(c) : a[c] }
function wa(a) { return Array.prototype.concat.apply([], arguments) }
function xa(a) { var b = a.length; if (0 < b) { for (var c = Array(b), d = 0; d < b; d++)c[d] = a[d]; return c } return [] }
; function ya(a) { var b = !1, c; return function () { b || (c = a(), b = !0); return c } }
; var za = /&/g, Aa = /</g, Ba = />/g, Ca = /"/g, Da = /'/g, Ea = /\x00/g, Fa = /[\x00&<>"']/; var E; a: { var Ga = r.navigator; if (Ga) { var Ha = Ga.userAgent; if (Ha) { E = Ha; break a } } E = "" }; function Ia(a, b) { for (var c in a) b.call(void 0, a[c], c, a) }
function Ja(a) { var b = F, c; for (c in b) if (a.call(void 0, b[c], c, b)) return c }
; function G(a, b) { this.b = a === Ka && b || ""; this.a = La }
var La = {}, Ka = {}, H = new G(Ka, ""); function I(a, b) { this.b = a === Ma && b || ""; this.a = Na }
var Na = {}, Ma = {}; function Oa() { this.a = ""; this.b = Pa }
var Pa = {}; function Qa(a) { var b = new Oa; b.a = a; return b }
Qa("<!DOCTYPE html>"); var J = Qa(""); Qa("<br>"); function Ra(a) { var b = new I(Ma, H instanceof G && H.constructor === G && H.a === La ? H.b : "type_error:Const"); a.src = (b instanceof I && b.constructor === I && b.a === Na ? b.b : "type_error:TrustedResourceUrl").toString() }
; var K = window; function L(a, b) { this.width = a; this.height = b }
L.prototype.aspectRatio = function () { return this.width / this.height };
L.prototype.ceil = function () { this.width = Math.ceil(this.width); this.height = Math.ceil(this.height); return this };
L.prototype.floor = function () { this.width = Math.floor(this.width); this.height = Math.floor(this.height); return this };
L.prototype.round = function () { this.width = Math.round(this.width); this.height = Math.round(this.height); return this }; function Sa(a, b) { var c, d; var e = document; e = b || e; if (e.querySelectorAll && e.querySelector && a) return e.querySelectorAll(a ? "." + a : ""); if (a && e.getElementsByClassName) { var f = e.getElementsByClassName(a); return f } f = e.getElementsByTagName("*"); if (a) { var g = {}; for (c = d = 0; e = f[c]; c++) { var h = e.className, m; if (m = "function" == typeof h.split) m = 0 <= ta(h.split(/\s+/), a); m && (g[d++] = e) } g.length = d; return g } return f }
function M(a) { var b = document; a = String(a); "application/xhtml+xml" === b.contentType && (a = a.toLowerCase()); return b.createElement(a) }
function Ta(a, b) { for (var c = 0; a;) { if (b(a)) return a; a = a.parentNode; c++ } return null }
; var Ua = /^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/\\#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#([\s\S]*))?$/; function Va(a) { var b = a.match(Ua); a = b[1]; var c = b[2], d = b[3]; b = b[4]; var e = ""; a && (e += a + ":"); d && (e += "//", c && (e += c + "@"), e += d, b && (e += ":" + b)); return e }
function Wa(a, b, c) { if ("array" == w(b)) for (var d = 0; d < b.length; d++)Wa(a, String(b[d]), c); else null != b && c.push(a + ("" === b ? "" : "=" + encodeURIComponent(String(b)))) }
function Xa(a) { var b = [], c; for (c in a) Wa(c, a[c], b); return b.join("&") }
var Ya = /#|$/; function Za(a) { var b = $a; if (b) for (var c in b) Object.prototype.hasOwnProperty.call(b, c) && a.call(void 0, b[c], c, b) }
function ab() {
var a = []; Za(function (b) { a.push(b) });
return a
}
var $a = { M: "allow-forms", N: "allow-modals", O: "allow-orientation-lock", P: "allow-pointer-lock", R: "allow-popups", S: "allow-popups-to-escape-sandbox", T: "allow-presentation", U: "allow-same-origin", V: "allow-scripts", W: "allow-top-navigation", X: "allow-top-navigation-by-user-activation" }, bb = ya(function () { return ab() });
function cb() {
var a = M("IFRAME"), b = {}; B(bb(), function (c) { a.sandbox && a.sandbox.supports && a.sandbox.supports(c) && (b[c] = !0) });
return b
}
; var db = (new Date).getTime(); function eb() { this.b = []; this.a = -1 }
eb.prototype.set = function (a, b) { b = void 0 === b ? !0 : b; 0 <= a && 52 > a && 0 === a % 1 && this.b[a] != b && (this.b[a] = b, this.a = -1) };
eb.prototype.get = function (a) { return !!this.b[a] };
function fb(a) {
-1 == a.a && (a.a = ua(a.b, function (b, c, d) { return c ? b + Math.pow(2, d) : b }, 0));
return a.a
}
; function gb(a, b) { this.f = a; this.g = b; this.b = 0; this.a = null }
gb.prototype.get = function () { if (0 < this.b) { this.b--; var a = this.a; this.a = a.next; a.next = null } else a = this.f(); return a }; function hb(a) { r.setTimeout(function () { throw a; }, 0) }
var ib;
function jb() {
var a = r.MessageChannel; "undefined" === typeof a && "undefined" !== typeof window && window.postMessage && window.addEventListener && -1 == E.indexOf("Presto") && (a = function () {
var e = M("IFRAME"); e.style.display = "none"; Ra(e); document.documentElement.appendChild(e); var f = e.contentWindow; e = f.document; e.open(); e.write(J instanceof Oa && J.constructor === Oa && J.b === Pa ? J.a : "type_error:SafeHtml"); e.close(); var g = "callImmediate" + Math.random(), h = "file:" == f.location.protocol ? "*" : f.location.protocol + "//" + f.location.host; e =
z(function (m) { if (("*" == h || m.origin == h) && m.data == g) this.port1.onmessage() }, this);
f.addEventListener("message", e, !1); this.port1 = {}; this.port2 = { postMessage: function () { f.postMessage(g, h) } }
});
if ("undefined" !== typeof a && -1 == E.indexOf("Trident") && -1 == E.indexOf("MSIE")) {
var b = new a, c = {}, d = c; b.port1.onmessage = function () { if (void 0 !== c.next) { c = c.next; var e = c.C; c.C = null; e() } };
return function (e) { d.next = { C: e }; d = d.next; b.port2.postMessage(0) }
} return "undefined" !== typeof document && "onreadystatechange" in M("SCRIPT") ? function (e) {
var f = M("SCRIPT");
f.onreadystatechange = function () { f.onreadystatechange = null; f.parentNode.removeChild(f); f = null; e(); e = null };
document.documentElement.appendChild(f)
} : function (e) { r.setTimeout(e, 0) }
}
; function kb() { this.b = this.a = null }
var mb = new gb(function () { return new lb }, function (a) { a.reset() });
kb.prototype.add = function (a, b) { var c = mb.get(); c.set(a, b); this.b ? this.b.next = c : this.a = c; this.b = c };
kb.prototype.remove = function () { var a = null; this.a && (a = this.a, this.a = this.a.next, this.a || (this.b = null), a.next = null); return a };
function lb() { this.next = this.b = this.a = null }
lb.prototype.set = function (a, b) { this.a = a; this.b = b; this.next = null };
lb.prototype.reset = function () { this.next = this.b = this.a = null }; function nb(a) { N || ob(); pb || (N(), pb = !0); qb.add(a, void 0) }
var N; function ob() {
if (r.Promise && r.Promise.resolve) { var a = r.Promise.resolve(void 0); N = function () { a.then(rb) } } else N = function () {
var b = rb, c;
!(c = "function" != w(r.setImmediate)) && (c = r.Window && r.Window.prototype) && (c = -1 == E.indexOf("Edge") && r.Window.prototype.setImmediate == r.setImmediate); c ? (ib || (ib = jb()), ib(b)) : r.setImmediate(b)
}
}
var pb = !1, qb = new kb; function rb() { for (var a; a = qb.remove();) { try { a.a.call(a.b) } catch (c) { hb(c) } var b = mb; b.g(a); 100 > b.b && (b.b++ , a.next = b.a, b.a = a) } pb = !1 }
; function O() { this.f = this.f; this.g = this.g }
O.prototype.f = !1; O.prototype.dispose = function () { this.f || (this.f = !0, this.w()) };
O.prototype.w = function () { if (this.g) for (; this.g.length;)this.g.shift()() }; var sb = r.JSON.stringify; function P(a) { O.call(this); this.m = 1; this.h = []; this.i = 0; this.a = []; this.b = {}; this.o = !!a }
sa(P, O); k = P.prototype; k.subscribe = function (a, b, c) { var d = this.b[a]; d || (d = this.b[a] = []); var e = this.m; this.a[e] = a; this.a[e + 1] = b; this.a[e + 2] = c; this.m = e + 3; d.push(e); return e };
function tb(a, b, c) { var d = Q; if (a = d.b[a]) { var e = d.a; (a = va(a, function (f) { return e[f + 1] == b && e[f + 2] == c })) && d.B(a) } }
k.B = function (a) { var b = this.a[a]; if (b) { var c = this.b[b]; if (0 != this.i) this.h.push(a), this.a[a + 1] = ma; else { if (c) { var d = ta(c, a); 0 <= d && Array.prototype.splice.call(c, d, 1) } delete this.a[a]; delete this.a[a + 1]; delete this.a[a + 2] } } return !!b };
k.G = function (a, b) { var c = this.b[a]; if (c) { for (var d = Array(arguments.length - 1), e = 1, f = arguments.length; e < f; e++)d[e - 1] = arguments[e]; if (this.o) for (e = 0; e < c.length; e++) { var g = c[e]; ub(this.a[g + 1], this.a[g + 2], d) } else { this.i++; try { for (e = 0, f = c.length; e < f; e++)g = c[e], this.a[g + 1].apply(this.a[g + 2], d) } finally { if (this.i-- , 0 < this.h.length && 0 == this.i) for (; c = this.h.pop();)this.B(c) } } return 0 != e } return !1 };
function ub(a, b, c) { nb(function () { a.apply(b, c) }) }
k.clear = function (a) { if (a) { var b = this.b[a]; b && (B(b, this.B, this), delete this.b[a]) } else this.a.length = 0, this.b = {} };
k.w = function () { P.J.w.call(this); this.clear(); this.h.length = 0 }; var R = window.yt && window.yt.config_ || window.ytcfg && window.ytcfg.data_ || {}; A("yt.config_", R); function vb(a) { var b = arguments; 1 < b.length ? R[b[0]] = b[1] : 1 === b.length && Object.assign(R, b[0]) }
function wb() { var a = []; return "ERRORS" in R ? R.ERRORS : a }
; var xb = []; function yb(a) { xb.forEach(function (b) { return b(a) }) }
function zb(a) { return a && window.yterr ? function () { try { return a.apply(this, arguments) } catch (d) { var b = d, c = v("yt.logging.errors.log"); c ? c(b, "ERROR", void 0, void 0, void 0) : (c = wb(), c.push([b, "ERROR", void 0, void 0, void 0]), vb("ERRORS", c)); yb(d) } } : a }
; var Ab = 0; A("ytDomDomGetNextId", v("ytDomDomGetNextId") || function () { return ++Ab }); var Bb = { stopImmediatePropagation: 1, stopPropagation: 1, preventMouseEvent: 1, preventManipulation: 1, preventDefault: 1, layerX: 1, layerY: 1, screenX: 1, screenY: 1, scale: 1, rotation: 1, webkitMovementX: 1, webkitMovementY: 1 };
function S(a) {
this.type = ""; this.state = this.source = this.data = this.currentTarget = this.relatedTarget = this.target = null; this.charCode = this.keyCode = 0; this.metaKey = this.shiftKey = this.ctrlKey = this.altKey = !1; this.clientY = this.clientX = 0; this.changedTouches = this.touches = null; try {
if (a = a || window.event) {
this.event = a; for (var b in a) b in Bb || (this[b] = a[b]); var c = a.target || a.srcElement; c && 3 == c.nodeType && (c = c.parentNode); this.target = c; var d = a.relatedTarget; if (d) try { d = d.nodeName ? d : null } catch (e) { d = null } else "mouseover" ==
this.type ? d = a.fromElement : "mouseout" == this.type && (d = a.toElement); this.relatedTarget = d; this.clientX = void 0 != a.clientX ? a.clientX : a.pageX; this.clientY = void 0 != a.clientY ? a.clientY : a.pageY; this.keyCode = a.keyCode ? a.keyCode : a.which; this.charCode = a.charCode || ("keypress" == this.type ? this.keyCode : 0); this.altKey = a.altKey; this.ctrlKey = a.ctrlKey; this.shiftKey = a.shiftKey; this.metaKey = a.metaKey
}
} catch (e) { }
}
S.prototype.preventDefault = function () { this.event && (this.event.returnValue = !1, this.event.preventDefault && this.event.preventDefault()) };
S.prototype.stopPropagation = function () { this.event && (this.event.cancelBubble = !0, this.event.stopPropagation && this.event.stopPropagation()) };
S.prototype.stopImmediatePropagation = function () { this.event && (this.event.cancelBubble = !0, this.event.stopImmediatePropagation && this.event.stopImmediatePropagation()) }; var F = v("ytEventsEventsListeners") || {}; A("ytEventsEventsListeners", F); var Cb = v("ytEventsEventsCounter") || { count: 0 }; A("ytEventsEventsCounter", Cb);
function Db(a, b, c, d) {
d = void 0 === d ? {} : d; a.addEventListener && ("mouseenter" != b || "onmouseenter" in document ? "mouseleave" != b || "onmouseenter" in document ? "mousewheel" == b && "MozBoxSizing" in document.documentElement.style && (b = "MozMousePixelScroll") : b = "mouseout" : b = "mouseover"); return Ja(function (e) {
var f = "boolean" === typeof e[4] && e[4] == !!d, g; if (g = x(e[4]) && x(d)) a: { g = e[4]; for (var h in g) if (!(h in d) || g[h] !== d[h]) { g = !1; break a } for (var m in d) if (!(m in g)) { g = !1; break a } g = !0 } return !!e.length && e[0] == a && e[1] == b && e[2] ==
c && (f || g)
})
}
function Eb(a) { a && ("string" == typeof a && (a = [a]), B(a, function (b) { if (b in F) { var c = F[b], d = c[0], e = c[1], f = c[3]; c = c[4]; d.removeEventListener ? Fb() || "boolean" === typeof c ? d.removeEventListener(e, f, c) : d.removeEventListener(e, f, !!c.capture) : d.detachEvent && d.detachEvent("on" + e, f); delete F[b] } })) }
var Fb = ya(function () {
var a = !1; try {
var b = Object.defineProperty({}, "capture", { get: function () { a = !0 } });
window.addEventListener("test", null, b)
} catch (c) { } return a
});
function Gb(a, b, c) {
var d = void 0 === d ? {} : d; if (a && (a.addEventListener || a.attachEvent)) {
var e = Db(a, b, c, d); if (!e) {
e = ++Cb.count + ""; var f = !("mouseenter" != b && "mouseleave" != b || !a.addEventListener || "onmouseenter" in document); var g = f ? function (h) { h = new S(h); if (!Ta(h.relatedTarget, function (m) { return m == a })) return h.currentTarget = a, h.type = b, c.call(a, h) } : function (h) {
h = new S(h);
h.currentTarget = a; return c.call(a, h)
};
g = zb(g); a.addEventListener ? ("mouseenter" == b && f ? b = "mouseover" : "mouseleave" == b && f ? b = "mouseout" : "mousewheel" == b && "MozBoxSizing" in document.documentElement.style && (b = "MozMousePixelScroll"), Fb() || "boolean" === typeof d ? a.addEventListener(b, g, d) : a.addEventListener(b, g, !!d.capture)) : a.attachEvent("on" + b, g); F[e] = [a, b, c, g, d]
}
}
}
; function Hb(a) { "function" == w(a) && (a = zb(a)); return window.setInterval(a, 250) }
; function Ib(a) {
var b = []; Ia(a, function (c, d) { var e = encodeURIComponent(String(d)), f; "array" == w(c) ? f = c : f = [c]; B(f, function (g) { "" == g ? b.push(e) : b.push(e + "=" + encodeURIComponent(String(g))) }) });
return b.join("&")
}
; var Jb = {}; function Kb(a) { return Jb[a] || (Jb[a] = String(a).replace(/\-([a-z])/g, function (b, c) { return c.toUpperCase() })) }
; var T = {}, l = [], Q = new P, Lb = {}; function Mb() { var a = "undefined" != typeof Symbol && Symbol.iterator && l[Symbol.iterator]; var b; a ? b = a.call(l) : b = { next: aa() }; a = b; for (b = a.next(); !b.done; b = a.next())b = b.value, b() }
function Nb(a, b) { b || (b = document); var c = xa(b.getElementsByTagName("yt:" + a)), d = "yt-" + a, e = b || document; d = xa(e.querySelectorAll && e.querySelector ? e.querySelectorAll("." + d) : Sa(d, b)); return wa(c, d) }
function U(a, b) { var c; "yt:" == a.tagName.toLowerCase().substr(0, 3) ? c = a.getAttribute(b) : c = a ? a.dataset ? a.dataset[Kb(b)] : a.getAttribute("data-" + b) : null; return c }
function Ob(a, b) { Q.G.apply(Q, arguments) }
; function Pb(a) { this.b = a || {}; this.f = this.a = !1; a = document.getElementById("www-widgetapi-script"); if (this.a = !!("https:" == document.location.protocol || a && 0 == a.src.indexOf("https:"))) { a = [this.b, window.YTConfig || {}]; for (var b = 0; b < a.length; b++)a[b].host && (a[b].host = a[b].host.replace("http://", "https://")) } }
function V(a, b) { for (var c = [a.b, window.YTConfig || {}], d = 0; d < c.length; d++) { var e = c[d][b]; if (void 0 != e) return e } return null }
function Qb(a, b, c) { W || (W = {}, Gb(window, "message", z(a.g, a))); W[c] = b }
Pb.prototype.g = function (a) { if (a.origin == V(this, "host") || a.origin == V(this, "host").replace(/^http:/, "https:")) { try { var b = JSON.parse(a.data) } catch (c) { return } this.f = !0; this.a || 0 != a.origin.indexOf("https:") || (this.a = !0); if (a = W[b.id]) a.o = !0, a.o && (B(a.m, a.A, a), a.m.length = 0), a.H(b) } };
var W = null; function Rb() {
var a = Sb, b = {}; b.dt = db; b.flash = "0"; a: { try { var c = a.a.top.location.href } catch (f) { a = 2; break a } a = c ? c === a.b.location.href ? 0 : 1 : 2 } b = (b.frm = a, b); b.u_tz = -(new Date).getTimezoneOffset(); var d = void 0 === d ? K : d; try { var e = d.history.length } catch (f) { e = 0 } b.u_his = e; b.u_java = !!K.navigator && "unknown" !== typeof K.navigator.javaEnabled && !!K.navigator.javaEnabled && K.navigator.javaEnabled(); K.screen && (b.u_h = K.screen.height, b.u_w = K.screen.width, b.u_ah = K.screen.availHeight, b.u_aw = K.screen.availWidth, b.u_cd = K.screen.colorDepth);
K.navigator && K.navigator.plugins && (b.u_nplug = K.navigator.plugins.length); K.navigator && K.navigator.mimeTypes && (b.u_nmime = K.navigator.mimeTypes.length); return b
}
function Tb() {
var a = Sb; var b = a.a; try { var c = b.screenX; var d = b.screenY } catch (t) { } try { var e = b.outerWidth; var f = b.outerHeight } catch (t) { } try { var g = b.innerWidth; var h = b.innerHeight } catch (t) { } b = [b.screenLeft, b.screenTop, c, d, b.screen ? b.screen.availWidth : void 0, b.screen ? b.screen.availTop : void 0, e, f, g, h]; c = a.a.top; try { var m = (c || window).document, n = "CSS1Compat" == m.compatMode ? m.documentElement : m.body; var u = (new L(n.clientWidth, n.clientHeight)).round() } catch (t) { u = new L(-12245933, -12245933) } m = u; u = {}; n = new eb; r.SVGElement &&
r.document.createElementNS && n.set(0); c = cb(); c["allow-top-navigation-by-user-activation"] && n.set(1); c["allow-popups-to-escape-sandbox"] && n.set(2); r.crypto && r.crypto.subtle && n.set(3); r.TextDecoder && r.TextEncoder && n.set(4); n = fb(n); u.bc = n; u.bih = m.height; u.biw = m.width; u.brdim = b.join(); a = a.b; return u.vis = { visible: 1, hidden: 2, prerender: 3, preview: 4, unloaded: 5 }[a.visibilityState || a.webkitVisibilityState || a.mozVisibilityState || ""] || 0, u.wgl = !!K.WebGLRenderingContext, u
}
var Sb = new function () { var a = window.document; this.a = window; this.b = a };
A("yt.ads_.signals_.getAdSignalsString", function (a) { a = void 0 === a ? v("yt.ads.biscotti.lastId_") || "" : a; var b = Object.assign(Rb(), Tb()); b.ca_type = "image"; a && (b.bid = a); return Ib(b) }); ra(); function X(a, b, c) {
this.i = this.a = this.b = null; this.h = na(this); this.f = 0; this.o = !1; this.m = []; this.g = null; this.D = c; this.I = {}; c = document; if (a = "string" === typeof a ? c.getElementById(a) : a) if (c = "iframe" == a.tagName.toLowerCase(), b.host || (b.host = c ? Va(a.src) : "https://www.youtube.com"), this.b = new Pb(b), c || (b = Ub(this, a), this.i = a, (c = a.parentNode) && c.replaceChild(b, a), a = b), this.a = a, this.a.id || (this.a.id = "widget" + na(this.a)), T[this.a.id] = this, window.postMessage) {
this.g = new P; Vb(this); b = V(this.b, "events"); for (var d in b) b.hasOwnProperty(d) &&
this.addEventListener(d, b[d]); for (var e in Lb) Wb(this, e)
}
}
k = X.prototype; k.setSize = function (a, b) { this.a.width = a; this.a.height = b; return this };
k.L = function () { return this.a };
k.H = function (a) { this.s(a.event, a) };
k.addEventListener = function (a, b) {
var c = b; "string" == typeof b && (c = function () { window[b].apply(window, arguments) });
if (!c) return this; this.g.subscribe(a, c); Xb(this, a); return this
};
function Wb(a, b) { var c = b.split("."); if (2 == c.length) { var d = c[1]; a.D == c[0] && Xb(a, d) } }
k.destroy = function () { this.a.id && (T[this.a.id] = null); var a = this.g; a && "function" == typeof a.dispose && a.dispose(); if (this.i) { a = this.a; var b = a.parentNode; b && b.replaceChild(this.i, a) } else (a = this.a) && a.parentNode && a.parentNode.removeChild(a); W && (W[this.h] = null); this.b = null; a = this.a; for (var c in F) F[c][0] == a && Eb(c); this.i = this.a = null };
k.u = function () { return {} };
function Yb(a, b, c) { c = c || []; c = Array.prototype.slice.call(c); b = { event: "command", func: b, args: c }; a.o ? a.A(b) : a.m.push(b) }
k.s = function (a, b) { if (!this.g.f) { var c = { target: this, data: b }; this.g.G(a, c); Ob(this.D + "." + a, c) } };
function Ub(a, b) {
for (var c = document.createElement("iframe"), d = b.attributes, e = 0, f = d.length; e < f; e++) { var g = d[e].value; null != g && "" != g && "null" != g && c.setAttribute(d[e].name, g) } c.setAttribute("frameBorder", 0); c.setAttribute("allowfullscreen", 1); c.setAttribute("allow", "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"); c.setAttribute("title", "YouTube " + V(a.b, "title")); (d = V(a.b, "width")) && c.setAttribute("width", d); (d = V(a.b, "height")) && c.setAttribute("height", d); var h = a.u(); h.enablejsapi =
window.postMessage ? 1 : 0; window.location.host && (h.origin = window.location.protocol + "//" + window.location.host); h.widgetid = a.h; window.location.href && B(["debugjs", "debugcss"], function (m) {
var n = window.location.href; var u = n.search(Ya); b: { var t = 0; for (var C = m.length; 0 <= (t = n.indexOf(m, t)) && t < u;) { var D = n.charCodeAt(t - 1); if (38 == D || 63 == D) if (D = n.charCodeAt(t + C), !D || 61 == D || 38 == D || 35 == D) break b; t += C + 1 } t = -1 } if (0 > t) n = null; else {
C = n.indexOf("&", t); if (0 > C || C > u) C = u; t += m.length + 1; n = decodeURIComponent(n.substr(t, C - t).replace(/\+/g,
" "))
} null !== n && (h[m] = n)
});
c.src = V(a.b, "host") + a.v() + "?" + Xa(h); return c
}
k.F = function () { this.a && this.a.contentWindow ? this.A({ event: "listening" }) : window.clearInterval(this.f) };
function Vb(a) { Qb(a.b, a, a.h); a.f = Hb(z(a.F, a)); Gb(a.a, "load", z(function () { window.clearInterval(this.f); this.f = Hb(z(this.F, this)) }, a)) }
function Xb(a, b) { a.I[b] || (a.I[b] = !0, Yb(a, "addEventListener", [b])) }
k.A = function (a) {
a.id = this.h; a.channel = "widget"; a = sb(a); var b = this.b; var c = Va(this.a.src || ""); b = 0 == c.indexOf("https:") ? [c] : b.a ? [c.replace("http:", "https:")] : b.f ? [c] : [c, c.replace("http:", "https:")]; if (this.a.contentWindow) for (c = 0; c < b.length; c++)try { this.a.contentWindow.postMessage(a, b[c]) } catch (f) {
if (f.name && "SyntaxError" == f.name) {
if (!(f.message && 0 < f.message.indexOf("target origin ''"))) {
var d = f, e = v("yt.logging.errors.log"); e ? e(d, "WARNING", void 0, void 0, !1, void 0) : (e = wb(), e.push([d, "WARNING", void 0,
void 0, !1, void 0]), vb("ERRORS", e))
}
} else throw f;
} else console && console.warn && console.warn("The YouTube player is not attached to the DOM. API calls should be made after the onReady event. See more: https://developers.google.com/youtube/iframe_api_reference#Events")
}; function Zb(a) { return (0 == a.search("cue") || 0 == a.search("load")) && "loadModule" != a }
function $b(a) { return 0 == a.search("get") || 0 == a.search("is") }
; function Y(a, b) { if (!a) throw Error("YouTube player element ID required."); var c = { title: "video player", videoId: "", width: 640, height: 360 }; if (b) for (var d in b) c[d] = b[d]; X.call(this, a, c, "player"); this.j = {}; this.l = {} }
fa(Y, X); k = Y.prototype; k.v = function () { return "/embed/" + V(this.b, "videoId") };
k.u = function () { var a = V(this.b, "playerVars"); if (a) { var b = {}, c; for (c in a) b[c] = a[c]; a = b } else a = {}; window != window.top && document.referrer && (a.widget_referrer = document.referrer.substring(0, 256)); if (c = V(this.b, "embedConfig")) { if (x(c)) try { c = JSON.stringify(c) } catch (d) { console.error("Invalid embed config JSON", d) } a.embed_config = c } return a };
k.H = function (a) { var b = a.event; a = a.info; switch (b) { case "apiInfoDelivery": if (x(a)) for (var c in a) this.j[c] = a[c]; break; case "infoDelivery": ac(this, a); break; case "initialDelivery": window.clearInterval(this.f); this.l = {}; this.j = {}; bc(this, a.apiInterface); ac(this, a); break; default: this.s(b, a) } };
function ac(a, b) { if (x(b)) for (var c in b) a.l[c] = b[c] }
function bc(a, b) {
B(b, function (c) {
this[c] || ("getCurrentTime" == c ? this[c] = function () { var d = this.l.currentTime; if (1 == this.l.playerState) { var e = (ra() / 1E3 - this.l.currentTimeLastUpdated_) * this.l.playbackRate; 0 < e && (d += Math.min(e, 1)) } return d } : Zb(c) ? this[c] = function () {
this.l = {};
this.j = {}; Yb(this, c, arguments); return this
} : $b(c) ? this[c] = function () {
var d = 0;
0 == c.search("get") ? d = 3 : 0 == c.search("is") && (d = 2); return this.l[c.charAt(d).toLowerCase() + c.substr(d + 1)]
} : this[c] = function () {
Yb(this, c, arguments);
return this
})
}, a)
}
k.getVideoEmbedCode = function () {
var a = parseInt(V(this.b, "width"), 10); var b = parseInt(V(this.b, "height"), 10), c = V(this.b, "host") + this.v(); Fa.test(c) && (-1 != c.indexOf("&") && (c = c.replace(za, "&amp;")), -1 != c.indexOf("<") && (c = c.replace(Aa, "&lt;")), -1 != c.indexOf(">") && (c = c.replace(Ba, "&gt;")), -1 != c.indexOf('"') && (c = c.replace(Ca, "&quot;")), -1 != c.indexOf("'") && (c = c.replace(Da, "&#39;")), -1 != c.indexOf("\x00") && (c = c.replace(Ea, "&#0;"))); a = '<iframe width="' + a + '" height="' + b + '" src="' + c + '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
return a
};
k.getOptions = function (a) { return this.j.namespaces ? a ? this.j[a].options || [] : this.j.namespaces || [] : [] };
k.getOption = function (a, b) { if (this.j.namespaces && a && b) return this.j[a][b] };
function cc(a) { if ("iframe" != a.tagName.toLowerCase()) { var b = U(a, "videoid"); b && (b = { videoId: b, width: U(a, "width"), height: U(a, "height") }, new Y(a, b)) } }
; function Z(a, b) { var c = { title: "Thumbnail", videoId: "", width: 120, height: 68 }; if (b) for (var d in b) c[d] = b[d]; X.call(this, a, c, "thumbnail") }
fa(Z, X); Z.prototype.v = function () { return "/embed/" + V(this.b, "videoId") };
Z.prototype.u = function () { return { player: 0, thumb_width: V(this.b, "thumbWidth"), thumb_height: V(this.b, "thumbHeight"), thumb_align: V(this.b, "thumbAlign") } };
Z.prototype.s = function (a, b) { X.prototype.s.call(this, a, b ? b.info : void 0) };
function dc(a) { if ("iframe" != a.tagName.toLowerCase()) { var b = U(a, "videoid"); if (b) { b = { videoId: b, events: {}, width: U(a, "width"), height: U(a, "height"), thumbWidth: U(a, "thumb-width"), thumbHeight: U(a, "thumb-height"), thumbAlign: U(a, "thumb-align") }; var c = U(a, "onclick"); c && (b.events.onClick = c); new Z(a, b) } } }
; A("YT.PlayerState.UNSTARTED", -1); A("YT.PlayerState.ENDED", 0); A("YT.PlayerState.PLAYING", 1); A("YT.PlayerState.PAUSED", 2); A("YT.PlayerState.BUFFERING", 3); A("YT.PlayerState.CUED", 5); A("YT.get", function (a) { return T[a] });
A("YT.scan", Mb); A("YT.subscribe", function (a, b, c) { Q.subscribe(a, b, c); Lb[a] = !0; for (var d in T) Wb(T[d], a) });
A("YT.unsubscribe", function (a, b, c) { tb(a, b, c) });
A("YT.Player", Y); A("YT.Thumbnail", Z); X.prototype.destroy = X.prototype.destroy; X.prototype.setSize = X.prototype.setSize; X.prototype.getIframe = X.prototype.L; X.prototype.addEventListener = X.prototype.addEventListener; Y.prototype.getVideoEmbedCode = Y.prototype.getVideoEmbedCode; Y.prototype.getOptions = Y.prototype.getOptions; Y.prototype.getOption = Y.prototype.getOption; l.push(function (a) { a = Nb("player", a); B(a, cc) });
l.push(function () { var a = Nb("thumbnail"); B(a, dc) });
"undefined" != typeof YTConfig && YTConfig.parsetags && "onload" != YTConfig.parsetags || Mb(); var ec = v("onYTReady"); ec && ec(); var fc = v("onYouTubeIframeAPIReady"); fc && fc(); var gc = v("onYouTubePlayerAPIReady"); gc && gc();
}).call(this);

View File

@ -1,25 +1,47 @@
'use strict';
"use strict";
const invidiousDefault = 'https://invidio.us';
const youtubeDomains = [
'm.youtube.com',
'youtube.com',
'img.youtube.com',
'www.youtube.com',
'youtube-nocookie.com',
'www.youtube-nocookie.com',
'youtu.be',
's.ytimg.com',
"m.youtube.com",
"youtube.com",
"img.youtube.com",
"www.youtube.com",
"youtube-nocookie.com",
"www.youtube-nocookie.com",
"youtu.be",
"s.ytimg.com",
"music.youtube.com",
];
const invidiousInstances = [
"https://invidious.snopyta.org",
"https://yewtu.be",
"https://invidious.13ad.de",
"https://invidious.xyz",
"https://invidious.site",
"https://invidiou.site",
"https://invidious.fdn.fr",
"https://invidious.toot.koeln",
];
const nitterDefault = 'https://nitter.net';
const twitterDomains = [
'twitter.com',
'www.twitter.com',
'mobile.twitter.com',
'pbs.twimg.com',
'video.twimg.com',
"twitter.com",
"www.twitter.com",
"mobile.twitter.com",
"pbs.twimg.com",
"video.twimg.com",
];
const nitterInstances = [
"https://nitter.net",
"https://nitter.snopyta.org",
"https://nitter.42l.fr",
"https://nitter.nixnet.services",
"https://nitter.13ad.de",
"https://nitter.pussthecat.org",
"https://nitter.mastodont.cat",
"https://nitter.tedomum.net",
"https://nitter.cattube.org",
"https://nitter.fdn.fr",
"https://nitter.1d4.us",
"https://nitter.kavin.rocks",
];
const bibliogramDefault = 'https://bibliogram.art';
const instagramDomains = [
"instagram.com",
"www.instagram.com",
@ -27,50 +49,57 @@ const instagramDomains = [
"about.instagram.com",
];
const instagramReservedPaths = [
'about',
'explore',
'support',
'press',
'api',
'privacy',
'safety',
'admin',
'graphql',
'accounts',
'help',
'terms',
'contact',
'blog',
'igtv',
'u',
'p',
'fragment',
'imageproxy',
'videoproxy',
'.well-known'
"about",
"explore",
"support",
"press",
"api",
"privacy",
"safety",
"admin",
"graphql",
"accounts",
"help",
"terms",
"contact",
"blog",
"igtv",
"u",
"p",
"fragment",
"imageproxy",
"videoproxy",
".well-known",
];
const bibliogramBypassPaths = /\/(accounts\/|embeds?.js)/;
const bibliogramInstances = [
'https://bibliogram.art',
'https://bibliogram.snopyta.org'
"https://bibliogram.art",
"https://bibliogram.snopyta.org",
"https://bibliogram.pussthecat.org",
"https://bibliogram.nixnet.services",
"https://bg.endl.site",
"https://bibliogram.13ad.de ",
"https://bibliogram.stemy.me ",
"https://bibliogram.hamster.dance",
"https://bibliogram.ggc-project.de",
];
const osmDefault = 'https://openstreetmap.org';
const googleMapsRegex = /https?:\/\/(((www|maps)\.)?(google).*(\/maps)|maps\.(google).*)/;
const osmDefault = "https://openstreetmap.org";
const googleMapsRegex = /https?:\/\/(((www|maps)\.)?(google\.).*(\/maps)|maps\.(google\.).*)/;
const mapCentreRegex = /@(-?\d[0-9.]*),(-?\d[0-9.]*),(\d{1,2})[.z]/;
const dataLatLngRegex = /(!3d|!4d)(-?[0-9]{1,10}.[0-9]{1,10})/g;
const placeRegex = /\/place\/(.*)\//;
const travelModes = {
'driving': 'fossgis_osrm_car',
'walking': 'fossgis_osrm_foot',
'bicycling': 'fossgis_osrm_bike',
'transit': 'fossgis_osrm_car' // not implemented on OSM, default to car.
driving: "fossgis_osrm_car",
walking: "fossgis_osrm_foot",
bicycling: "fossgis_osrm_bike",
transit: "fossgis_osrm_car", // not implemented on OSM, default to car.
};
const layers = {
'none': 'S',
'transit': 'T',
'traffic': 'S', // not implemented on OSM, default to standard.
'bicycling': 'C'
}
none: "S",
transit: "T",
traffic: "S", // not implemented on OSM, default to standard.
bicycling: "C",
};
let disableNitter;
let disableInvidious;
@ -84,85 +113,119 @@ let alwaysProxy;
let onlyEmbeddedVideo;
let videoQuality;
let invidiousDarkMode;
let whitelist;
let invidiousVolume;
let invidiousPlayerStyle;
let invidiousSubtitles;
let invidiousAutoplay;
let exceptions;
window.browser = window.browser || window.chrome;
browser.storage.sync.get(
[
'nitterInstance',
'invidiousInstance',
'bibliogramInstance',
'osmInstance',
'disableNitter',
'disableInvidious',
'disableBibliogram',
'disableOsm',
'alwaysProxy',
'onlyEmbeddedVideo',
'videoQuality',
'invidiousDarkMode',
'whitelist'
"nitterInstance",
"invidiousInstance",
"bibliogramInstance",
"osmInstance",
"disableNitter",
"disableInvidious",
"disableBibliogram",
"disableOsm",
"alwaysProxy",
"onlyEmbeddedVideo",
"videoQuality",
"invidiousDarkMode",
"invidiousVolume",
"invidiousPlayerStyle",
"invidiousSubtitles",
"invidiousAutoplay",
"exceptions",
],
result => {
(result) => {
disableNitter = result.disableNitter;
disableInvidious = result.disableInvidious;
disableBibliogram = result.disableBibliogram;
disableOsm = result.disableOsm;
nitterInstance = result.nitterInstance || nitterDefault;
invidiousInstance = result.invidiousInstance || invidiousDefault;
bibliogramInstance = result.bibliogramInstance || bibliogramDefault;
nitterInstance = result.nitterInstance;
invidiousInstance = result.invidiousInstance;
bibliogramInstance = result.bibliogramInstance;
osmInstance = result.osmInstance || osmDefault;
alwaysProxy = result.alwaysProxy;
onlyEmbeddedVideo = result.onlyEmbeddedVideo;
videoQuality = result.videoQuality;
invidiousDarkMode = result.invidiousDarkMode;
whitelist = result.whitelist ? result.whitelist.map(e => new RegExp(e)) : [];
exceptions = result.exceptions
? result.exceptions.map((e) => {
return new RegExp(e);
})
: [];
invidiousVolume = result.invidiousVolume;
invidiousPlayerStyle = result.invidiousPlayerStyle;
invidiousSubtitles = result.invidiousSubtitles || "";
invidiousAutoplay = result.invidiousAutoplay;
}
);
browser.storage.onChanged.addListener(changes => {
if ('nitterInstance' in changes) {
nitterInstance = changes.nitterInstance.newValue || nitterDefault;
browser.storage.onChanged.addListener((changes) => {
if ("nitterInstance" in changes) {
nitterInstance = changes.nitterInstance.newValue;
}
if ('invidiousInstance' in changes) {
invidiousInstance = changes.invidiousInstance.newValue || invidiousDefault;
if ("invidiousInstance" in changes) {
invidiousInstance = changes.invidiousInstance.newValue;
}
if ('bibliogramInstance' in changes) {
bibliogramInstance = changes.bibliogramInstance.newValue || bibliogramDefault;
if ("bibliogramInstance" in changes) {
bibliogramInstance = changes.bibliogramInstance.newValue;
}
if ('osmInstance' in changes) {
if ("osmInstance" in changes) {
osmInstance = changes.osmInstance.newValue || osmDefault;
}
if ('disableNitter' in changes) {
if ("disableNitter" in changes) {
disableNitter = changes.disableNitter.newValue;
}
if ('disableInvidious' in changes) {
if ("disableInvidious" in changes) {
disableInvidious = changes.disableInvidious.newValue;
}
if ('disableBibliogram' in changes) {
if ("disableBibliogram" in changes) {
disableBibliogram = changes.disableBibliogram.newValue;
}
if ('disableOsm' in changes) {
if ("disableOsm" in changes) {
disableOsm = changes.disableOsm.newValue;
}
if ('alwaysProxy' in changes) {
if ("alwaysProxy" in changes) {
alwaysProxy = changes.alwaysProxy.newValue;
}
if ('onlyEmbeddedVideo' in changes) {
if ("onlyEmbeddedVideo" in changes) {
onlyEmbeddedVideo = changes.onlyEmbeddedVideo.newValue;
}
if ('videoQuality' in changes) {
if ("videoQuality" in changes) {
videoQuality = changes.videoQuality.newValue;
}
if ('invidiousDarkMode' in changes) {
if ("invidiousDarkMode" in changes) {
invidiousDarkMode = changes.invidiousDarkMode.newValue;
}
if ('whitelist' in changes) {
whitelist = changes.whitelist.newValue.map(e => new RegExp(e));
if ("invidiousVolume" in changes) {
invidiousVolume = changes.invidiousVolume.newValue;
}
if ("invidiousPlayerStyle" in changes) {
invidiousPlayerStyle = changes.invidiousPlayerStyle.newValue;
}
if ("invidiousSubtitles" in changes) {
invidiousSubtitles = changes.invidiousSubtitles.newValue;
}
if ("invidiousAutoplay" in changes) {
invidiousAutoplay = changes.invidiousAutoplay.newValue;
}
if ("exceptions" in changes) {
exceptions = changes.exceptions.newValue.map((e) => {
return new RegExp(e);
});
}
});
function getRandomInstance(instanceList) {
return instanceList[~~(instanceList.length * Math.random())];
}
function addressToLatLng(address, callback) {
const xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = () => {
@ -175,120 +238,181 @@ function addressToLatLng(address, callback) {
`${json.boundingbox[2]},${json.boundingbox[1]},${json.boundingbox[3]},${json.boundingbox[0]}`
);
}
}
else {
} else {
console.info("Error: Status is " + xmlhttp.status);
}
}
};
xmlhttp.open(
'GET',
"GET",
`https://nominatim.openstreetmap.org/search/${address}?format=json&limit=1`,
false
);
xmlhttp.send();
}
function isWhitelisted(initiator) {
return initiator && whitelist.some(regex => (regex.test(initiator.href)));
function isException(url, initiator) {
return (
exceptions.some((regex) => regex.test(url.href)) ||
(initiator && exceptions.some((regex) => regex.test(initiator.href)))
);
}
function isFirefox() {
return typeof InstallTrigger !== "undefined";
}
function redirectYouTube(url, initiator, type) {
if (disableInvidious || isWhitelisted(initiator)) {
if (disableInvidious || isException(url, initiator)) {
return null;
}
if (initiator && (initiator.origin === invidiousInstance || youtubeDomains.includes(initiator.host))) {
if (
initiator &&
(initiator.origin === invidiousInstance ||
invidiousInstances.includes(initiator.origin) ||
youtubeDomains.includes(initiator.host))
) {
return null;
}
if (url.pathname.match(/iframe_api/)) {
// Redirect requests for YouTube Player API to local files instead
return browser.runtime.getURL('assets/iframe_api.js');
} else if (url.pathname.match(/www-widgetapi/)) {
// Redirect requests for YouTube Player API to local files instead
return browser.runtime.getURL('assets/www-widgetapi.js');
} else {
// Proxy video through the server if enabled by user
if (alwaysProxy) {
url.searchParams.append('local', true);
}
if (videoQuality) {
url.searchParams.append('quality', videoQuality);
}
if (onlyEmbeddedVideo && type !== 'sub_frame') {
return null;
}
if (invidiousDarkMode) {
url.searchParams.append('dark_mode', invidiousDarkMode);
}
return `${invidiousInstance}${url.pathname}${url.search}`;
if (url.pathname.match(/iframe_api/) || url.pathname.match(/www-widgetapi/)) {
// Don't redirect YouTube Player API.
return null;
}
if (url.host.split(".")[0] === "studio") {
// Avoid redirecting `studio.youtube.com`
return null;
}
if (onlyEmbeddedVideo && type !== "sub_frame") {
return null;
}
// Apply settings
if (alwaysProxy) {
url.searchParams.append("local", true);
}
if (videoQuality) {
url.searchParams.append("quality", videoQuality);
}
if (invidiousDarkMode) {
url.searchParams.append("dark_mode", invidiousDarkMode);
}
if (invidiousVolume) {
url.searchParams.append("volume", invidiousVolume);
}
if (invidiousPlayerStyle) {
url.searchParams.append("player_style", invidiousPlayerStyle);
}
if (invidiousSubtitles) {
url.searchParams.append("subtitles", invidiousSubtitles);
}
url.searchParams.append("autoplay", invidiousAutoplay ? 1 : 0);
return `${invidiousInstance || getRandomInstance(invidiousInstances)}${
url.pathname
}${url.search}`;
}
function redirectTwitter(url, initiator) {
if (disableNitter || isWhitelisted(initiator)) {
if (disableNitter || isException(url, initiator)) {
return null;
}
if (url.host.split('.')[0] === 'pbs') {
return `${nitterInstance}/pic/${encodeURIComponent(url.href)}`;
} else if (url.host.split('.')[0] === 'video') {
return `${nitterInstance}/gif/${encodeURIComponent(url.href)}`;
} else if (url.pathname.includes('tweets')) {
return `${nitterInstance}${url.pathname.replace('/tweets', '')}${url.search}`;
if (url.pathname.includes("/home")) {
return null;
}
if (
isFirefox() &&
initiator &&
(initiator.origin === nitterInstance ||
nitterInstances.includes(initiator.origin) ||
twitterDomains.includes(initiator.host))
) {
browser.storage.sync.set({
redirectBypassFlag: true,
});
return null;
}
if (url.host.split(".")[0] === "pbs") {
return `${
nitterInstance || getRandomInstance(nitterInstances)
}/pic/${encodeURIComponent(url.href)}`;
} else if (url.host.split(".")[0] === "video") {
return `${
nitterInstance || getRandomInstance(nitterInstances)
}/gif/${encodeURIComponent(url.href)}`;
} else if (url.pathname.includes("tweets")) {
return `${
nitterInstance || getRandomInstance(nitterInstances)
}${url.pathname.replace("/tweets", "")}${url.search}`;
} else {
return `${nitterInstance}${url.pathname}${url.search}`;
return `${nitterInstance || getRandomInstance(nitterInstances)}${
url.pathname
}${url.search}`;
}
}
function redirectInstagram(url, initiator, type) {
if (disableBibliogram || isWhitelisted(initiator)) {
if (disableBibliogram || isException(url, initiator)) {
return null;
}
// Do not redirect Bibliogram view on Instagram links
if (initiator && (initiator.origin === bibliogramInstance || instagramDomains.includes(initiator.host))) {
if (
initiator &&
(initiator.origin === bibliogramInstance ||
bibliogramInstances.includes(initiator.origin) ||
instagramDomains.includes(initiator.host))
) {
return null;
}
// Do not redirect /accounts, /embeds.js, or anything other than main_frame
if (type !== 'main_frame' || url.pathname.match(bibliogramBypassPaths)) {
if (type !== "main_frame" || url.pathname.match(bibliogramBypassPaths)) {
return null;
}
if (url.pathname === '/' || instagramReservedPaths.includes(url.pathname.split('/')[1])) {
return `${bibliogramInstance}${url.pathname}${url.search}`;
if (
url.pathname === "/" ||
instagramReservedPaths.includes(url.pathname.split("/")[1])
) {
return `${bibliogramInstance || getRandomInstance(bibliogramInstances)}${
url.pathname
}${url.search}`;
} else {
// Likely a user profile, redirect to '/u/...'
return `${bibliogramInstance}/u${url.pathname}${url.search}`;
return `${bibliogramInstance || getRandomInstance(bibliogramInstances)}/u${
url.pathname
}${url.search}`;
}
}
function redirectGoogleMaps(url, initiator) {
if (disableOsm || isWhitelisted(initiator)) {
if (disableOsm || isException(url, initiator)) {
return null;
}
let redirect;
let mapCentre = '';
let params = '';
let mapCentre = "";
let params = "";
// Set map centre if present
if (url.pathname.match(mapCentreRegex)) {
const [, lat, lon, zoom] = url.pathname.match(mapCentreRegex);
mapCentre = `#map=${zoom}/${lat}/${lon}`;
} else if (url.search.includes('center=')) {
const [lat, lon] = url.searchParams.get('center').split(',');
mapCentre = `#map=${url.searchParams.get('zoom') || '17'}/${lat}/${lon}`;
} else if (url.search.includes("center=")) {
const [lat, lon] = url.searchParams.get("center").split(",");
mapCentre = `#map=${url.searchParams.get("zoom") || "17"}/${lat}/${lon}`;
// Set default zoom if mapCentre not present
} else {
params = '&zoom=17';
params = "&zoom=17";
}
// Set map layer
params = `${params}&layers=${layers[url.searchParams.get('layer')] || layers['none']}`;
params = `${params}&layers=${
layers[url.searchParams.get("layer")] || layers["none"]
}`;
// Handle Google Maps Embed API
if (url.pathname.includes('/embed')) {
let query = '';
if (url.searchParams.has('q')) {
query = url.searchParams.get('q');
} else if (url.searchParams.has('query')) {
query = url.searchParams.has('query');
} else if (url.searchParams.has('pb')) {
if (url.pathname.includes("/embed")) {
let query = "";
if (url.searchParams.has("q")) {
query = url.searchParams.get("q");
} else if (url.searchParams.has("query")) {
query = url.searchParams.has("query");
} else if (url.searchParams.has("pb")) {
try {
query = url.searchParams.get('pb').split(/!2s(.*?)!/)[1];
query = url.searchParams.get("pb").split(/!2s(.*?)!/)[1];
} catch (error) {
console.error(error);
// Unable to find map marker in URL.
@ -301,92 +425,118 @@ function redirectGoogleMaps(url, initiator) {
});
redirect = `${osmInstance}/export/embed.html?bbox=${bbox}&layer=mapnik&marker=${marker}`;
// Handle Google Maps Directions
} else if (url.pathname.includes('/dir')) {
const travelMode = travelModes[url.searchParams.get('travelmode')] || travelModes['driving'];
} else if (url.pathname.includes("/dir")) {
const travelMode =
travelModes[url.searchParams.get("travelmode")] || travelModes["driving"];
let origin;
addressToLatLng(url.searchParams.get('origin'), coords => {
addressToLatLng(url.searchParams.get("origin"), (coords) => {
origin = coords;
});
let destination;
addressToLatLng(url.searchParams.get('destination'), coords => {
addressToLatLng(url.searchParams.get("destination"), (coords) => {
destination = coords;
});
redirect = `${osmInstance}/directions?engine=${travelMode}&route=${origin}%3B${destination}${mapCentre}${params}`;
// Get marker from data attribute
} else if (url.pathname.includes('data=') && url.pathname.match(dataLatLngRegex)) {
} else if (
url.pathname.includes("data=") &&
url.pathname.match(dataLatLngRegex)
) {
const [mlat, mlon] = url.pathname.match(dataLatLngRegex);
redirect = `${osmInstance}/?mlat=${mlat.replace('!3d', '')}&mlon=${mlon.replace('!4d', '')}${mapCentre}${params}`;
redirect = `${osmInstance}/?mlat=${mlat.replace(
"!3d",
""
)}&mlon=${mlon.replace("!4d", "")}${mapCentre}${params}`;
// Get marker from ll param
} else if (url.searchParams.has('ll')) {
const [mlat, mlon] = url.searchParams.get('ll').split(',');
} else if (url.searchParams.has("ll")) {
const [mlat, mlon] = url.searchParams.get("ll").split(",");
redirect = `${osmInstance}/?mlat=${mlat}&mlon=${mlon}${mapCentre}${params}`;
// Get marker from viewpoint param.
} else if (url.searchParams.has('viewpoint')) {
const [mlat, mlon] = url.searchParams.get('viewpoint').split(',');
} else if (url.searchParams.has("viewpoint")) {
const [mlat, mlon] = url.searchParams.get("viewpoint").split(",");
redirect = `${osmInstance}/?mlat=${mlat}&mlon=${mlon}${mapCentre}${params}`;
// Use query as search if present.
} else {
let query;
if (url.searchParams.has('q')) {
query = url.searchParams.get('q');
} else if (url.searchParams.has('query')) {
query = url.searchParams.get('query');
if (url.searchParams.has("q")) {
query = url.searchParams.get("q");
} else if (url.searchParams.has("query")) {
query = url.searchParams.get("query");
} else if (url.pathname.match(placeRegex)) {
query = url.pathname.match(placeRegex)[1];
}
redirect = `${osmInstance}/${query ? 'search?query=' + query : ''}${mapCentre || '#'}${params}`;
redirect = `${osmInstance}/${query ? "search?query=" + query : ""}${
mapCentre || "#"
}${params}`;
}
return redirect;
}
browser.webRequest.onBeforeRequest.addListener(
details => {
(details) => {
const url = new URL(details.url);
let initiator;
if (details.initiator) {
initiator = new URL(details.initiator);
} else if (details.originUrl) {
if (details.originUrl) {
initiator = new URL(details.originUrl);
} else if (details.initiator) {
initiator = new URL(details.initiator);
}
let redirect;
if (youtubeDomains.includes(url.host)) {
redirect = {
redirectUrl: redirectYouTube(url, initiator, details.type)
redirectUrl: redirectYouTube(url, initiator, details.type),
};
} else if (twitterDomains.includes(url.host)) {
redirect = {
redirectUrl: redirectTwitter(url, initiator)
redirectUrl: redirectTwitter(url, initiator),
};
} else if (instagramDomains.includes(url.host)) {
redirect = {
redirectUrl: redirectInstagram(url, initiator, details.type)
redirectUrl: redirectInstagram(url, initiator, details.type),
};
} else if (url.href.match(googleMapsRegex)) {
redirect = {
redirectUrl: redirectGoogleMaps(url, initiator)
redirectUrl: redirectGoogleMaps(url, initiator),
};
}
if (redirect && redirect.redirectUrl) {
console.info(
'Redirecting', `"${url.href}"`, '=>', `"${redirect.redirectUrl}"`
"Redirecting",
`"${url.href}"`,
"=>",
`"${redirect.redirectUrl}"`
);
console.info('Details', details);
console.info("Details", details);
}
return redirect;
},
{
urls: ["<all_urls>"]
urls: ["<all_urls>"],
},
['blocking']
["blocking"]
);
browser.runtime.onInstalled.addListener(
details => {
if (details.reason === 'install') {
browser.storage.sync.set({
bibliogramInstance: bibliogramInstances[~~(bibliogramInstances.length * Math.random())]
});
}
browser.runtime.onInstalled.addListener((details) => {
if (details.reason === "update") {
browser.storage.sync.get(
["whitelist", "exceptions", "invidiousInstance"],
(result) => {
if (result.whitelist) {
let whitelist = result.whitelist.map((e) =>
e.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&")
);
browser.storage.sync.set({
exceptions: result.exceptions.concat(whitelist),
whitelist: null,
});
}
if (result.invidiousInstance === "https://invidio.us") {
browser.storage.sync.set({
invidiousInstance: null,
});
}
}
);
}
);
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 814 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

View File

@ -1,34 +1,28 @@
{
"name": "Privacy Redirect",
"description": "Redirects Twitter, YouTube, Instagram & Google Maps requests to privacy friendly alternatives.",
"version": "1.1.29",
"name": "__MSG_extensionName__",
"description": "__MSG_extensionDescription__",
"version": "1.1.41",
"manifest_version": 2,
"background": {
"scripts": [
"background.js"
],
"scripts": ["background.js"],
"persistent": true
},
"default_locale": "en",
"icons": {
"16": "images/icon16.png",
"32": "images/icon32.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
"16": "assets/images/icon16.png",
"32": "assets/images/icon32.png",
"48": "assets/images/icon48.png",
"128": "assets/images/icon128.png"
},
"permissions": [
"storage",
"webRequest",
"webRequestBlocking",
"<all_urls>"
],
"permissions": ["storage", "webRequest", "webRequestBlocking", "<all_urls>"],
"browser_action": {
"default_title": "Privacy Redirect",
"default_popup": "pages/popup/popup.html",
"default_icon": {
"16": "images/icon16.png",
"32": "images/icon32.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
"16": "assets/images/icon16.png",
"32": "assets/images/icon32.png",
"48": "assets/images/icon48.png",
"128": "assets/images/icon128.png"
}
},
"content_scripts": [
@ -40,32 +34,32 @@
"*://pbs.twimg.com/*",
"*://video.twimg.com/*"
],
"js": [
"assets/remove-twitter-sw.js"
],
"js": ["assets/javascript/remove-twitter-sw.js"],
"run_at": "document_start"
},
{
"matches": [
"*://invidio.us/*",
"*://invidio.us/*",
"*://invidious.snopyta.org/*",
"*://invidiou.sh/*",
"*://yewtu.be/*",
"*://yt.maisputain.ovh/*",
"*://invidious.toot.koeln/*",
"*://invidious.xyz/*",
"*://invidious.site/*",
"*://invidiou.site/*",
"*://invidious.ggc-project.de/*",
"*://invidious.13ad.de/*",
"*://invidious.toot.koeln/*",
"*://invidious.fdn.fr/*",
"*://watch.nettohikari.com/*",
"*://yt.iswleuven.be/*",
"*://yt.maisputain.ovh/*",
"*://kgg2m7yk5aybusll.onion/*",
"*://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion/*",
"*://fz253lmuao3strwbfbmx46yu7acac2jz27iwtorgmbqlkurlclmancad.onion/*",
"*://qklhadlycap4cnod.onion/*",
"*://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion/*",
"*://mfqczy4mysscub2s.onio/*n"
],
"js": [
"assets/persist-invidious-prefs.js"
"*://mfqczy4mysscub2s.onion/*",
"*://4l2dgddgsrkf2ous66i6seeyi6etzfgrue332grh2n7madpwopotugyd.onion/*"
],
"js": ["assets/javascript/persist-invidious-prefs.js"],
"run_at": "document_start"
}
],
@ -73,13 +67,9 @@
"page": "pages/options/options.html",
"open_in_tab": false
},
"web_accessible_resources": [
"assets/iframe_api.js",
"assets/www-widgetapi.js"
],
"browser_specific_settings": {
"gecko": {
"id": "{b7f9d2cd-d772-4302-8c3f-eb941af36f76}"
}
}
}
}

View File

@ -1,183 +1,448 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title></title>
<link href="../styles.css" rel="stylesheet" />
<title>Privacy Redirect Options</title>
</head>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link href="../styles.css" rel="stylesheet">
<title>Privacy Redirect Options</title>
</head>
<body>
<div class="tab">
<button
class="tablinks"
id="general-tab"
data-localise="__MSG_generalTab__"
>
General
</button>
<button
class="tablinks"
id="advanced-tab"
data-localise="__MSG_advancedTab__"
>
Advanced
</button>
<button
class="tablinks"
id="exceptions-tab"
data-localise="__MSG_exceptionsTab__"
>
Exceptions
</button>
</div>
<body>
<div id="general" class="tabcontent">
<section class="settings-block">
<table class="option" aria-label="Toggle Nitter redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableNitter__">Nitter Redirects</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-nitter"
type="checkbox"
checked
/>&nbsp;
<label for="disable-nitter" class="checkbox-label"></label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<table class="option" aria-label="Toggle Invidious redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableInvidious__">
Invidious Redirects
</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-invidious"
type="checkbox"
checked
/>&nbsp;
<label for="disable-invidious" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<table class="option" aria-label="Toggle Bibliogram redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableBibliogram__">
Bibliogram Redirects
</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-bibliogram"
type="checkbox"
checked
/>&nbsp;
<label for="disable-bibliogram" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<table class="option" aria-label="Toggle OpenStreetMap redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableOsm__">
OpenStreetMap Redirects
</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-osm"
type="checkbox"
checked
/>&nbsp;
<label for="disable-osm" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_nitterInstance__">Nitter Instance</h1>
<div class="autocomplete">
<input
id="nitter-instance"
type="url"
name="nitter-instance"
placeholder="Random instance (none selected)"
/>
</div>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_invidiousInstance__">Invidious Instance</h1>
<div class="autocomplete">
<input
id="invidious-instance"
type="url"
placeholder="Random instance (none selected)"
/>
</div>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_bibliogramInstance__">Bibliogram Instance</h1>
<div class="autocomplete">
<input
id="bibliogram-instance"
type="url"
placeholder="Random instance (none selected)"
/>
</div>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_osmInstance__">OpenStreetMap Instance</h1>
<div class="autocomplete">
<input
id="osm-instance"
type="url"
placeholder="https://openstreetmap.org"
/>
</div>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_theme__">Theme</h1>
<select id="theme">
<option value="">System</option>
<option value="light-theme">Light</option>
<option value="dark-theme">Dark</option>
</select>
</section>
</div>
<div class="tab">
<button class="tablinks" id="general-tab">General</button>
<button class="tablinks" id="advanced-tab">Advanced</button>
<button class="tablinks" id="whitelist-tab">Whitelist</button>
</div>
<div id="advanced" class="tabcontent">
<section class="settings-block">
<table
class="option"
aria-label="Always proxy videos through Invidious"
>
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_alwaysProxy__">
Always proxy videos through Invidious
</h1>
</td>
<td>
<input
aria-hidden="true"
id="always-proxy"
type="checkbox"
checked
/>&nbsp;
<label for="always-proxy" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<table
class="option"
aria-label="Only redirect embedded video to Invidious"
>
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_onlyEmbeddedVideo__">
Only redirect embedded video to Invidious
</h1>
</td>
<td>
<input
aria-hidden="true"
id="only-embed"
type="checkbox"
checked
/>&nbsp;
<label for="only-embed" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_videoQuality__">Invidious Video Quality</h1>
<select id="video-quality">
<option value="">Default</option>
<option value="hd720">720p</option>
<option value="medium">480p</option>
<option value="dash">DASH (Dynamic Adaptive Streaming over HTTP)</option>
</option>
</select>
</section>
<section class="settings-block">
<table class="option" aria-label="Invidious dark mode aways on">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_invidiousDarkMode__">
Invidious dark mode always on
</h1>
</td>
<td>
<input
aria-hidden="true"
id="invidious-dark-mode"
type="checkbox"
checked
/>&nbsp;
<label for="invidious-dark-mode" class="checkbox-label">
</label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_invidiousVolume__">
Invidious Volume
</h1>
<input
id="invidious-volume"
name="invidious-volume"
type="range"
min="0"
max="100"
step="1"
/><span id="volume-value"></span>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_invidiousPlayerStyle__">
Invidious Player Style
</h1>
<select id="invidious-player-style">
<option value="">Invidious</option>
<option value="youtube">YouTube</option>
</select>
</section>
<section class="settings-block">
<h1 data-localise="__MSG_invidiousSubtitles__">
Invidious Subtitles - language codes (comma-separated)
</h1>
<input
id="invidious-subtitles"
name="invidious-subtitles"
type="text"
/>
</section>
<section class="settings-block">
<table
class="option"
aria-label="Invidious automatically play video on load"
>
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_invidiousAutoplay__">
Invidious automatically play video on load
</h1>
</td>
<td>
<input
aria-hidden="true"
id="invidious-autoplay"
type="checkbox"
checked
/>&nbsp;
<label for="invidious-autoplay" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<table class="option" aria-label="Persist Invidious preferences">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_persistInvidiousPrefs__">
Persist Invidious preferences (as cookie)
</h1>
</td>
<td>
<input
aria-hidden="true"
id="persist-invidious-prefs"
type="checkbox"
checked
/>&nbsp;
<label for="persist-invidious-prefs" class="checkbox-label">
</label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="settings-block">
<table
class="option"
aria-label="Proactively remove Twitter service worker"
>
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_removeTwitterSW__">
Proactively remove Twitter service worker
</h1>
</td>
<td>
<input
aria-hidden="true"
id="remove-twitter-sw"
type="checkbox"
checked
/>&nbsp;
<label for="remove-twitter-sw" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
</div>
<div id="general" class="tabcontent">
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle Nitter redirects">
<h1>Nitter Redirects</h1>
<input aria-hidden="true" id="disable-nitter" type="checkbox" checked>&nbsp;
<label for="disable-nitter" class="checkbox-label">
</label>
</div>
</section>
<div id="exceptions" class="tabcontent">
<section class="settings-block">
<p data-localise="__MSG_exceptionsDescriptionP1__">
Enter a URL or Regular Expression to be excluded from redirects.
</p>
<p data-localise="__MSG_exceptionsDescriptionP2__">
All requests for or initiating from a URL that matches your exception
will be excluded from redirects.
</p>
<p data-localise="__MSG_exceptionsDescriptionP3__">
Note - Supports JavaScript regular expressions, excluding the
enclosing forward slashes.
</p>
</section>
<section class="settings-block">
<table class="exceptions option">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_addException__">Add Exception</h1>
</td>
</tr>
<tr>
<td>
<input
id="new-exceptions-item"
type="text"
placeholder="URL or RegExp"
/>
</td>
<td>
<input type="radio" id="url" name="type" value="URL" checked />
<label class="radio" for="url">URL</label>
<input type="radio" id="regExp" name="type" value="RegExp" />
<label class="radio" for="regExp">RegExp</label>
</td>
<td>
<button id="add-to-exceptions">
<svg
xmlns="http://www.w3.org/2000/svg"
width="512"
height="512"
viewBox="0 0 512 512"
>
<line
x1="256"
y1="112"
x2="256"
y2="400"
style="
fill: none;
stroke: #fff;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 32px;
"
/>
<line
x1="400"
y1="256"
x2="112"
y2="256"
style="
fill: none;
stroke: #fff;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 32px;
"
/>
</svg>
</button>
</td>
</tr>
</tbody>
</table>
</section>
<ul id="exceptions-items"></ul>
</div>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle Invidious redirects">
<h1>Invidious Redirects</h1>
<input aria-hidden="true" id="disable-invidious" type="checkbox" checked>&nbsp;
<label for="disable-invidious" class="checkbox-label">
</label>
</div>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle Bibliogram redirects">
<h1>Bibliogram Redirects</h1>
<input aria-hidden="true" id="disable-bibliogram" type="checkbox" checked>&nbsp;
<label for="disable-bibliogram" class="checkbox-label">
</label>
</div>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle OpenStreetMap redirects">
<h1>OpenStreetMap Redirects</h1>
<input aria-hidden="true" id="disable-osm" type="checkbox" checked>&nbsp;
<label for="disable-osm" class="checkbox-label">
</label>
</div>
</section>
<section class="options settings_block">
<h1>Nitter Instance</h1>
<input id="nitter-instance" list="nitter-instance-list" type="url" placeholder="https://nitter.net">
<datalist id="nitter-instance-list">
<option value="https://nitter.net">
<option value="https://nitter.snopyta.org">
<option value="https://nitter.42l.fr">
<option value="https://nitter.nixnet.xyz">
<option value="https://nitter.13ad.de">
<option value="https://tw.openalgeria.org">
<option value="https://nitter.pussthecat.org">
<option value="https://nitter.mastodont.cat">
<option value="https://nitter.dark.fail">
<option value="https://nitter.tedomum.net">
<option value="https://t.maisputain.ovh">
<option value="http://3nzoldnxplag42gqjs23xvghtzf6t6yzssrtytnntc6ppc7xxuoneoad.onion">
<option value="http://nitter.l4qlywnpwqsluw65ts7md3khrivpirse744un3x7mlskqauz5pyuzgqd.onion">
<option value="http://3nzoldnxplag42gqjs23xvghtzf6t6yzssrtytnntc6ppc7xxuoneoad.onion">
</datalist>
<h1>Invidious Instance</h1>
<input id="invidious-instance" list="invidious-instances-list" type="url" placeholder="https://invidio.us">
<datalist id="invidious-instances-list">
<option value="https://invidio.us">
<option value="https://invidious.snopyta.org">
<option value="https://invidiou.sh">
<option value="https://yewtu.be">
<option value="https://yt.maisputain.ovh">
<option value="https://invidious.toot.koeln">
<option value="https://invidious.ggc-project.de">
<option value="https://invidious.toot.koeln">
<option value="http://kgg2m7yk5aybusll.onion">
<option value="http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion">
<option value="http://fz253lmuao3strwbfbmx46yu7acac2jz27iwtorgmbqlkurlclmancad.onion">
<option value="http://qklhadlycap4cnod.onion">
<option value="http://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion">
<option value="http://mfqczy4mysscub2s.onion">
</datalist>
<h1>Bibliogram Instance</h1>
<input id="bibliogram-instance" list="bibliogram-instance-list" type="url" placeholder="https://bibliogram.art">
<datalist id="bibliogram-instance-list">
<option value="https://bibliogram.art">
<option value="https://bibliogram.snopyta.org">
<option value="https://bibliogram.pussthecat.org">
<option value="https://insta.maisputain.ovh">
<option value="https://bibliogram.nixnet.services">
</datalist>
<h1>OpenStreetMap Instance</h1>
<input id="osm-instance" list="osm-instance-list" type="url" placeholder="https://openstreetmap.org">
<datalist id="osm-instance-list">
<option value="https://openstreetmap.org">
</datalist>
</section>
</div>
<div id="advanced" class="tabcontent">
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Always proxy videos through Invidious">
<h1>Always proxy videos through Invidious</h1>
<input aria-hidden="true" id="always-proxy" type="checkbox" checked>&nbsp;
<label for="always-proxy" class="checkbox-label">
</label>
</div>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Only redirect embedded video to Invidious">
<h1>Only redirect embedded video to Invidious</h1>
<input aria-hidden="true" id="only-embed" type="checkbox" checked>&nbsp;
<label for="only-embed" class="checkbox-label">
</label>
</div>
</section>
<section class="options settings_block">
<h1>Invidious Video Quality</h1>
<select id="video-quality">
<option value="">Default</option>
<option value="hd720">720p</option>
<option value="medium">480p</option>
<option value="dash">DASH (Dynamic Adaptive Streaming over HTTP)</option>
</select>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Invidious dark mode aways on">
<h1>Invidious dark mode always on</h1>
<input aria-hidden="true" id="invidious-dark-mode" type="checkbox" checked>&nbsp;
<label for="invidious-dark-mode" class="checkbox-label">
</label>
</div>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Persist Invidious preferences">
<h1>Persist Invidious preferences (as cookie)</h1>
<input aria-hidden="true" id="persist-invidious-prefs" type="checkbox" checked>&nbsp;
<label for="persist-invidious-prefs" class="checkbox-label">
</label>
</div>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Proactively remove Twitter service worker">
<h1>Proactively remove Twitter service worker</h1>
<input aria-hidden="true" id="remove-twitter-sw" type="checkbox" checked>&nbsp;
<label for="remove-twitter-sw" class="checkbox-label">
</label>
</div>
</section>
</div>
<div id="whitelist" class="tabcontent">
<section class="options settings_block">
<h1>Whitelisted Sites</h1>
<div class="whitelist">
<input id="new-whitelist-item" type="text" placeholder="URL (RegExp accepted)">
<button id="add-to-whitelist">Add to Whitelist</button>
</div>
</section>
<ul id="whitelist-items"></ul>
</div>
<script src="./options.js"></script>
</body>
</html>
<script src="./options.js"></script>
<script src="../../assets/javascript/localise.js"></script>
</body>
</html>

View File

@ -1,130 +1,213 @@
'use strict';
"use strict";
let nitterInstance = document.getElementById('nitter-instance');
let invidiousInstance = document.getElementById('invidious-instance');
let bibliogramInstance = document.getElementById('bibliogram-instance');
let osmInstance = document.getElementById('osm-instance');
let disableNitter = document.getElementById('disable-nitter');
let disableInvidious = document.getElementById('disable-invidious');
let disableBibliogram = document.getElementById('disable-bibliogram');
let disableOsm = document.getElementById('disable-osm');
let alwaysProxy = document.getElementById('always-proxy');
let onlyEmbeddedVideo = document.getElementById('only-embed');
let videoQuality = document.getElementById('video-quality');
let removeTwitterSW = document.getElementById('remove-twitter-sw');
let invidiousDarkMode = document.getElementById('invidious-dark-mode');
let persistInvidiousPrefs = document.getElementById('persist-invidious-prefs');
let whitelist;
const nitterInstances = [
"https://nitter.net",
"https://nitter.snopyta.org",
"https://nitter.42l.fr",
"https://nitter.nixnet.services",
"https://nitter.13ad.de",
"https://nitter.pussthecat.org",
"https://nitter.mastodont.cat",
"https://nitter.dark.fail",
"https://nitter.tedomum.net",
"https://t.maisputain.ovh",
"http://3nzoldnxplag42gqjs23xvghtzf6t6yzssrtytnntc6ppc7xxuoneoad.onion",
"http://nitter.l4qlywnpwqsluw65ts7md3khrivpirse744un3x7mlskqauz5pyuzgqd.onion",
];
const invidiousInstances = [
"https://invidious.snopyta.org",
"https://yewtu.be",
"https://invidious.ggc-project.de",
"https://invidious.13ad.de",
"https://invidious.xyz",
"https://invidious.toot.koeln",
"https://invidious.site",
"https://invidiou.site",
"https://invidious.fdn.fr",
"https://watch.nettohikari.com",
"https://yt.iswleuven.be",
"https://yt.maisputain.ovh",
"http://kgg2m7yk5aybusll.onion",
"http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion",
"http://fz253lmuao3strwbfbmx46yu7acac2jz27iwtorgmbqlkurlclmancad.onion",
"http://qklhadlycap4cnod.onion",
"http://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion",
"http://mfqczy4mysscub2s.onion",
"http://4l2dgddgsrkf2ous66i6seeyi6etzfgrue332grh2n7madpwopotugyd.onion",
];
const bibliogramInstances = [
"https://bibliogram.art",
"https://bibliogram.snopyta.org",
"https://bibliogram.pussthecat.org",
"https://bibliogram.nixnet.services",
"https://bibliogram.hamster.dance",
"https://insta.maisputain.ovh",
"https://bibliogram.ggc-project.de",
];
const osmInstances = ["https://openstreetmap.org"];
const autocompletes = [
{ id: "nitter-instance", instances: nitterInstances },
{ id: "invidious-instance", instances: invidiousInstances },
{ id: "bibliogram-instance", instances: bibliogramInstances },
{ id: "osm-instance", instances: osmInstances },
];
let nitterInstance = document.getElementById("nitter-instance");
let invidiousInstance = document.getElementById("invidious-instance");
let bibliogramInstance = document.getElementById("bibliogram-instance");
let osmInstance = document.getElementById("osm-instance");
let disableNitter = document.getElementById("disable-nitter");
let disableInvidious = document.getElementById("disable-invidious");
let disableBibliogram = document.getElementById("disable-bibliogram");
let disableOsm = document.getElementById("disable-osm");
let alwaysProxy = document.getElementById("always-proxy");
let onlyEmbeddedVideo = document.getElementById("only-embed");
let videoQuality = document.getElementById("video-quality");
let removeTwitterSW = document.getElementById("remove-twitter-sw");
let invidiousDarkMode = document.getElementById("invidious-dark-mode");
let persistInvidiousPrefs = document.getElementById("persist-invidious-prefs");
let invidiousVolume = document.getElementById("invidious-volume");
let invidiousPlayerStyle = document.getElementById("invidious-player-style");
let invidiousSubtitles = document.getElementById("invidious-subtitles");
let invidiousAutoplay = document.getElementById("invidious-autoplay");
let theme = document.getElementById("theme");
let exceptions;
window.browser = window.browser || window.chrome;
function prependWhitelistItem(item, index) {
const li = document.createElement('li');
function prependExceptionsItem(item, index) {
const li = document.createElement("li");
li.appendChild(document.createTextNode(item.toString()));
const button = document.createElement('button');
button.appendChild(document.createTextNode('X'));
button.addEventListener('click', () => {
li.remove();
whitelist.splice(index, 1);
browser.storage.sync.set({
whitelist: whitelist
});
});
const button = document.createElement("button");
li.appendChild(button);
document.getElementById('whitelist-items').prepend(li);
document.getElementById("exceptions-items").prepend(li);
const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 512 512'>
<line x1='368' y1='368' x2='144' y2='144'
style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px' />
<line x1='368' y1='144' x2='144' y2='368'
style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px' />
</svg>`;
button.innerHTML = svg;
button.addEventListener("click", () => {
exceptions.splice(index, 1);
browser.storage.sync.set({
exceptions: exceptions,
});
li.remove();
});
}
browser.storage.sync.get(
[
'nitterInstance',
'invidiousInstance',
'bibliogramInstance',
'osmInstance',
'disableNitter',
'disableInvidious',
'disableBibliogram',
'disableOsm',
'alwaysProxy',
'onlyEmbeddedVideo',
'videoQuality',
'removeTwitterSW',
'whitelist',
'invidiousDarkMode',
'persistInvidiousPrefs'
"nitterInstance",
"invidiousInstance",
"bibliogramInstance",
"osmInstance",
"disableNitter",
"disableInvidious",
"disableBibliogram",
"disableOsm",
"alwaysProxy",
"onlyEmbeddedVideo",
"videoQuality",
"removeTwitterSW",
"invidiousDarkMode",
"persistInvidiousPrefs",
"invidiousVolume",
"invidiousPlayerStyle",
"invidiousSubtitles",
"invidiousAutoplay",
"exceptions",
"theme",
],
result => {
nitterInstance.value = result.nitterInstance || '';
invidiousInstance.value = result.invidiousInstance || '';
bibliogramInstance.value = result.bibliogramInstance || '';
osmInstance.value = result.osmInstance || '';
(result) => {
theme.value = result.theme || "";
if (result.theme) document.body.classList.add(result.theme);
nitterInstance.value = result.nitterInstance || "";
invidiousInstance.value = result.invidiousInstance || "";
bibliogramInstance.value = result.bibliogramInstance || "";
osmInstance.value = result.osmInstance || "";
disableNitter.checked = !result.disableNitter;
disableInvidious.checked = !result.disableInvidious;
disableBibliogram.checked = !result.disableBibliogram;
disableOsm.checked = !result.disableOsm;
alwaysProxy.checked = result.alwaysProxy;
onlyEmbeddedVideo.checked = result.onlyEmbeddedVideo;
videoQuality.value = result.videoQuality || '';
videoQuality.value = result.videoQuality || "";
removeTwitterSW.checked = !result.removeTwitterSW;
invidiousDarkMode.checked = result.invidiousDarkMode;
persistInvidiousPrefs.checked = result.persistInvidiousPrefs;
whitelist = result.whitelist || [];
whitelist.forEach(prependWhitelistItem);
exceptions = result.exceptions || [];
exceptions.forEach(prependExceptionsItem);
invidiousVolume.value = result.invidiousVolume;
document.querySelector("#volume-value").textContent = result.invidiousVolume
? `${result.invidiousVolume}%`
: " - ";
invidiousPlayerStyle.value = result.invidiousPlayerStyle || "";
invidiousSubtitles.value = result.invidiousSubtitles || "";
invidiousAutoplay.checked = result.invidiousAutoplay;
}
);
function openTab(tab, event) {
let i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName('tabcontent');
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = 'none';
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName('tablinks');
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(' active', '');
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(tab).style.display = 'block';
event.currentTarget.className += ' active';
document.getElementById(tab).style.display = "block";
event.currentTarget.className += " active";
}
document.getElementById('general-tab').addEventListener(
'click', openTab.bind(null, 'general')
);
document.getElementById('advanced-tab').addEventListener(
'click', openTab.bind(null, 'advanced')
);
document.getElementById('whitelist-tab').addEventListener(
'click', openTab.bind(null, 'whitelist')
);
document
.getElementById("general-tab")
.addEventListener("click", openTab.bind(null, "general"));
document
.getElementById("advanced-tab")
.addEventListener("click", openTab.bind(null, "advanced"));
document
.getElementById("exceptions-tab")
.addEventListener("click", openTab.bind(null, "exceptions"));
document.getElementById('general-tab').click();
document.getElementById("general-tab").click();
function addToWhitelist() {
const input = document.getElementById('new-whitelist-item');
function addToExceptions() {
const input = document.getElementById("new-exceptions-item");
const type = document.querySelector('input[name="type"]:checked').value;
if (input.value) {
try {
let value = input.value;
new RegExp(input.value);
const index = whitelist.push(input.value);
prependWhitelistItem(input.value, index);
if (type === "URL") {
value = value.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
}
exceptions.push(value);
browser.storage.sync.set({
whitelist: whitelist
exceptions: exceptions,
});
input.value = '';
prependExceptionsItem(value, exceptions.indexOf(value));
input.value = "";
} catch (error) {
input.setCustomValidity('Invalid RegExp');
input.setCustomValidity("Invalid RegExp");
}
} else {
input.setCustomValidity('Invalid RegExp');
input.setCustomValidity("Invalid RegExp");
}
}
document.getElementById('add-to-whitelist').addEventListener(
'click', addToWhitelist
);
document
.getElementById("add-to-exceptions")
.addEventListener("click", addToExceptions);
function debounce(func, wait, immediate) {
let timeout;
return () => {
let context = this, args = arguments;
let context = this,
args = arguments;
let later = () => {
timeout = null;
if (!immediate) func.apply(context, args);
@ -134,100 +217,239 @@ function debounce(func, wait, immediate) {
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
}
function parseURL(urlString) {
if (urlString) {
try {
const url = new URL(urlString);
if (url.username && url.password) {
return `${url.protocol}//${url.username}:${url.password}@${url.host}`
return `${url.protocol}//${url.username}:${url.password}@${url.host}`;
} else {
return url.origin;
}
} catch (error) {
console.log(error);
return '';
return "";
}
} else {
return '';
return "";
}
}
let nitterInstanceChange = debounce(() => {
if (nitterInstance.checkValidity()) {
browser.storage.sync.set({
nitterInstance: parseURL(nitterInstance.value)
nitterInstance: parseURL(nitterInstance.value),
});
}
}, 500);
nitterInstance.addEventListener('input', nitterInstanceChange);
nitterInstance.addEventListener("input", nitterInstanceChange);
let invidiousInstanceChange = debounce(() => {
if (invidiousInstance.checkValidity()) {
browser.storage.sync.set({
invidiousInstance: parseURL(invidiousInstance.value)
invidiousInstance: parseURL(invidiousInstance.value),
});
}
}, 500);
invidiousInstance.addEventListener('input', invidiousInstanceChange);
invidiousInstance.addEventListener("input", invidiousInstanceChange);
let bibliogramInstanceChange = debounce(() => {
if (bibliogramInstance.checkValidity()) {
browser.storage.sync.set({
bibliogramInstance: parseURL(bibliogramInstance.value)
bibliogramInstance: parseURL(bibliogramInstance.value),
});
}
}, 500);
bibliogramInstance.addEventListener('input', bibliogramInstanceChange);
bibliogramInstance.addEventListener("input", bibliogramInstanceChange);
let osmInstanceChange = debounce(() => {
if (osmInstance.checkValidity()) {
browser.storage.sync.set({
osmInstance: parseURL(osmInstance.value)
osmInstance: parseURL(osmInstance.value),
});
}
}, 500);
osmInstance.addEventListener('input', osmInstanceChange);
osmInstance.addEventListener("input", osmInstanceChange);
disableNitter.addEventListener('change', event => {
disableNitter.addEventListener("change", (event) => {
browser.storage.sync.set({ disableNitter: !event.target.checked });
});
disableInvidious.addEventListener('change', event => {
disableInvidious.addEventListener("change", (event) => {
browser.storage.sync.set({ disableInvidious: !event.target.checked });
});
disableBibliogram.addEventListener('change', event => {
disableBibliogram.addEventListener("change", (event) => {
browser.storage.sync.set({ disableBibliogram: !event.target.checked });
});
disableOsm.addEventListener('change', event => {
disableOsm.addEventListener("change", (event) => {
browser.storage.sync.set({ disableOsm: !event.target.checked });
});
alwaysProxy.addEventListener('change', event => {
alwaysProxy.addEventListener("change", (event) => {
browser.storage.sync.set({ alwaysProxy: event.target.checked });
});
onlyEmbeddedVideo.addEventListener('change', event => {
onlyEmbeddedVideo.addEventListener("change", (event) => {
browser.storage.sync.set({ onlyEmbeddedVideo: event.target.checked });
});
videoQuality.addEventListener('change', event => {
videoQuality.addEventListener("change", (event) => {
browser.storage.sync.set({
videoQuality: event.target.options[videoQuality.selectedIndex].value
videoQuality: event.target.options[videoQuality.selectedIndex].value,
});
});
removeTwitterSW.addEventListener('change', event => {
removeTwitterSW.addEventListener("change", (event) => {
browser.storage.sync.set({ removeTwitterSW: !event.target.checked });
});
invidiousDarkMode.addEventListener('change', event => {
invidiousDarkMode.addEventListener("change", (event) => {
browser.storage.sync.set({ invidiousDarkMode: event.target.checked });
});
persistInvidiousPrefs.addEventListener('change', event => {
persistInvidiousPrefs.addEventListener("change", (event) => {
browser.storage.sync.set({ persistInvidiousPrefs: event.target.checked });
});
let invidiousVolumeChange = debounce(() => {
document.querySelector(
"#volume-value"
).textContent = `${invidiousVolume.value}%`;
browser.storage.sync.set({
invidiousVolume: invidiousVolume.value,
});
}, 500);
invidiousVolume.addEventListener("input", invidiousVolumeChange);
invidiousPlayerStyle.addEventListener("change", (event) => {
browser.storage.sync.set({
invidiousPlayerStyle:
event.target.options[invidiousPlayerStyle.selectedIndex].value,
});
});
let invidiousSubtitlesChange = debounce(() => {
if (invidiousInstance.checkValidity()) {
browser.storage.sync.set({
invidiousSubtitles: invidiousSubtitles.value,
});
}
}, 500);
invidiousSubtitles.addEventListener("input", invidiousSubtitlesChange);
invidiousAutoplay.addEventListener("change", (event) => {
browser.storage.sync.set({ invidiousAutoplay: event.target.checked });
});
theme.addEventListener("change", (event) => {
const value = event.target.options[theme.selectedIndex].value;
switch (value) {
case "dark-theme":
document.body.classList.add("dark-theme");
document.body.classList.remove("light-theme");
break;
case "light-theme":
document.body.classList.add("light-theme");
document.body.classList.remove("dark-theme");
break;
default:
document.body.classList.remove("light-theme");
document.body.classList.remove("dark-theme");
}
browser.storage.sync.set({
theme: value,
});
});
function autocomplete(input, list) {
let currentFocus;
input.addEventListener("focus", (e) => {
showOptions(e, true);
});
input.addEventListener("input", (e) => {
const val = e.target.value;
if (!val) {
return false;
}
currentFocus = -1;
showOptions(e);
});
input.addEventListener("keydown", function (e) {
let x = document.getElementById(this.id + "autocomplete-list");
if (x) x = x.getElementsByTagName("div");
if (e.keyCode == 40) {
currentFocus++;
addActive(x);
} else if (e.keyCode == 38) {
currentFocus--;
addActive(x);
} else if (e.keyCode == 13) {
e.preventDefault();
if (currentFocus > -1) {
if (x) x[currentFocus].click();
}
}
});
function showOptions(event, showAll = false) {
let div,
i,
val = event.target.value;
closeAllLists();
div = document.createElement("div");
div.setAttribute("id", event.target.id + "autocomplete-list");
div.setAttribute("class", "autocomplete-items");
event.target.parentNode.appendChild(div);
for (i = 0; i < list.length; i++) {
if (list[i].toLowerCase().indexOf(val.toLowerCase()) > -1) {
div.appendChild(getItem(list[i], val));
} else if (showAll) {
div.appendChild(getItem(list[i], val));
}
}
}
function getItem(item, val) {
let div = document.createElement("div");
div.innerHTML = "<strong>" + item.substr(0, val.length) + "</strong>";
div.innerHTML += item.substr(val.length);
div.innerHTML += "<input type='hidden' value='" + item + "'>";
div.addEventListener("click", function (e) {
input.value = e.target.getElementsByTagName("input")[0].value;
input.dispatchEvent(new Event("input"));
closeAllLists();
});
return div;
}
function addActive(x) {
if (!x) return false;
removeActive(x);
if (currentFocus >= x.length) currentFocus = 0;
if (currentFocus < 0) currentFocus = x.length - 1;
x[currentFocus].classList.add("autocomplete-active");
}
function removeActive(x) {
for (let i = 0; i < x.length; i++) {
x[i].classList.remove("autocomplete-active");
}
}
function closeAllLists(elmnt) {
let x = document.getElementsByClassName("autocomplete-items");
for (let i = 0; i < x.length; i++) {
if (elmnt != x[i] && elmnt != input) {
x[i].parentNode.removeChild(x[i]);
}
}
}
document.addEventListener("click", (e) => {
if (!autocompletes.find((element) => element.id === e.target.id)) {
closeAllLists(e.target);
}
});
}
autocompletes.forEach((value) => {
autocomplete(document.getElementById(value.id), value.instances);
});

View File

@ -1,5 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg' width='512' height='512' viewBox='0 0 512 512'>
<path d='M384,224V408a40,40,0,0,1-40,40H104a40,40,0,0,1-40-40V168a40,40,0,0,1,40-40H271.48' style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px'/>
<polyline points='336 64 448 64 448 176' style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px'/>
<line x1='224' y1='288' x2='440' y2='72' style='fill:none;stroke:#FFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px'/>
</svg>

Before

Width:  |  Height:  |  Size: 553 B

View File

@ -1,122 +1,170 @@
<!doctype html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title></title>
<link href="../styles.css" rel="stylesheet" />
</head>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link href="../styles.css" rel="stylesheet">
</head>
<body class="popup">
<header class="popup">
<div class="logo-container">
<img
src="../../assets/images/icon128.png"
alt="Privacy Redirect logo"
/>
<h1>
<span data-localise="__MSG_privacy__" class="privacy">Privacy</span
><br /><span data-localise="__MSG_redirect__">Redirect</span>
</h1>
</div>
<div class="version">
<span data-localise="__MSG_version__">Version</span>:&nbsp;<span
id="version"
></span>
</div>
</header>
<body class="popup">
<header>
<div class="logo-container">
<img src="../../images/icon128.png" alt="Privacy Redirect logo">
<h1><span class="privacy">Privacy</span><br>Redirect</h1>
</div>
<div class="version">
<span>Version:&nbsp;<span id="version"></span></span>
</div>
</header>
<section class="settings-block">
<table class="option" aria-label="Toggle Nitter redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableNitter__">Nitter Redirects</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-nitter"
type="checkbox"
checked
/>&nbsp;
<label for="disable-nitter" class="checkbox-label"></label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle Nitter redirects">
<h1>Nitter Redirects</h1>
<input aria-hidden="true" id="disable-nitter" type="checkbox" checked>&nbsp;
<label for="disable-nitter" class="checkbox-label">
</label>
</div>
</section>
<section class="settings-block">
<table class="option" aria-label="Toggle Invidious redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableInvidious__">
Invidious Redirects
</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-invidious"
type="checkbox"
checked
/>&nbsp;
<label for="disable-invidious" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle Invidious redirects">
<h1>Invidious Redirects</h1>
<input aria-hidden="true" id="disable-invidious" type="checkbox" checked>&nbsp;
<label for="disable-invidious" class="checkbox-label">
</label>
</div>
</section>
<section class="settings-block">
<table class="option" aria-label="Toggle Bibliogram redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableBibliogram__">
Bibliogram Redirects
</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-bibliogram"
type="checkbox"
checked
/>&nbsp;
<label for="disable-bibliogram" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle Bibliogram redirects">
<h1>Bibliogram Redirects</h1>
<input aria-hidden="true" id="disable-bibliogram" type="checkbox" checked>&nbsp;
<label for="disable-bibliogram" class="checkbox-label">
</label>
</div>
</section>
<section class="settings-block">
<table class="option" aria-label="Toggle OpenStreetMap redirects">
<tbody>
<tr>
<td>
<h1 data-localise="__MSG_disableOsm__">
OpenStreetMap Redirects
</h1>
</td>
<td>
<input
aria-hidden="true"
id="disable-osm"
type="checkbox"
checked
/>&nbsp;
<label for="disable-osm" class="checkbox-label"> </label>
</td>
</tr>
</tbody>
</table>
</section>
<section class="options settings_block">
<div class="onoffswitch switch" aria-label="Toggle OpenStreetMap redirects">
<h1>OpenStreetMap Redirects</h1>
<input aria-hidden="true" id="disable-osm" type="checkbox" checked>&nbsp;
<label for="disable-osm" class="checkbox-label">
</label>
</div>
</section>
<section class="settings-block"></section>
<section class="options settings_block">
<h1>Nitter Instance</h1>
<input id="nitter-instance" list="nitter-instance-list" type="url" placeholder="https://nitter.net">
<datalist id="nitter-instance-list">
<option value="https://nitter.net">
<option value="https://nitter.snopyta.org">
<option value="https://nitter.42l.fr">
<option value="https://nitter.nixnet.xyz">
<option value="https://nitter.13ad.de">
<option value="https://tw.openalgeria.org">
<option value="https://nitter.pussthecat.org">
<option value="https://nitter.mastodont.cat">
<option value="https://nitter.dark.fail">
<option value="https://nitter.tedomum.net">
<option value="https://t.maisputain.ovh">
<option value="http://3nzoldnxplag42gqjs23xvghtzf6t6yzssrtytnntc6ppc7xxuoneoad.onion">
<option value="http://nitter.l4qlywnpwqsluw65ts7md3khrivpirse744un3x7mlskqauz5pyuzgqd.onion">
<option value="http://3nzoldnxplag42gqjs23xvghtzf6t6yzssrtytnntc6ppc7xxuoneoad.onion">
</datalist>
<h1>Invidious Instance</h1>
<input id="invidious-instance" list="invidious-instances-list" type="url" placeholder="https://invidio.us">
<datalist id="invidious-instances-list">
<option value="https://invidio.us">
<option value="https://invidious.snopyta.org">
<option value="https://invidiou.sh">
<option value="https://yewtu.be">
<option value="https://yt.maisputain.ovh">
<option value="https://invidious.toot.koeln">
<option value="https://invidious.ggc-project.de">
<option value="https://invidious.toot.koeln">
<option value="http://kgg2m7yk5aybusll.onion">
<option value="http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion">
<option value="http://fz253lmuao3strwbfbmx46yu7acac2jz27iwtorgmbqlkurlclmancad.onion">
<option value="http://qklhadlycap4cnod.onion">
<option value="http://c7hqkpkpemu6e7emz5b4vyz7idjgdvgaaa3dyimmeojqbgpea3xqjoid.onion">
<option value="http://mfqczy4mysscub2s.onion">
</datalist>
<h1>Bibliogram Instance</h1>
<input id="bibliogram-instance" list="bibliogram-instance-list" type="url" placeholder="https://bibliogram.art">
<datalist id="bibliogram-instance-list">
<option value="https://bibliogram.art">
<option value="https://bibliogram.snopyta.org">
<option value="https://bibliogram.pussthecat.org">
<option value="https://insta.maisputain.ovh">
<option value="https://bibliogram.nixnet.services">
</datalist>
<h1>OpenStreetMap Instance</h1>
<input id="osm-instance" list="osm-instance-list" type="url" placeholder="https://openstreetmap.org">
<datalist id="osm-instance-list">
<option value="https://openstreetmap.org">
</datalist>
</section>
<footer>
<a class="button" id="more-options">
<span data-localise="__MSG_moreOptions__">More Options&nbsp;</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="512"
height="512"
viewBox="0 0 512 512"
>
<path
d="M384,224V408a40,40,0,0,1-40,40H104a40,40,0,0,1-40-40V168a40,40,0,0,1,40-40H271.48"
style="
fill: none;
stroke: inherit;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 32px;
"
/>
<polyline
points="336 64 448 64 448 176"
style="
fill: none;
stroke: inherit;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 32px;
"
/>
<line
x1="224"
y1="288"
x2="440"
y2="72"
style="
fill: none;
stroke: inherit;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 32px;
"
/>
</svg>
</a>
</footer>
<footer>
<a class="button" id="more-options">
<span>More Options&nbsp;</span>
<img height="18px" src="open.svg" alt="more-options" />
</a>
</footer>
<script src="./popup.js"></script>
</body>
</html>
<script src="./popup.js"></script>
<script src="../../assets/javascript/localise.js"></script>
</body>
</html>

View File

@ -1,33 +1,23 @@
'use strict';
"use strict";
let nitterInstance = document.querySelector('#nitter-instance');
let invidiousInstance = document.querySelector('#invidious-instance');
let bibliogramInstance = document.querySelector('#bibliogram-instance');
let osmInstance = document.querySelector('#osm-instance');
let disableNitter = document.querySelector('#disable-nitter');
let disableInvidious = document.querySelector('#disable-invidious');
let disableBibliogram = document.querySelector('#disable-bibliogram');
let disableOsm = document.querySelector('#disable-osm');
let version = document.querySelector('#version');
let disableNitter = document.querySelector("#disable-nitter");
let disableInvidious = document.querySelector("#disable-invidious");
let disableBibliogram = document.querySelector("#disable-bibliogram");
let disableOsm = document.querySelector("#disable-osm");
let version = document.querySelector("#version");
window.browser = window.browser || window.chrome;
browser.storage.sync.get(
[
'nitterInstance',
'invidiousInstance',
'bibliogramInstance',
'osmInstance',
'disableNitter',
'disableInvidious',
'disableBibliogram',
'disableOsm'
"disableNitter",
"disableInvidious",
"disableBibliogram",
"disableOsm",
"theme",
],
result => {
nitterInstance.value = result.nitterInstance || '';
invidiousInstance.value = result.invidiousInstance || '';
bibliogramInstance.value = result.bibliogramInstance || '';
osmInstance.value = result.osmInstance || '';
(result) => {
if (result.theme) document.body.classList.add(result.theme);
disableNitter.checked = !result.disableNitter;
disableInvidious.checked = !result.disableInvidious;
disableBibliogram.checked = !result.disableBibliogram;
@ -37,91 +27,22 @@ browser.storage.sync.get(
version.textContent = browser.runtime.getManifest().version;
function debounce(func, wait, immediate) {
let timeout;
return () => {
let context = this, args = arguments;
let later = () => {
timeout = null;
if (!immediate) func.apply(context, args);
};
let callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
function parseURL(urlString) {
if (urlString) {
try {
const url = new URL(urlString);
if (url.username && url.password) {
return `${url.protocol}//${url.username}:${url.password}@${url.host}`
} else {
return url.origin;
}
} catch (error) {
console.log(error);
return '';
}
} else {
return '';
}
}
let nitterInstanceChange = debounce(() => {
if (nitterInstance.checkValidity()) {
browser.storage.sync.set({
nitterInstance: parseURL(nitterInstance.value)
});
}
}, 500);
nitterInstance.addEventListener('input', nitterInstanceChange);
let invidiousInstanceChange = debounce(() => {
if (invidiousInstance.checkValidity()) {
browser.storage.sync.set({
invidiousInstance: parseURL(invidiousInstance.value)
});
}
}, 500);
invidiousInstance.addEventListener('input', invidiousInstanceChange);
let bibliogramInstanceChange = debounce(() => {
if (bibliogramInstance.checkValidity()) {
browser.storage.sync.set({
bibliogramInstance: parseURL(bibliogramInstance.value)
});
}
}, 500);
bibliogramInstance.addEventListener('input', bibliogramInstanceChange);
let osmInstanceChange = debounce(() => {
if (osmInstance.checkValidity()) {
browser.storage.sync.set({
osmInstance: parseURL(osmInstance.value)
});
}
}, 500);
osmInstance.addEventListener('input', osmInstanceChange);
disableNitter.addEventListener('change', event => {
disableNitter.addEventListener("change", (event) => {
browser.storage.sync.set({ disableNitter: !event.target.checked });
});
disableInvidious.addEventListener('change', event => {
disableInvidious.addEventListener("change", (event) => {
browser.storage.sync.set({ disableInvidious: !event.target.checked });
});
disableBibliogram.addEventListener('change', event => {
disableBibliogram.addEventListener("change", (event) => {
browser.storage.sync.set({ disableBibliogram: !event.target.checked });
});
disableOsm.addEventListener('change', event => {
disableOsm.addEventListener("change", (event) => {
browser.storage.sync.set({ disableOsm: !event.target.checked });
});
document.querySelector('#more-options').addEventListener('click', () => {
document.querySelector("#more-options").addEventListener("click", () => {
browser.runtime.openOptionsPage();
});

View File

@ -1,31 +1,41 @@
:root {
--text-main: #FFF;
--text-secondary: #000;
--dark: #3C4043;
--darker: #292A2D;
--light: #E3E7EA;
--lighter: #FFF;
--active: #FF5B56;
body {
--text: #fff;
--bg-main: #3c4043;
--bg-secondary: #292a2d;
--active: #ff5b56;
--space: 5px;
--danger: #f04141;
--danger-light: #F9D0D5;
--danger-light: #f9d0d5;
--dark-grey: #767676;
--light-grey: #c3c3c3;
}
body.light-theme {
--text: #000;
--bg-main: #e3e7ea;
--bg-secondary: #fff;
}
.light-theme.popup,
.light-theme .popup {
background-color: var(--bg-secondary);
}
body {
color: var(--text-secondary);
margin: 0;
width: 400px;
max-width: 400px;
margin: auto;
min-height: 572px;
font-family: Sans-Serif;
background-color: var(--darker);
background-color: var(--bg-secondary);
color: var(--text);
}
.popup {
width: 300px;
min-height: auto;
overflow: hidden;
background-color: var(--dark);
background-color: var(--bg-main);
}
input {
@ -35,8 +45,8 @@ input {
}
header {
background-color: var(--lighter);
color: var(--text-secondary);
background-color: var(--bg-main);
color: var(--text);
display: flex;
padding: var(--space);
}
@ -45,7 +55,7 @@ header .logo-container {
width: 100%;
margin: var(--space) 0 var(--space) 0;
display: flex;
align-items:center;
align-items: center;
}
header .logo-container img {
@ -75,7 +85,7 @@ header .version {
h1 {
font-size: 14px;
margin: var(--space) auto;
margin: 7px auto;
}
i {
@ -95,7 +105,7 @@ h3 {
h1,
h2 {
color: var(--text-main);
color: var(--text);
}
footer {
@ -106,26 +116,40 @@ footer a.button {
margin: var(--space);
}
/* Elements */
input[type=url], input[type=text], select {
input[type="url"],
input[type="text"],
select {
width: 100%;
box-sizing: border-box;
margin-bottom: var(--space);
background-color: var(--bg-main);
border-style: inset;
color: var(--text);
}
input[type=url] {
input[type="url"] {
padding: 1px 2px;
}
input[type=checkbox] {
input[type="checkbox"] {
opacity: 0;
}
input[type="radio"] {
appearance: radio;
-moz-appearance: radio;
-webkit-appearance: radio;
}
input[type="radio"]:checked + label {
background: transparent;
}
.checkbox-label {
margin-left: 5px;
background: grey;
border-radius: 25px;
color: var(--text-main);
color: var(--text);
cursor: pointer;
display: block;
float: right;
@ -137,37 +161,39 @@ input[type=checkbox] {
}
.checkbox-label:after {
background: #fff;
background: white;
border-radius: 90px;
content: '';
content: "";
height: 20px;
left: var(--space);
position: absolute;
top: var(--space);
transition: 0.3s; /* Acts on transform below */
transition: 0.3s;
width: 20px;
}
input:checked+label {
input:checked + label {
background: var(--active);
}
/* position when active*/
input:checked+label:after {
input:checked + label:after {
left: calc(100% - var(--space));
transform: translateX(-100%);
}
.settings_block {
.settings-block {
display: block;
padding: 10px 1em 1em 1em;
padding: 5px 10px 5px 10px;
}
.settings_block h1 {
.settings-block h1 {
float: left;
}
.button {
border: var(--active) solid 1px;
color: var(--text-main);
color: var(--text);
stroke: var(--text);
display: block;
font-size: 12px;
font-weight: bold;
@ -186,12 +212,13 @@ input:checked+label:after {
.button:hover {
background-color: var(--active);
color: #fff;
color: var(--text);
stroke: var(--text);
}
.button:active {
background-color: var(--active);
box-shadow: 0 var(--space) var(--dark);
box-shadow: 0 var(--space) var(--bg-main);
transform: translateY(4px);
}
@ -207,13 +234,13 @@ input:invalid {
.tab {
overflow: hidden;
background-color: var(--darker);
background-color: var(--bg-secondary);
}
.tab button {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
color: var(--text-main);
color: var(--text);
background-color: inherit;
float: left;
border: none;
@ -221,7 +248,7 @@ input:invalid {
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
border: solid 1px var(--dark);
border: solid 1px var(--bg-main);
width: 33.333%;
font-size: 14px;
}
@ -231,106 +258,206 @@ input:invalid {
}
.tab button.active {
background-color: var(--dark);
background-color: var(--bg-main);
}
.tabcontent {
padding-top: 10px;
display: none;
border: solid 1px var(--dark);
background-color: var(--dark);
background-color: var(--bg-main);
min-height: 510px;
}
div.whitelist {
div.exceptions {
clear: left;
}
div.whitelist > input {
div.exceptions > input {
width: 240px;
float: left;
}
#add-to-whitelist {
width: 120px;
#add-to-exceptions {
float: right;
border: var(--active) solid 1px;
background-color: var(--active);
color: var(--text-main);
color: var(--text);
font-weight: bold;
cursor: pointer;
border-radius: 25px;
border-radius: 50%;
padding: 1px 1px 0px 1px;
margin-right: 5px;
}
#add-to-exceptions svg {
height: 20px;
width: 20px;
}
ul {
padding: 0;
list-style-type: none;
color: var(--text-main);
margin-right: 20px;
margin-left: 20px;
color: var(--text);
margin: 20px 20px 0 20px;
}
li {
border-bottom: solid 0.5px var(--darker);
border-bottom: solid 0.5px var(--bg-secondary);
padding: 20px 0px 20px 20px;
}
#whitelist-items button {
#exceptions-items button {
float: right;
margin-right: -5px;
border: var(--active) solid 1px;
background-color: var(--active);
color: var(--text-main);
color: var(--text);
font-weight: bold;
cursor: pointer;
border-radius: 50%;
padding: 2px 2px 0px 2px;
}
@media (prefers-color-scheme: dark) {
.button svg {
height: 18px;
width: 18px;
}
body.popup, header, h1, input, select, div.tabcontent, button.tablinks.active {
background-color: var(--dark);
color: var(--text-main);
}
.autocomplete {
position: relative;
display: inline-block;
width: 100%;
}
body {
background-color: var(--darker);
}
.autocomplete input {
background: url(../assets/images/chevron-down.svg) right no-repeat;
}
a.button {
color: var(--text-main);
}
.autocomplete-items {
position: absolute;
border: 1px solid var(--bg-main);
border-bottom: none;
border-top: none;
z-index: 99;
top: 85%;
left: 0;
right: 0;
overflow-y: auto;
max-height: 175px;
color: var(--text);
overflow-x: hidden;
max-width: 380px;
}
::placeholder {
color: var(--text-main);
opacity: 0.7;
}
.autocomplete-items div {
padding: 10px;
cursor: pointer;
background-color: var(--bg-secondary);
border-bottom: 1px solid var(--bg-main);
}
.autocomplete-items div:hover {
background-color: var(--active);
}
.autocomplete-active {
background-color: var(--active);
color: var(--text);
}
.option {
width: 100%;
}
.option td {
vertical-align: middle;
}
input[type="range"] {
-webkit-appearance: none;
margin: 18px 0;
width: 100%;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
border-color: var(--dark-grey), var(--light-grey);
background: var(--bg-main);
border-radius: 1.3px;
border: 0.2px inset var(--dark-grey);
}
input[type="range"]::-webkit-slider-thumb {
border-color: var(--active);
border: 1px solid var(--dark-grey);
height: 36px;
width: 16px;
border-radius: 3px;
background: var(--active);
cursor: pointer;
-webkit-appearance: none;
margin-top: -14px;
}
input[type="range"]:focus::-webkit-slider-runnable-track {
background: var(--bg-main);
}
input[type="range"]::-moz-range-track {
width: 100%;
height: 8.4px;
cursor: pointer;
border-color: var(--dark-grey), var(--light-grey);
background: var(--bg-main);
border-radius: 1.3px;
border: 0.2px inset var(--dark-grey);
}
input[type="range"]::-moz-range-thumb {
border-color: var(--active);
border: 1px solid var(--dark-grey);
height: 36px;
width: 16px;
border-radius: 3px;
background: var(--active);
cursor: pointer;
}
::placeholder {
color: var(--text);
opacity: 0.7;
}
*:focus {
outline: var(--active) solid 2px;
}
@media (prefers-color-scheme: light) {
body.popup, header, h1, input, select, div.tabcontent, button.tablinks.active {
background-color: var(--lighter);
color: var(--text-secondary);
}
body {
background-color: var(--light);
--text: #000;
--text-secondary: #fff;
--bg-main: #e3e7ea;
--bg-secondary: #fff;
}
a.button {
color: var(--text-secondary);
body.dark-theme {
--text: #fff;
--text-secondary: #000;
--bg-main: #3c4043;
--bg-secondary: #292a2d;
}
button.tablinks {
background-color: var(--light);
color: var(--text-secondary);
.popup {
background-color: var(--bg-secondary);
}
::placeholder {
color: var(--text-secondary);
opacity: 0.7;
}
}
#volume-value {
float: right;
}

View File

@ -1,19 +0,0 @@
# Privacy Policy for Privacy Redirect
**I solemnly swear this extension is up to only good! 🙂**
All aspects of the extension work locally on your device. With the exception of
OpenStreetMap (OSM) reverse geocoding, done via the [OSM Nomantim API](https://nominatim.org/release-docs/latest/),
used as part of OSM redirects, the extension does not connect to any other
third-party web services and it doesnt collect or transmit
any information about you, your browsing habits, or your device.
The extension requires access to request data for **all websites** in order
to intercept requests made to targeted services (Twitter, YouTube, Instagram &
Google Maps) so that they may be redirected to the appropriate privacy
respecting alternative, all other requests are ignored.
The extension also requires **local storage** permissions in order to store
extension specific user preferences and settings.
The extension development is funded through gifts, donations and love.

View File

@ -1,7 +1,8 @@
module.exports = {
ignoreFiles: [
'images/Screen*.png',
'images/small-tile.png',
'buy-me-a-coffee.png'
'assets/images/Screen Shot*.png',
'assets/images/buy-me-a-coffee.png',
'assets/images/logo*.png',
'assets/images/badge*.png'
],
};