Greasy Fork is available in English.
Находит доступные юзерскрипты для текущей веб-страницы.
- // ==UserScript==
- // @version 7.6.4
- // @name Magic Userscript+ : Show Site All UserJS
- // @name:ar Magic Userscript+: عرض جميع ملفات UserJS
- // @name:de Magic Userscript+ : Website anzeigen Alle UserJS
- // @name:es Magic Userscript+: Mostrar sitio todos los UserJS
- // @name:fr Magic Userscript+ : Afficher le site Tous les UserJS
- // @name:ja Magic Userscript+ : サイトをすべて表示 UserJS
- // @name:nl Magic Userscript+: Site alle UserJS tonen
- // @name:pl Magic Userscript+ : Pokaż witrynę Wszystkie UserJS
- // @name:ru Magic Userscript+: показать сайт всем UserJS
- // @name:zh Magic Userscript+ :显示站点所有 UserJS
- // @name:zh-CN Magic Userscript+ :显示站点所有 UserJS
- // @name:zh-TW Magic Userscript+ :显示站点所有 UserJS
- // @description Finds available userscripts for the current webpage.
- // @description:ar يبحث عن نصوص المستخدمين المتاحة لصفحة الويب الحالية.
- // @description:de Findet verfügbare Benutzerskripte für die aktuelle Webseite.
- // @description:es Busca los usercripts disponibles para la página web actual.
- // @description:fr Recherche les userscripts disponibles pour la page web en cours.
- // @description:ja 現在のウェブページで利用可能なユーザスクリプトを検索します。
- // @description:nl Zoekt beschikbare gebruikerscripts voor de huidige webpagina.
- // @description:pl Wyszukuje dostępne skrypty użytkownika dla bieżącej strony internetowej.
- // @description:ru Находит доступные юзерскрипты для текущей веб-страницы.
- // @description:zh 为当前网页查找可用的用户脚本。
- // @description:zh-CN 为当前网页查找可用的用户脚本。
- // @description:zh-TW 为当前网页查找可用的用户脚本。
- // @author Magic <magicoflolis@tuta.io>
- // @supportURL https://github.com/magicoflolis/Userscript-Plus/issues
- // @namespace https://github.com/magicoflolis/Userscript-Plus
- // @homepageURL https://github.com/magicoflolis/Userscript-Plus
- // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV8TRZFKBzuIOGSoTnZREcGlVLEIFkpboVUHk0u/oElDkuLiKLgWHPxYrDq4OOvq4CoIgh8gzg5Oii5S4v+SQosYD4778e7e4+4dIDSrTLN6YoCm22Y6EZdy+VWp7xUigghhDqLMLCOZWczCd3zdI8DXuyjP8j/35xhUCxYDAhJxjBmmTbxBPLNpG5z3icOsLKvE58QTJl2Q+JHrisdvn###CzwzbGbT88RhYqnUxUoXs7KpEU8TR1RNp3wh57HKeYuzVq2z9j35C4MFfSXDdZqjSGAJSaQgQUEdFVRhI0qrToqFNO3Hffwjrj9FLoVcFTByLKAGDbLrB/+D391axalJLykYB3pfHOdjDOjbBVoNx/k+dpzWCSA+A1d6x19rArOfpDc6WuQICG0DF9cdTdkDLneA4SdDNmVXEmkKxSLwfkbflAeGboGBNa+39j5OH4AsdbV8AxwcAuMlyl73eXd/d2//nmn39wOjunK6jS33SAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+gDDBAAJWyXgRAAABRPSURBVHjazVt9VNRl9v9854VhhjdBiHcUaFQEDTVCdk1IstTV0jb1LLZkJZrl4knLTnZaKjdqdXdLXcvfyoHUErPUBBEMLREJ6egJFBUUBF9WMd6R4WW+M/P5/eHMdxkYEJS0e8498MzzzPN87537PM+9n3u/An49kgFwA+AJIACAP4AxAEIA+AFwBzDEPLYJQB2AqwDOATgN4AqAywBubNu2rTk+Pl4EAJIyABAEwTQYDyn8CoIrAEQD+BOAMLPgLgAcAGDs2LGQyWSora1FYGAg6urqUFZWBgCIiYnBqVOn0NDQAAA6T0/Pm/X19ZflcvkZo9G4w2AwHAFgwG+Q5ACCg4KClixZsuT82rVrTTt27CCAHpybm8vq6moWFRXRZDKxpqaGkyZN4q0fl3zyySelsaIoMiYmhg899BD/9re/mQAUAogHEGxe8/5TaGiob0RERMrSpUuvZ2Zmmo4cOcIjR44wLy/PpgIOHjzI2tpaTp06lVqtlhUVFUxLS5MU8MQTT0hjLQqZPHkySRIAFy1aZAwNDa0C8C/z9rpvNBbAPwBctyVob3zw4EEWFBRQJpNJFvH999/3WwE5OTncs2ePZUwVgDjzWXPHB9Wd0GsACuRy+UoXFxev5cuXo7OzEyStWBBsHzGiKMJkunWGmUwmyGQy6X+lUgkAcHBw6HXxoUOHWv4dDiAFwNcAJtzpgTUQUgNYIgjCP2bNmiX7+9//jo0bN2Lz5s3IyspCUFCQJIz5xB7Q5FVVVZg9ezby8vKwYsWKgTzTFACZAFYC+BZA+6ArQKlUOouiuAZAgiAIMq1WixEjRuCjjz6Cq6srPvzwQ1RUVNze5GQyKyV1bW/atAnJycmIj49Henr6/66qLpbUdbzRaMS0adOQm5sLAN4A/g/ARADvAGgZvCNeLvdUq9VbzVcQAXDo0KHcs2cPDQYD29ramJiYSKVSedszICIigpGRkTbb9vb2nDRpEmNiYujk5MQZM2bQ3d2dbm5unDFjhtX4qKgonj59mt7e3t3XEAH82+xnDAp5AThjSxgPDw9++eWXNJlMbGpq4htvvCEdbr82r1ixgr/73e966zeaz4W7VoIzgAyZTMaoqChOnTqVarW6hxIyMzNpMBio0+m4ZMmSflnCPWCj2RKc71R4NYD1AIwODg4sKipiU1MTV69e3UNAT09Pfv311yTJxsZGLl++/J5Zwm1YNMugvhMFxAFoA0CFQsH33nuPHR0dbGtr49KlS6lSqawW8/LyYnZ2Ng0GA2/evMkXXniBCoXit6CEFrNbPiB6SalUtncVwNnZmcnJySTJlpYWvv7665TL5VaL+fj4cN++fSTJ+vp6vvzyy31agrOzc1/7eMAcFRXFIUOG2Oq7NhA/YaRcLr85bNgwuri4WE2kUqn48ccfs7OzkzqdjgkJCT0swdfXl7m5uTQajWxubuaCBQskRYWGhjIrK4uCIBAAY2JiSFJq3y2T5PTp03vrP9wfj1EA8PkjjzzC8+fPMysriz4+PlYTubi4cN26dSTJ5uZmm/vdz8+PBw4cIEnW1tbyxRdfpCAIDA4OpsFgsBo7WML3Y64287buk7x9fX07oqOj2dLSQpPJxMzMzB5KUKvV3LRpE/V6PW/evMmFCxfSzs7Oaoy/vz9/+OEHGo1GNjY2cu7cudRoNExNTeWePXuYkZHBsLAw7t+/n4IgUBAEPv/889y+fTu/+OILvvDCC5JAGRkZjIiI4OrVq/nll19aRYxdOSMjg+PHjycAJiUl8cMPP+TMmTO5Y8cOzpo1yxI7ePYV0v5rzpw51Gg0/Mtf/kKdTkeDwcCcnBx6enpaLebq6sr169dLJ7+t/a7Vann+/HmS5I0bN7hgwQK6urpy1apVLCwslLaASqViSkoKW1tbWVJSwuLiYt68eZNpaWlUKpUkyR9//JE///wzL126xOrqagYFBdncAhblZGdns66ujoWFhTx16hQ7Ozvp7+9PcxRpM5QOBlBu2cdOTk5877332NraSpPJxN27d9PLy8tqQQcHB27ZsoWiKLKlpYULFiyQrkhHR0e+++671Ov1tFB9fT1nz54tKSo6OpokOWbMGDY0NPC1116jWq2mvb09ly9fzsbGRoaHh5MkP/nkE9rb23PMmDESTnA7BVy4cIHBwcF0cXHhTz/9xH/+8580yxhsSwHx5nuT0dHRTEpKokql4sqVK9ne3k5RFLl//356eHhYLerm5sbPPvtMEvDFF1+kvb09165dy/b2dnan69ev86mnnqIgCJJwlnC366Hr7OxMk8nE2NhYkpRcYVvASW8KyM/Pl/qys7OZk5Nj8Q3ibQVFhZbBjz32GHU6HQFQqVQyOTmZOp2ORqOR6enpPZTg5OTErVu30mAwsKmpiSkpKezs7GRvdO7cOXp7e9PHx4cGg4GRkZHs7Ozkww8/LM05fvx4dnR0cNKkST0E7q8Cjh49aqUAC0gjCEJh90Aw1uw6SgqwABAWc37rrbfY0dFBURS5d+9eurm5WS3u7u7OlJQU9of0ej2fffZZOjk5UafT0dPTkydOnGBpaSmfeeYZzpkzh6dOnWJxcTG9vLwGTQGWtqOjo9EsM2Rm/lNXcKQ7kOHs7IwNGzZg48aNEEURTz31FD7++OOuwATa2tpw/vx5GAy3xyyVSiV8fX1hMplgMplw48YNvPTSS7h48SJ27NiB9PR0XL58GQsXLkRNTY3t+7oXsMXyeV9h9/z5861kdgdwvPt92tULtFxTarWaSUlJ1Ov11Ov13LVrF4cMGUKlUsl33nmHOp2uXxYgiiLnz59Pi5ttWUcmk1GhUFChUFjdKAqFwuqO79629blcLrfyVLu2zX+PW6LFUAD/7a+zoVKp+Mknn7C9vZ0Gg4Fbtmzh66+/zo6ODvaXzp07R19f3/sdI/zXLDumA2gdyJcdHByYnJxMURSp1+v7PPC6k8lk4ubNm38LIXMrgOlyM572zEAiJVEUUVBQAHd3d4wbNw4qlar/mRhBwKhRo3DlyhWcPXtWAkfvA9kBOCoHsBDAIwP9tsFgwNGjR6HRaBAZGWl14Nx2ZTs7PProo6irq0NxcfGAwdNBpEsAcOhOzSgoKIhqtZr/+c9/BnQGWKilpYVxcXE2cYO3336b77777q+9DQ4BQNmdfDk0NJS5ubm0s7Ojs7Mz169fT6PRaHPP90W//PIL4+Pje8QRmzZtYkpKyqAIGh0dzRMnTrC5uZm7du2in5+fpa8M5qzsgCaUyWRMT0+3+NbS7fDBBx+wvLyc9fX1rK2t5cmTJ/nSSy/xq6++oiiKvSqhqamJc+fO/VUQpMDAQNbW1jI9PZ0JCQksLy/nd999R3t7ewKow7fffmuqq6tjWlqapBlRFBkfH8+srCzJJe4e6lZUVEggaVlZGbVaLRUKBYOCgjhp0iRGRkbS29ubgiDQ3d2d27dv79MSampqOH/+fOke379/Pw8fPmxz24WHh9vkBx98sMf41atXs7KykgEBAQTAWbNmsba2lsHBwQRgwLx584wrVqxgdXU18/PzOXToUJJkVVUVk5KSGBcX12PShx9+WHJhAXDt2rVWgYeDgwMfe+wxenh48NVXX6W/vz/d3Ny4Z8+ePi2hsbGRs2fPplwuZ0JCAg8dOtRj7cOHD/f6/cLCwh7j09PTWVhYKDlBTk5OFEWR4eHhtKTa6yzwVFtbGydOnEiSfOutt3pFWCzRm+UunzBhAltaWjh69GgC4LJly5iXl0dBEOjm5sbg4GA6OTnxgQce4M6dO/u0hGvXrtGCSSQkJPRYWy6XS95id+6OUQJgZmam1Y8jCAJJWhRQpzArYOjJkyehVquhVt9CkH/++ederyeDwQCDwQCVSgVRFFFWVobS0lIkJCRg5cqVWLFiBdasWQMPDw9s2bIFTzzxBGpraxEXF4dly5ZBo9FgxowZkMt74hLe3t5ISUnB888/j23btvXof+ONNzB27Fibz1VWVob333/f6rOGhgZ4enrCzs4Oer0e7u7u0Ov1aGtrA4A6mUKh+K9SqcTTTz+NlpYWNDc3S0L2Ro2NjWhoaEBQUBAAQKfTYdeuXZgyZQoWL14MOzs7HDt2DFqtFjNnzsTcuXMRFhYGPz8/hIaGYvHixdi3b1+v87u5uWHz5s2IjY3t0Tds2DCEhoba5MDAwB7ji4qK4OPjg5CQEMhkMsyZMwcNDQ1obGwEgKtITEzcn5mZyaamJn7zzTfUaDQkyccff7zXk9XR0ZGFhYVctmyZ9NmQIUN45coV3rhxg/v27aNcLmd4eDibm5uZm5vLvXv3sqCggBcvXpSSKdnZ2TavTgvV1tbyySefvKski6urK8vLy1lSUsLdu3ezvr6eqampljk3YsGCBe/n5+fzzTfflCDu0tJSTpw4sc+Jly5dypycHKt9l5SUxNLSUgmalsvlXLp0KY8dO8ZPP/2U0dHRPHPmDAEwODiYPj4+zMjI6PNMuHTpUp8/Rn94+PDh/OKLL1hUVMQ1a9ZIcsrl8iV3FAxZMrm7d+9mWFjYXT2ct7e3lEfo64qMjY0d7HRbq6+v79MDDod7i7/vhv39/Zmdnd2nJVRVVXHy5MmDGg4LghBqExC5H+zv788jR4706Tpfu3aN0dHRg2UJEiAiM9fZ3PdE5vDhw5mbm9unJVRUVDAqKmow1kvpCgNagaL3WwnHjh3r0xKuXLnC3//+93ez/SRQ1AoWDwwM5PDhwwc84eTJkymKIgEwICCAw4YNs+rXaDSSlwiAo0ePpoODQ6/toKAgHjlypE9LKC8vt4LRB8g9YHFoNJqF5eXlpr/+9a8DntCS4rL46l1dz64wu+UX6w/MrdVqefz48T4tobq6mpGRkQO1BKvEiKwLrJ2/bt26ms8++wwAEBAQgGHDhsHNzQ0jRoyAp+etnKK7uztGjBgBb29vm16c0Wjs4UVaYC+S8Pf3BwD4+fkhJCQEo0aNAgD4+/sjJCQEDg4OCAwMRGVlJf785z/jxx9/7NVjDAgIQFpamuQay2Qy+Pj4YOTIkdBqtXB1dZVgOA8PD/j6+kIQhIsACmwmR11cXDZYNPX999+zsrJSMsWysjJOmTKFRUVF0rVkMeuuFvDdd99JlZ8WtmR3ANzWtKdNm0aSfPPNNxkUFMSQkBCeOHHitgfjhAkTqFarmZKSQpPJRKPRyIKCAoaEhDA0NJR5eXkcNWpUn8lRmFPHVZYS1oaGBs6ZM4djx45ldXU1q6urrdobN260qQCj0cj29naJLaixIAi0s7MjSc6cOVNKhHZty2QykuSZM2c4cuRIqlQqjho1isePH+8TaT59+jRHjx5NjUZDZ2dnhoSEMD8/n3v37uVXX33FxMREm+nx7oWSNwC8bb4i1GfPnkVGRgaMRiMqKythb29v1X7wwQdtavHChQv46KOPJKB05MiRWLVqFQBAr9dLf9vb/1fQ2b29bt06lJeXAwCuXr2KxYsXY9u2bXjooYdsIs1hYWHYu3cv5s2bh6qqKjz99NPo6OjA1KlTcfHiRSQkJLSbZbtxu1rhHACFDQ0N0Ov1MBqN0j7u2jYajbC3t7ep###Xr+Pzzz9HamoqUlNTceDAgQHDtR0dHdL/EyZMQGtrK5577jmcPHmy1+9otVps2bIFSqUSxcXF8PLywoULF/D++++jpaWl0CzbbYulGwCsysrKaureMVjwdUdHBwICAnptA8DLL78MX19feHt7IykpCYmJiaioqMCSJUtQWlraa84hIiICr732GnJychAbG4tFixbhm2++uQ5glVm2flWLn9y5c+erhw8f7uwtIdlbctJWX/f2gQMHsGHDBnR0dCA2NrZHGwBu3ryJkpISVFZWIiwsDPv378fIkSNRX1+P5557DiUlJb2uHx0dDZlMhk2bNuHSpUut5iLqkwMulHR0dPy3pWhixowZ/MMf/iCd7NOnT5fa3t7eXLx4cY/Pu0Z8ln4AfOCBBzhv3jwmJCTQz8/Pqu3r6yv5BY8//jgXLlzIRx55hDKZjF5eXlKhxMSJE3nu3Dmbh+LWrVspCAI1Gs1dFUpaSmX/fa/d5O4vTvTG48ePZ3FxsZXwlZWVluvOBODTuymVtZC7ufDYeC8VMG3atH6NHTFiBNPS0piXl8ddu3Z19QwPDGbFuLvZEsR7oQCNRmMT4e2NlUolhwwZYkl2mABsHUzhu26H9ebaW/5GWXe3FeL9qSD/k7n29p4K5+Pjc7uiimvmZ1PjHtAEc+1t271SwKFDh1hQUGAVLU6dOpX+/v7t5me5Jy9NSX4CgLkApgH4ALfe3vpVyWAwQBRFAMCUKVNgNBrxww8/VBsMhrfNHl7DHb0OdBfP1I5b7/juBCAPDg72GjdunLOXl5csMTERoaGhOH36NERRhEajQVxcHOLj4zF58mSIoojLly9Dq9UiOTkZJ06cwMqVK/Hoo4/i7NmzaGtrg4ODA1555RU8++yz0Ov1GDduHI4ePYqSkhJDfX191blz57aaTKYXzNheO+4zyZVK5YMajWahq6vrT4sWLTLl5eUxNTWVLi4uzMnJYW1tLauqqnj58mXW1dVx1qxZUqlsVlYWq6qq2Nrays2bN1OlUnH79u2sqqriwYMH+corr9DLy8uoUCiOC4Lw23p1tpdtFatSqVLHjx9fEhUV9curr77aYYHaVCoVk5KSWFRUxJiYGOr1es6bN49yuZxxcXFcv349PTw8+Mc//rHd09PzuvkXTjFjeIrBflihl/2mkMlkTgAUwi1HXiDZaPbpXVtbW39xcnKiOUByNcf6wi23X2gAgPj4eHl4ePiI4uJij5qaGv+Wlhbftra2EL1erzWZTN4k3a5everk4+ODixcvNpGs02g01wIDA6uvXr16IiIioik/P/9UZ2dnjZ+fX8OVK1dczOuZBEGQ63S6RkdHR5vRGUlPk8nUJJfLOy1tAI2CIOi7j/1/l0eTL0xHMHkAAAAASUVORK5CYII=
- // @license MIT
- // @compatible chrome
- // @compatible firefox
- // @compatible edge
- // @compatible opera
- // @compatible safari
- // @connect greasyfork.org
- // @connect sleazyfork.org
- // @connect github.com
- // @connect githubusercontent.com
- // @connect openuserjs.org
- // @grant GM_addElement
- // @grant GM_info
- // @grant GM_getValue
- // @grant GM_openInTab
- // @grant GM_setValue
- // @grant GM_registerMenuCommand
- // @grant GM_xmlhttpRequest
- // @grant GM.addElement
- // @grant GM.info
- // @grant GM.getValue
- // @grant GM.openInTab
- // @grant GM.setValue
- // @grant GM.registerMenuCommand
- // @grant GM.xmlHttpRequest
- // @match https://*/*
- // @noframes
- // @run-at document-start
- // ==/UserScript==
- (() => {
- 'use strict';
- /******************************************************************************/
- const inIframe = (() => {
- try {
- return window.self !== window.top;
- } catch (e) {
- return true;
- }
- })();
- if (inIframe) {
- return;
- }
- let userjs = self.userjs;
- /**
- * Skip text/plain documents, based on uBlock Origin `vapi.js` file
- *
- * [source code](https://github.com/gorhill/uBlock/blob/68962453ff6eec7ff109615a738beb8699b9844a/platform/common/vapi.js#L35)
- */
- if (
- (document instanceof Document ||
- (document instanceof XMLDocument && document.createElement('div') instanceof HTMLDivElement)) &&
- /^text\/html|^application\/(xhtml|xml)/.test(document.contentType || '') === true &&
- (self.userjs instanceof Object === false || userjs.UserJS !== true)
- ) {
- userjs = self.userjs = { UserJS: true };
- } else {
- console.error('[%cMagic Userscript+%c] %cERROR','color: rgb(29, 155, 240);','','color: rgb(249, 24, 128);', `MIME type is not a document, got "${document.contentType || ''}"`);
- }
- if (!(typeof userjs === 'object' && userjs.UserJS)) {
- return;
- }
- /** Native implementation exists */
- if (window.trustedTypes && window.trustedTypes.createPolicy) window.trustedTypes.createPolicy('default', { createHTML: (string) => string });
- /** [i18n directory](https://github.com/magicoflolis/Userscript-Plus/tree/master/src/_locales) */
- const translations = {
- "ar": {
- "createdby": "انشأ من قبل",
- "name": "اسم",
- "daily_installs": "التثبيت اليومي",
- "close": "يغلق",
- "filterA": "منقي",
- "max": "تحقيق أقصى قدر",
- "min": "تصغير",
- "search": "يبحث",
- "search_placeholder": "بحث في البرامج النصية",
- "install": "تثبيت",
- "issue": "إصدار جديد",
- "version_number": "الإصدار",
- "updated": "آخر تحديث",
- "total_installs": "إجمالي التثبيت",
- "ratings": "التقييمات",
- "good": "جيد",
- "ok": "جيد",
- "bad": "سيء",
- "created_date": "تم إنشاؤه",
- "redirect": "شوكة دهنية للكبار",
- "filter": "تصفية اللغات الأخرى",
- "dtime": "عرض المهلة",
- "save": "حفظ",
- "reset": "إعادة تعيين",
- "preview_code": "كود المعاينة",
- "saveFile": "احفظ الملف",
- "newTab": "علامة تبويب جديدة",
- "applies_to": "ينطبق على",
- "license": "الترخيص",
- "no_license": "لا يوجد",
- "antifeatures": "إعلانات",
- "userjs_fullscreen": "ملء الشاشة الكاملة التلقائي",
- "listing_none": "(لا يوجد)",
- "export_config": "تهيئة التصدير",
- "export_theme": "تصدير السمة",
- "import_config": "استيراد تهيئة الاستيراد",
- "import_theme": "استيراد النسق",
- "code_size": "حجم الرمز",
- "prmpt_css": "التثبيت كأسلوب المستخدم؟",
- "userjs_inject": "حقن Userscript+",
- "userjs_close": "إغلاق Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Code",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "de": {
- "createdby": "Erstellt von",
- "name": "Name",
- "daily_installs": "Tägliche Installationen",
- "close": "Schließen Sie",
- "filterA": "Filter",
- "max": "Maximieren Sie",
- "min": "minimieren",
- "search": "Suche",
- "search_placeholder": "Suche nach Userscripts",
- "install": "Installieren Sie",
- "issue": "Neue Ausgabe",
- "version_number": "Version",
- "updated": "Zuletzt aktualisiert",
- "total_installs": "Installationen insgesamt",
- "ratings": "Bewertungen",
- "good": "Gut",
- "ok": "Okay",
- "bad": "Schlecht",
- "created_date": "Erstellt",
- "redirect": "Greasy Fork für Erwachsene",
- "filter": "Andere Sprachen herausfiltern",
- "dtime": "Zeitüberschreitung anzeigen",
- "save": "Speichern Sie",
- "reset": "Zurücksetzen",
- "preview_code": "Vorschau Code",
- "saveFile": "Datei speichern",
- "newTab": "Neue Registerkarte",
- "applies_to": "Gilt für",
- "license": "Lizenz",
- "no_license": "N/A",
- "antifeatures": "Antifeatures",
- "userjs_fullscreen": "Automatischer Vollbildmodus",
- "listing_none": "(Keine)",
- "export_config": "Konfig exportieren",
- "export_theme": "Thema exportieren",
- "import_config": "Konfig importieren",
- "import_theme": "Thema importieren",
- "code_size": "Code Größe",
- "prmpt_css": "Als UserStyle installieren?",
- "userjs_inject": "Userscript+ einfügen",
- "userjs_close": "Userscript+ schließen",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Quelltext",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "en": {
- "createdby": "Created by",
- "name": "Name",
- "daily_installs": "Daily Installs",
- "close": "Close",
- "filterA": "Filter",
- "max": "Maximize",
- "min": "Minimize",
- "search": "Search",
- "search_placeholder": "Search for userscripts",
- "install": "Install",
- "issue": "New Issue",
- "version_number": "Version",
- "updated": "Last Updated",
- "total_installs": "Total Installs",
- "ratings": "Ratings",
- "good": "Good",
- "ok": "Okay",
- "bad": "Bad",
- "created_date": "Created",
- "redirect": "Greasy Fork for adults",
- "filter": "Filter out other languages",
- "dtime": "Display Timeout",
- "save": "Save",
- "reset": "Reset",
- "preview_code": "Preview Code",
- "saveFile": "Download",
- "newTab": "New Tab",
- "applies_to": "Applies to",
- "license": "License",
- "no_license": "N/A",
- "antifeatures": "Antifeatures",
- "userjs_fullscreen": "Automatic Fullscreen",
- "listing_none": "(None)",
- "export_config": "Export Config",
- "export_theme": "Export Theme",
- "import_config": "Import Config",
- "import_theme": "Import Theme",
- "code_size": "Code Size",
- "prmpt_css": "Install as UserStyle?",
- "userjs_inject": "Inject Userscript+",
- "userjs_close": "Close Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Code",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "en_GB": {
- "createdby": "Created by",
- "name": "Name",
- "daily_installs": "Daily Installs",
- "close": "Close",
- "filterA": "Filter",
- "max": "Maximize",
- "min": "Minimize",
- "search": "Search",
- "search_placeholder": "Search for userscripts",
- "install": "Install",
- "issue": "New Issue",
- "version_number": "Version",
- "updated": "Last Updated",
- "total_installs": "Total Installs",
- "ratings": "Ratings",
- "good": "Good",
- "ok": "Okay",
- "bad": "Bad",
- "created_date": "Created",
- "redirect": "Greasy Fork for adults",
- "filter": "Filter out other languages",
- "dtime": "Display Timeout",
- "save": "Save",
- "reset": "Reset",
- "preview_code": "Preview Code",
- "saveFile": "Download",
- "newTab": "New Tab",
- "applies_to": "Applies to",
- "license": "License",
- "no_license": "N/A",
- "antifeatures": "Antifeatures",
- "userjs_fullscreen": "Automatic Fullscreen",
- "listing_none": "(None)",
- "export_config": "Export Config",
- "export_theme": "Export Theme",
- "import_config": "Import Config",
- "import_theme": "Import Theme",
- "code_size": "Code Size",
- "prmpt_css": "Install as UserStyle?",
- "userjs_inject": "Inject Userscript+",
- "userjs_close": "Close Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Code",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "es": {
- "createdby": "Creado por",
- "name": "Nombre",
- "daily_installs": "Instalaciones diarias",
- "close": "Ya no se muestra",
- "filterA": "Filtro",
- "max": "Maximizar",
- "min": "Minimizar",
- "search": "Busque en",
- "search_placeholder": "Buscar userscripts",
- "install": "Instalar",
- "issue": "Nueva edición",
- "version_number": "Versión",
- "updated": "Última actualización",
- "total_installs": "Total de instalaciones",
- "ratings": "Clasificaciones",
- "good": "Bueno",
- "ok": "Ok",
- "bad": "Malo",
- "created_date": "Creado",
- "redirect": "Greasy Fork para adultos",
- "filter": "Filtrar otros idiomas",
- "dtime": "Mostrar el tiempo de espera",
- "save": "Guardar",
- "reset": "Reiniciar",
- "preview_code": "Vista previa del código",
- "saveFile": "Guardar archivo",
- "newTab": "Guardar archivo",
- "applies_to": "Se aplica a",
- "license": "Licencia",
- "no_license": "Desconocida",
- "antifeatures": "Características indeseables",
- "userjs_fullscreen": "Pantalla completa automática",
- "listing_none": "(Ninguno)",
- "export_config": "Exportar configuración",
- "export_theme": "Exportar tema",
- "import_config": "Importar configuración",
- "import_theme": "Importar tema",
- "code_size": "Código Tamaño",
- "prmpt_css": "¿Instalar como UserStyle?",
- "userjs_inject": "Inyectar Userscript+",
- "userjs_close": "Cerrar Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Código",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "fr": {
- "createdby": "Créé par",
- "name": "Nom",
- "daily_installs": "Installations quotidiennes",
- "close": "Ne plus montrer",
- "filterA": "Filtre",
- "max": "Maximiser",
- "min": "Minimiser",
- "search": "Recherche",
- "search_placeholder": "Rechercher des userscripts",
- "install": "Installer",
- "issue": "Nouveau numéro",
- "version_number": "Version",
- "updated": "Dernière mise à jour",
- "total_installs": "Total des installations",
- "ratings": "Notations",
- "good": "Bon",
- "ok": "Ok",
- "bad": "Mauvais",
- "created_date": "Créé",
- "redirect": "Greasy Fork pour les adultes",
- "filter": "Filtrer les autres langues",
- "dtime": "Délai d'affichage",
- "save": "Sauvez",
- "reset": "Réinitialiser",
- "preview_code": "Prévisualiser le code",
- "saveFile": "Enregistrer le fichier",
- "newTab": "Nouvel onglet",
- "applies_to": "S'applique à",
- "license": "Licence",
- "no_license": "N/A",
- "antifeatures": "Antifeatures",
- "userjs_fullscreen": "Plein écran automatique",
- "listing_none": "(Aucun)",
- "export_config": "Export Config",
- "export_theme": "Exporter le thème",
- "import_config": "Importer la configuration",
- "import_theme": "Importer le thème",
- "code_size": "Code Taille",
- "prmpt_css": "Installer comme UserStyle ?",
- "userjs_inject": "Injecter Userscript+",
- "userjs_close": "Fermer Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Code",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "ja": {
- "createdby": "によって作成された",
- "name": "名前",
- "daily_installs": "デイリーインストール",
- "close": "表示されなくなりました",
- "filterA": "フィルター",
- "max": "最大化",
- "min": "ミニマム",
- "search": "検索",
- "search_placeholder": "ユーザースクリプトの検索",
- "install": "インストール",
- "issue": "新刊のご案内",
- "version_number": "バージョン",
- "updated": "最終更新日",
- "total_installs": "総インストール数",
- "ratings": "レーティング",
- "good": "グッド",
- "ok": "良い",
- "bad": "悪い",
- "created_date": "作成",
- "redirect": "大人のGreasyfork",
- "filter": "他の言語をフィルタリングする",
- "dtime": "表示タイムアウト",
- "save": "拯救",
- "reset": "リセット",
- "preview_code": "コードのプレビュー",
- "saveFile": "ファイルを保存",
- "newTab": "新しいタブ",
- "applies_to": "適用対象",
- "license": "ライセンス",
- "no_license": "不明",
- "antifeatures": "アンチ機能",
- "userjs_fullscreen": "自動フルスクリーン",
- "listing_none": "(なし)",
- "export_config": "エクスポート設定",
- "export_theme": "テーマのエクスポート",
- "import_config": "設定のインポート",
- "import_theme": "テーマのインポート",
- "code_size": "コード・サイズ",
- "prmpt_css": "UserStyleとしてインストールしますか?",
- "userjs_inject": "Userscript+ を挿入",
- "userjs_close": "Userscript+ を閉じる",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "コード",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "nl": {
- "createdby": "Gemaakt door",
- "name": "Naam",
- "daily_installs": "Dagelijkse Installaties",
- "close": "Sluit",
- "filterA": "Filter",
- "max": "Maximaliseer",
- "min": "Minimaliseer",
- "search": "Zoek",
- "search_placeholder": "Zoeken naar gebruikersscripts",
- "install": "Installeer",
- "issue": "Nieuw Issue",
- "version_number": "Versie",
- "updated": "Laatste Update",
- "total_installs": "Totale Installaties",
- "ratings": "Beoordeling",
- "good": "Goed",
- "ok": "Ok",
- "bad": "Slecht",
- "created_date": "Aangemaakt",
- "redirect": "Greasy Fork voor volwassenen",
- "filter": "Filter andere talen",
- "dtime": "Weergave timeout",
- "save": "Opslaan",
- "reset": "Opnieuw instellen",
- "preview_code": "Voorbeeldcode",
- "saveFile": "Bestand opslaan",
- "newTab": "Nieuw tabblad",
- "applies_to": "Geldt voor",
- "license": "Licentie",
- "no_license": "N.v.t.",
- "antifeatures": "Functies voor eigen gewin",
- "userjs_fullscreen": "Automatisch volledig scherm",
- "listing_none": "(Geen)",
- "export_config": "Configuratie exporteren",
- "export_theme": "Thema exporteren",
- "import_config": "Configuratie importeren",
- "import_theme": "Thema importeren",
- "code_size": "Code Grootte",
- "prmpt_css": "Installeren als UserStyle?",
- "userjs_inject": "Injecteer Userscript+",
- "userjs_close": "Sluit Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Code",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "pl": {
- "createdby": "Stworzony przez",
- "name": "Nazwa",
- "daily_installs": "Codzienne instalacje",
- "close": "Zamknij",
- "filterA": "Filtr",
- "max": "Maksymalizuj",
- "min": "Minimalizuj",
- "search": "Wyszukiwanie",
- "search_placeholder": "Wyszukiwanie skryptów użytkownika",
- "install": "Instalacja",
- "issue": "Nowy numer",
- "version_number": "Wersja",
- "updated": "Ostatnia aktualizacja",
- "total_installs": "Łączna liczba instalacji",
- "ratings": "Oceny",
- "good": "Dobry",
- "ok": "Ok",
- "bad": "Zły",
- "created_date": "Utworzony",
- "redirect": "Greasy Fork dla dorosłych",
- "filter": "Odfiltruj inne języki",
- "dtime": "Limit czasu wyświetlania",
- "save": "Zapisz",
- "reset": "Reset",
- "preview_code": "Kod podglądu",
- "saveFile": "Zapisz plik",
- "newTab": "Nowa karta",
- "applies_to": "Dotyczy",
- "license": "Licencja",
- "no_license": "N/A",
- "antifeatures": "Antywzorce",
- "userjs_fullscreen": "Automatyczny pełny ekran",
- "listing_none": "(Brak)",
- "export_config": "Konfiguracja eksportu",
- "export_theme": "Motyw eksportu",
- "import_config": "Importuj konfigurację",
- "import_theme": "Importuj motyw",
- "code_size": "Kod Rozmiar",
- "prmpt_css": "Zainstalować jako UserStyle?",
- "userjs_inject": "Wstrzyknij Userscript+",
- "userjs_close": "Zamknij Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Kod",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "ru": {
- "createdby": "Сделано",
- "name": "Имя",
- "daily_installs": "Ежедневные установки",
- "close": "Больше не показывать",
- "filterA": "Фильтр",
- "max": "Максимизировать",
- "min": "Минимизировать",
- "search": "Поиск",
- "search_placeholder": "Поиск юзерскриптов",
- "install": "Установите",
- "issue": "Новый выпуск",
- "version_number": "Версия",
- "updated": "Последнее обновление",
- "total_installs": "Всего установок",
- "ratings": "Рейтинги",
- "good": "Хорошо",
- "ok": "Хорошо",
- "bad": "Плохо",
- "created_date": "Создано",
- "redirect": "Greasy Fork для взрослых",
- "filter": "Отфильтровать другие языки",
- "dtime": "Тайм-аут отображения",
- "save": "Сохранить",
- "reset": "Перезагрузить",
- "preview_code": "Предварительный просмотр кода",
- "saveFile": "Сохранить файл",
- "newTab": "Новая вкладка",
- "applies_to": "Применяется к",
- "license": "Лицензия",
- "no_license": "Недоступно",
- "antifeatures": "Нежелательная функциональность",
- "userjs_fullscreen": "Автоматический полноэкранный режим",
- "listing_none": "(нет)",
- "export_config": "Экспорт конфигурации",
- "export_theme": "Экспорт темы",
- "import_config": "Импорт конфигурации",
- "import_theme": "Импортировать тему",
- "code_size": "Код Размер",
- "prmpt_css": "Установить как UserStyle?",
- "userjs_inject": "Вставить Userscript+",
- "userjs_close": "Закрыть Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "Исходный код",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "zh": {
- "createdby": "由...制作",
- "name": "姓名",
- "daily_installs": "日常安装",
- "close": "不再显示",
- "filterA": "过滤器",
- "max": "最大化",
- "min": "最小化",
- "search": "搜索",
- "search_placeholder": "搜索用户脚本",
- "install": "安装",
- "issue": "新问题",
- "version_number": "版本",
- "updated": "最后更新",
- "total_installs": "总安装量",
- "ratings": "评级",
- "good": "好的",
- "ok": "好的",
- "bad": "不好",
- "created_date": "创建",
- "redirect": "大人的Greasyfork",
- "filter": "过滤掉其他语言",
- "dtime": "显示超时",
- "save": "拯救",
- "reset": "重置",
- "preview_code": "预览代码",
- "saveFile": "保存存档",
- "newTab": "新标签",
- "applies_to": "适用于",
- "license": "许可证",
- "no_license": "暂无",
- "antifeatures": "可能不受欢迎的功能",
- "userjs_fullscreen": "自动全屏",
- "listing_none": "(无)",
- "export_config": "导出配置",
- "export_theme": "导出主题",
- "import_config": "导入配置",
- "import_theme": "导入主题",
- "code_size": "代码 尺寸",
- "prmpt_css": "安装为用户风格?",
- "userjs_inject": "注入 Userscript+",
- "userjs_close": "关闭 Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "代码",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "zh_CN": {
- "createdby": "由...制作",
- "name": "姓名",
- "daily_installs": "日常安装",
- "close": "不再显示",
- "filterA": "过滤器",
- "max": "最大化",
- "min": "最小化",
- "search": "搜索",
- "search_placeholder": "搜索用户脚本",
- "install": "安装",
- "issue": "新问题",
- "version_number": "版本",
- "updated": "最后更新",
- "total_installs": "总安装量",
- "ratings": "评级",
- "good": "好的",
- "ok": "好的",
- "bad": "不好",
- "created_date": "创建",
- "redirect": "大人的Greasyfork",
- "filter": "过滤掉其他语言",
- "dtime": "显示超时",
- "save": "拯救",
- "reset": "重置",
- "preview_code": "预览代码",
- "saveFile": "保存存档",
- "newTab": "新标签",
- "applies_to": "适用于",
- "license": "许可证",
- "no_license": "暂无",
- "antifeatures": "可能不受欢迎的功能",
- "userjs_fullscreen": "自动全屏",
- "listing_none": "(无)",
- "export_config": "导出配置",
- "export_theme": "导出主题",
- "import_config": "导入配置",
- "import_theme": "导入主题",
- "code_size": "代码 尺寸",
- "prmpt_css": "安装为用户风格?",
- "userjs_inject": "注入 Userscript+",
- "userjs_close": "关闭 Userscript+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "代码",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- },
- "zh_TW": {
- "createdby": "由...制作",
- "name": "姓名",
- "daily_installs": "日常安装",
- "close": "不再显示",
- "filterA": "过滤器",
- "max": "最大化",
- "min": "最小化",
- "search": "搜索",
- "search_placeholder": "搜索用户脚本",
- "install": "安装",
- "issue": "新问题",
- "version_number": "版本",
- "updated": "最后更新",
- "total_installs": "总安装量",
- "ratings": "评级",
- "good": "好的",
- "ok": "好的",
- "bad": "不好",
- "created_date": "创建",
- "redirect": "大人的Greasyfork",
- "filter": "过滤掉其他语言",
- "dtime": "显示超时",
- "save": "拯救",
- "reset": "重置",
- "preview_code": "预览代码",
- "saveFile": "保存存档",
- "newTab": "新标签",
- "applies_to": "适用于",
- "license": "许可证",
- "no_license": "暂无",
- "antifeatures": "可能不受欢迎的功能",
- "userjs_fullscreen": "自动全屏",
- "listing_none": "(无)",
- "export_config": "导出配置",
- "export_theme": "导出主题",
- "import_config": "导入配置",
- "import_theme": "导入主题",
- "code_size": "代码 尺寸",
- "prmpt_css": "作為使用者樣式安裝?",
- "userjs_inject": "注入用戶腳本+",
- "userjs_close": "關閉用戶腳本+",
- "userjs_sync": "Sync",
- "userjs_autoinject": "Inject on load",
- "auto_fetch": "Fetch on load",
- "code": "代碼",
- "metadata": "Metadata",
- "preview_metadata": "Preview Metadata",
- "recommend_author": "Recommend Author",
- "recommend_other": "Recommend Others",
- "default_sort": "Default Sort"
- }
- };
- /** [source code](https://github.com/magicoflolis/Userscript-Plus/blob/master/src/sass/_main.scss) */
- const main_css = `mujs-root {
- --mujs-even-row: hsl(222, 14%, 22%);
- --mujs-odd-row: hsl(222, 14%, 11%);
- --mujs-even-err: hsl(0, 100%, 22%);
- --mujs-odd-err: hsl(0, 100%, 11%);
- --mujs-background-color: hsl(222, 14%, 33%);
- --mujs-gf-color: hsl(204, 100%, 40%);
- --mujs-sf-color: hsl(12, 86%, 50%);
- --mujs-border-b-color: hsla(0, 0%, 0%, 0);
- --mujs-gf-btn-color: hsl(211, 87%, 56%);
- --mujs-sf-btn-color: hsl(12, 86%, 50%);
- --mujs-sf-txt-color: hsl(12, 79%, 55%);
- --mujs-txt-color: hsl(0, 0%, 100%);
- --mujs-chck-color: hsla(0, 0%, 100%, 0.568);
- --mujs-chck-gf: hsla(197, 100%, 50%, 0.568);
- --mujs-chck-git: hsla(213, 13%, 16%, 0.568);
- --mujs-chck-open: hsla(12, 86%, 50%, 0.568);
- --mujs-placeholder: hsl(81, 56%, 54%);
- --mujs-position-top: unset;
- --mujs-position-bottom: 1em;
- --mujs-position-left: unset;
- --mujs-position-right: 1em;
- --mujs-font-family: Arial, Helvetica, sans-serif;
- font-family: var(--mujs-font-family, Arial, Helvetica, sans-serif);
- text-rendering: optimizeLegibility;
- word-break: normal;
- font-size: 14px;
- color: var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- mujs-root * {
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- scrollbar-color: var(--mujs-txt-color, hsl(0, 0%, 100%)) hsl(224, 14%, 21%);
- scrollbar-width: thin;
- }
- @supports not (scrollbar-width: thin) {
- mujs-root * ::-webkit-scrollbar {
- width: 1.4vw;
- height: 3.3vh;
- }
- mujs-root * ::-webkit-scrollbar-track {
- background-color: hsl(224, 14%, 21%);
- border-radius: 16px;
- margin-top: 3px;
- margin-bottom: 3px;
- box-shadow: inset 0 0 6px hsla(0, 0%, 0%, 0.3);
- }
- mujs-root * ::-webkit-scrollbar-thumb {
- border-radius: 16px;
- background-color: var(--mujs-txt-color, hsl(0, 0%, 100%));
- background-image: -webkit-linear-gradient(45deg, hsla(0, 0%, 100%, 0.2) 25%, transparent 25%, transparent 50%, hsla(0, 0%, 100%, 0.2) 50%, hsla(0, 0%, 100%, 0.2) 75%, transparent 75%, transparent);
- }
- mujs-root * ::-webkit-scrollbar-thumb:hover {
- background: var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- }
- mu-js {
- line-height: normal;
- }
- mujs-section > label,
- .mujs-homepag e,
- td.mujs-list,
- .install {
- font-size: 16px;
- }
- .install,
- .mujs-homepage {
- font-weight: 700;
- }
- mujs-section > label,
- td.mujs-list {
- font-weight: 500;
- }
- .mujs-invalid {
- border-radius: 8px !important;
- border-width: 2px !important;
- border-style: solid !important;
- border-color: hsl(0, 100%, 50%) !important;
- }
- mujs-tabs,
- mujs-column,
- mujs-row,
- .mujs-sty-flex {
- display: flex;
- }
- mujs-column,
- mujs-row {
- gap: 0.5em;
- }
- mujs-column count-frame[data-counter=greasyfork] {
- background: var(--mujs-gf-color, hsl(204, 100%, 40%));
- }
- mujs-column count-frame[data-counter=sleazyfork] {
- background: var(--mujs-sf-color, hsl(12, 86%, 50%));
- }
- mujs-column count-frame[data-counter=github] {
- background: hsl(213, 13%, 16%);
- }
- mujs-column count-frame[data-counter=openuserjs] {
- background: hsla(12, 86%, 50%, 0.568);
- }
- @media screen and (max-width: 800px) {
- mujs-column {
- flex-flow: row wrap;
- }
- }
- mujs-row {
- flex-flow: column wrap;
- }
- mu-js {
- cursor: default;
- }
- .hidden {
- display: none !important;
- z-index: -1 !important;
- }
- mujs-main {
- width: 100%;
- width: -moz-available;
- width: -webkit-fill-available;
- background: var(--mujs-background-color, hsl(222, 14%, 33%)) !important;
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- border-radius: 16px;
- }
- @media screen and (max-height: 720px) {
- mujs-main:not(.webext-page) {
- height: 100% !important;
- bottom: 0rem !important;
- right: 0rem !important;
- margin: 0rem !important;
- }
- }
- mujs-main.expanded {
- height: 100% !important;
- bottom: 0rem !important;
- }
- mujs-main:not(.webext-page) {
- position: fixed;
- height: 492px;
- }
- mujs-main:not(.webext-page):not(.expanded) {
- margin-left: 1rem;
- margin-right: 1rem;
- right: 1rem;
- bottom: 1rem;
- }
- mujs-main:not(.hidden) {
- z-index: 100000000000000000 !important;
- display: flex !important;
- flex-direction: column !important;
- }
- mujs-main > * {
- width: 100%;
- width: -moz-available;
- width: -webkit-fill-available;
- }
- mujs-main mujs-toolbar {
- order: 0;
- padding: 0.5em;
- display: flex;
- place-content: space-between;
- }
- mujs-main mujs-toolbar mujs-tabs {
- overflow: hidden;
- order: 0;
- }
- mujs-main mujs-toolbar mujs-column {
- flex-flow: row nowrap;
- order: 999999999999;
- }
- mujs-main mujs-toolbar > * {
- width: -webkit-fit-content;
- width: -moz-fit-content;
- width: fit-content;
- }
- mujs-main mujs-tabs {
- gap: 0.5em;
- text-align: center;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- flex-flow: row wrap;
- }
- mujs-main mujs-tabs mujs-tab {
- padding: 0.25em;
- min-width: 150px;
- width: -webkit-fit-content;
- width: -moz-fit-content;
- width: fit-content;
- height: -webkit-fit-content;
- height: -moz-fit-content;
- height: fit-content;
- display: flex;
- place-content: space-between;
- border: 1px solid transparent;
- border-radius: 4px;
- background: transparent;
- }
- @media screen and (max-width: 800px) {
- mujs-main mujs-tabs mujs-tab {
- min-width: 6em !important;
- }
- }
- mujs-main mujs-tabs mujs-tab.active {
- background: var(--mujs-even-row, hsl(222, 14%, 18%));
- }
- mujs-main mujs-tabs mujs-tab:not(.active):hover {
- background: var(--mujs-even-row, hsl(222, 14%, 18%));
- }
- mujs-main mujs-tabs mujs-tab mujs-host {
- float: left;
- overflow: auto;
- overflow-wrap: break-word;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- mujs-main mujs-tabs mujs-tab mu-js {
- float: right;
- }
- mujs-main mujs-tabs mujs-addtab {
- order: 999999999999;
- font-size: 20px;
- padding: 0px 0.25em;
- }
- mujs-main mujs-tabs mujs-addtab:hover {
- background: var(--mujs-even-row, hsl(222, 14%, 18%));
- }
- mujs-main mujs-tab,
- mujs-main mujs-btn,
- mujs-main input {
- width: -webkit-fit-content;
- width: -moz-fit-content;
- width: fit-content;
- height: -webkit-fit-content;
- height: -moz-fit-content;
- height: fit-content;
- }
- mujs-main input {
- background: hsla(0, 0%, 0%, 0);
- color: var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- mujs-main input:not([type=checkbox]) {
- border: transparent;
- outline: none !important;
- }
- mujs-main mujs-page,
- mujs-main textarea {
- background: inherit;
- overflow-y: auto;
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- border-radius: 5px;
- outline: none;
- font-family: monospace;
- font-size: 14px;
- }
- mujs-main mujs-page {
- padding: 0.5em;
- margin: 0.5em;
- }
- mujs-main textarea {
- overflow-y: auto;
- color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- resize: vertical;
- }
- mujs-main textarea:focus {
- outline: none;
- }
- mujs-main th,
- mujs-main .mujs-cfg *:not(input[type=password], input[type=text], input[type=number]) {
- -webkit-user-select: none !important;
- -moz-user-select: none !important;
- -ms-user-select: none !important;
- user-select: none !important;
- }
- mujs-main .mujs-footer {
- order: 3;
- overflow-x: hidden;
- text-align: center;
- border-radius: 16px;
- }
- mujs-main .mujs-footer > * {
- min-height: 50px;
- }
- mujs-main .mujs-footer .error:nth-child(even) {
- background: var(--mujs-even-err, hsl(0, 100%, 22%)) !important;
- }
- mujs-main .mujs-footer .error:nth-child(odd) {
- background: var(--mujs-odd-err, hsl(0, 100%, 11%)) !important;
- }
- mujs-main .mujs-prompt {
- align-items: center;
- justify-content: center;
- }
- mujs-main .mujs-prompt svg {
- width: 14px;
- height: 14px;
- background: transparent;
- }
- mujs-main .mujs-prompt > .prompt {
- position: absolute;
- background: var(--mujs-background-color, hsl(222, 14%, 33%)) !important;
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- border-radius: 16px;
- text-align: center;
- padding: 0.5em;
- z-index: 1;
- }
- mujs-main .mujs-prompt > .prompt .prompt-head {
- font-size: 18px;
- }
- mujs-main .mujs-prompt > .prompt .prompt-body {
- display: grid;
- grid-auto-flow: column;
- grid-gap: 0.5em;
- padding-top: 0.5em;
- }
- mujs-main .mujs-prompt > .prompt mujs-btn.prompt-deny {
- background: var(--mujs-sf-btn-color, hsl(12, 86%, 50%));
- border-color: var(--mujs-sf-btn-color, hsl(12, 86%, 50%));
- }
- mujs-main .mujs-prompt > .prompt mujs-btn.prompt-deny:hover {
- background: var(--mujs-sf-txt-color, hsl(12, 79%, 55%));
- border-color: var(--mujs-sf-txt-color, hsl(12, 79%, 55%));
- }
- mujs-main .mujs-prompt > .prompt mujs-btn.prompt-confirm {
- background: var(--mujs-gf-color, hsl(204, 100%, 40%));
- border-color: var(--mujs-gf-color, hsl(204, 100%, 40%));
- }
- mujs-main .mujs-prompt > .prompt mujs-btn.prompt-confirm:hover {
- background: var(--mujs-gf-btn-color, hsl(211, 87%, 56%));
- border-color: var(--mujs-gf-btn-color, hsl(211, 87%, 56%));
- }
- .mainframe {
- background: transparent;
- position: fixed;
- bottom: var(--mujs-position-bottom, 1rem);
- right: var(--mujs-position-right, 1rem);
- top: var(--mujs-position-top, unset);
- left: var(--mujs-position-left, unset);
- }
- .mainframe count-frame {
- width: fit-content;
- width: -moz-fit-content;
- width: -webkit-fit-content;
- height: auto;
- padding: 14px 16px;
- }
- .mainframe.error {
- opacity: 1 !important;
- }
- .mainframe.error count-frame {
- background: var(--mujs-even-err, hsl(0, 100%, 22%)) !important;
- }
- .mainframe:not(.hidden) {
- z-index: 100000000000000000 !important;
- display: block;
- }
- count-frame {
- border-radius: 1000px;
- margin: 0px 3px;
- padding: 4px 6px;
- border: 2px solid var(--mujs-border-b-color, hsla(0, 0%, 0%, 0));
- font-size: 16px;
- font-weight: 400;
- display: inline-block;
- text-align: center;
- min-width: 1em;
- background: var(--mujs-background-color, hsl(222, 14%, 33%));
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- mujs-header {
- order: 1;
- display: flex;
- border-bottom: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- padding-left: 0.5em;
- padding-right: 0.5em;
- padding-bottom: 0.5em;
- font-size: 1em;
- place-content: space-between;
- height: fit-content;
- height: -moz-fit-content;
- height: -webkit-fit-content;
- gap: 1em;
- }
- mujs-header > *:not(mujs-url) {
- height: fit-content;
- height: -moz-fit-content;
- height: -webkit-fit-content;
- }
- mujs-header mujs-url {
- order: 0;
- flex-grow: 1;
- }
- mujs-header mujs-url > input {
- width: 100%;
- height: 100%;
- background: var(--mujs-even-row, hsl(222, 14%, 18%));
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- border-radius: 4px;
- }
- mujs-header .rate-container {
- order: 1;
- }
- mujs-header .btn-frame {
- order: 999999999999;
- }
- mujs-body {
- order: 2;
- overflow-x: hidden;
- padding: 0px;
- height: 100%;
- border: 1px solid var(--mujs-border-b-color, hsla(0, 0%, 0%, 0));
- border-bottom-left-radius: 16px;
- border-bottom-right-radius: 16px;
- }
- mujs-body .mujs-ratings {
- padding: 0 0.25em;
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- border-radius: 1000px;
- width: -webkit-fit-content;
- width: -moz-fit-content;
- width: fit-content;
- }
- mujs-body mu-jsbtn {
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- mujs-body table,
- mujs-body th,
- mujs-body td {
- border-collapse: collapse;
- }
- mujs-body table {
- width: 100%;
- width: -moz-available;
- width: -webkit-fill-available;
- }
- @media screen and (max-width: 1180px) {
- mujs-body table thead > tr {
- display: table-column;
- }
- mujs-body table .frame:not(.webext-page) {
- width: 100%;
- display: flex;
- flex-flow: row wrap;
- align-items: center;
- padding-top: 0.5em;
- padding-bottom: 0.5em;
- }
- mujs-body table .frame:not(.webext-page) td {
- margin: auto;
- }
- mujs-body table .frame:not(.webext-page) td > mujs-a,
- mujs-body table .frame:not(.webext-page) td > mu-js,
- mujs-body table .frame:not(.webext-page) td > mujs-column {
- text-align: center;
- justify-content: center;
- }
- mujs-body table .frame:not(.webext-page) td > mujs-a {
- width: 100%;
- }
- }
- @media screen and (max-width: 1180px) and (max-width: 800px) {
- mujs-body table .frame:not(.webext-page) td > mujs-column {
- flex-flow: column wrap;
- }
- mujs-body table .frame:not(.webext-page) td > mujs-column > mujs-row {
- align-content: center;
- }
- mujs-body table .frame:not(.webext-page) td > mujs-column mujs-column {
- justify-content: center;
- }
- }
- @media screen and (max-width: 1180px) {
- mujs-body table .frame:not(.webext-page) td:not(.mujs-name, .install-btn) {
- width: 25%;
- }
- }
- @media screen and (max-width: 1180px) and (max-width: 800px) {
- mujs-body table .frame:not(.webext-page) td.install-btn {
- width: 100%;
- }
- }
- @media screen and (max-width: 1180px) {
- mujs-body table .frame:not(.webext-page) .mujs-name {
- width: 100%;
- }
- }
- @media screen and (max-width: 550px) {
- mujs-body table .frame:not(.webext-page) td {
- margin: 1rem !important;
- }
- mujs-body table .frame:not(.webext-page) td:not(.mujs-name, .install-btn) {
- width: auto !important;
- }
- }
- mujs-body table th {
- position: -webkit-sticky;
- position: sticky;
- top: 0;
- background: hsla(222, 14%, 33%, 0.75);
- border-bottom: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- mujs-body table th.mujs-header-name {
- width: 50%;
- }
- @media screen and (max-width: 800px) {
- mujs-body table th.mujs-header-name {
- width: auto !important;
- }
- }
- mujs-body table .frame:nth-child(even) {
- background: var(--mujs-even-row, hsl(222, 14%, 18%)) !important;
- }
- mujs-body table .frame:nth-child(even) textarea {
- background: var(--mujs-odd-row, hsl(222, 14%, 33%)) !important;
- }
- mujs-body table .frame:nth-child(odd) {
- background: var(--mujs-odd-row, hsl(222, 14%, 33%)) !important;
- }
- mujs-body table .frame:nth-child(odd) textarea {
- background: var(--mujs-even-row, hsl(222, 14%, 18%)) !important;
- }
- mujs-body table .frame:not([data-engine=sleazyfork], [data-engine=greasyfork]) mujs-a {
- color: var(--mujs-sf-txt-color, hsl(12, 79%, 55%));
- }
- mujs-body table .frame:not([data-engine=sleazyfork], [data-engine=greasyfork]) mu-jsbtn {
- background: var(--mujs-sf-btn-color, hsl(12, 86%, 50%));
- border-color: var(--mujs-sf-btn-color, hsl(12, 86%, 50%));
- }
- mujs-body table .frame:not([data-engine=sleazyfork], [data-engine=greasyfork]) mu-jsbtn:hover {
- background: var(--mujs-sf-txt-color, hsl(12, 79%, 55%));
- border-color: var(--mujs-sf-txt-color, hsl(12, 79%, 55%));
- }
- mujs-body table .frame[data-engine=sleazyfork] mujs-a, mujs-body table .frame[data-engine=greasyfork] mujs-a {
- color: var(--mujs-gf-color, hsl(197, 100%, 50%));
- }
- mujs-body table .frame[data-engine=sleazyfork] mujs-a:hover, mujs-body table .frame[data-engine=greasyfork] mujs-a:hover {
- color: var(--mujs-gf-btn-color, hsl(211, 87%, 56%));
- }
- mujs-body table .frame[data-engine=sleazyfork] mu-jsbtn, mujs-body table .frame[data-engine=greasyfork] mu-jsbtn {
- background: var(--mujs-gf-color, hsl(204, 100%, 40%));
- border-color: var(--mujs-gf-color, hsl(204, 100%, 40%));
- }
- mujs-body table .frame[data-engine=sleazyfork] mu-jsbtn:hover, mujs-body table .frame[data-engine=greasyfork] mu-jsbtn:hover {
- background: var(--mujs-gf-btn-color, hsl(211, 87%, 56%));
- border-color: var(--mujs-gf-btn-color, hsl(211, 87%, 56%));
- }
- mujs-body table .frame[data-good] mujs-a, mujs-body table .frame[data-author] mujs-a {
- color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- }
- mujs-body table .frame[data-good] mujs-a:hover, mujs-body table .frame[data-author] mujs-a:hover {
- color: hsl(81, 56%, 43%);
- }
- mujs-body table .frame[data-good] .mujs-list, mujs-body table .frame[data-author] .mujs-list {
- color: hsl(0, 0%, 100%);
- }
- mujs-body table .frame[data-good] mu-jsbtn, mujs-body table .frame[data-author] mu-jsbtn {
- color: hsl(215, 47%, 24%);
- background: var(--mujs-placeholder, hsl(81, 56%, 54%));
- border-color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- }
- mujs-body table .frame[data-good] mu-jsbtn:hover, mujs-body table .frame[data-author] mu-jsbtn:hover {
- background: hsl(81, 56%, 65%);
- border-color: hsl(81, 56%, 65%);
- }
- mujs-body table .frame.translated:not([data-good], [data-author]) mujs-a {
- color: hsl(249, 56%, 65%);
- }
- mujs-body table .frame.translated:not([data-good], [data-author]) mujs-a:hover {
- color: hsl(249, 56%, 85%);
- }
- mujs-body table .frame.translated:not([data-good], [data-author]) mu-jsbtn {
- color: hsl(215, 47%, 85%);
- background: hsl(249, 56%, 65%);
- border-color: hsl(249, 56%, 65%);
- }
- mujs-body table .frame.translated:not([data-good], [data-author]) mu-jsbtn:hover {
- background: hsl(249, 56%, 65%);
- border-color: hsl(249, 56%, 65%);
- }
- mujs-body table .frame .mujs-ratings[data-el=good] {
- border-color: hsl(120, 50%, 40%);
- background-color: hsla(120, 50%, 40%, 0.102);
- color: hsl(120, 100%, 60%);
- }
- mujs-body table .frame .mujs-ratings[data-el=ok] {
- border-color: hsl(60, 100%, 30%);
- background-color: hsla(60, 100%, 30%, 0.102);
- color: hsl(60, 100%, 50%);
- }
- mujs-body table .frame .mujs-ratings[data-el=bad] {
- border-color: hsl(0, 100%, 30%);
- background-color: hsla(0, 50%, 40%, 0.102);
- color: hsl(0, 100%, 50%);
- }
- mujs-body table .frame svg {
- width: 12px;
- height: 12px;
- fill: currentColor;
- background: transparent;
- }
- mujs-body table .frame > td:not(.mujs-name) {
- text-align: center;
- }
- mujs-body table .frame > .mujs-name > mujs-a {
- width: -webkit-fit-content;
- width: -moz-fit-content;
- width: fit-content;
- }
- mujs-body table .frame > .mujs-name mu-jsbtn,
- mujs-body table .frame > .mujs-name mu-js {
- height: -webkit-fit-content;
- height: -moz-fit-content;
- height: fit-content;
- }
- mujs-body table .frame > .mujs-name > mu-jsbtn {
- margin: auto;
- }
- mujs-body table .frame > .mujs-name > mujs-column > mu-jsbtn {
- padding: 0px 7px;
- }
- @media screen and (max-width: 800px) {
- mujs-body table .frame > .mujs-name > mujs-column > mu-jsbtn {
- width: 100%;
- }
- }
- mujs-body table .frame > .mujs-uframe > mujs-a {
- font-size: 16px;
- font-weight: 500;
- padding-left: 0.5rem;
- padding-right: 0.5rem;
- }
- mujs-body table .frame [data-el=more-info] > mujs-row {
- gap: 0.25em;
- }
- mujs-body table .frame [data-el=matches] {
- gap: 0.25em;
- max-width: 40em;
- }
- mujs-body table .frame [data-el=matches] .mujs-grants {
- display: inline-flex;
- flex-flow: row wrap;
- overflow: auto;
- overflow-wrap: break-word;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: -webkit-fit-content;
- width: -moz-fit-content;
- width: fit-content;
- max-height: 5em;
- gap: 0.2em;
- }
- mujs-body table .frame [data-el=matches] .mujs-grants > mujs-a {
- display: inline;
- }
- mujs-body table .frame [data-el=matches] .mujs-grants > mujs-a:not([data-command]) {
- cursor: default !important;
- color: var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- mujs-body table .frame [data-el=matches] .mujs-grants > mujs-a::after {
- content: ", ";
- color: var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- mujs-body table .frame [data-el=matches] .mujs-grants > mujs-a:last-child::after {
- content: "";
- }
- @media screen and (max-width: 800px) {
- mujs-body table .frame [data-el=matches] {
- align-self: center;
- width: 30em !important;
- }
- }
- mujs-body table .frame [data-name=license] {
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- width: -webkit-fit-content;
- width: -moz-fit-content;
- width: fit-content;
- }
- @media screen and (max-width: 800px) {
- mujs-body table .frame [data-name=license] {
- width: 100% !important;
- width: -moz-available !important;
- width: -webkit-fill-available !important;
- }
- }
- @media screen and (max-width: 1150px) {
- .mujs-cfg {
- margin: 0px auto 1rem auto !important;
- }
- }
- .mujs-cfg {
- height: fit-content;
- height: -moz-fit-content;
- height: -webkit-fit-content;
- }
- .mujs-cfg mujs-section {
- border-radius: 16px;
- padding: 0.5em;
- }
- .mujs-cfg mujs-section:nth-child(even) {
- background: var(--mujs-even-row, hsl(222, 14%, 18%)) !important;
- }
- .mujs-cfg mujs-section:nth-child(even) input,
- .mujs-cfg mujs-section:nth-child(even) select {
- background: var(--mujs-odd-row, hsl(222, 14%, 33%));
- }
- .mujs-cfg mujs-section:nth-child(even) select option {
- background: var(--mujs-odd-row, hsl(222, 14%, 33%));
- }
- .mujs-cfg mujs-section:nth-child(even) select option:hover {
- background: var(--mujs-even-row, hsl(222, 14%, 18%)) !important;
- }
- .mujs-cfg mujs-section:nth-child(odd) {
- background: var(--mujs-odd-row, hsl(222, 14%, 33%)) !important;
- }
- .mujs-cfg mujs-section:nth-child(odd) input,
- .mujs-cfg mujs-section:nth-child(odd) select {
- background: var(--mujs-even-row, hsl(222, 14%, 18%));
- }
- .mujs-cfg mujs-section:nth-child(odd) select option {
- background: var(--mujs-even-row, hsl(222, 14%, 18%));
- }
- .mujs-cfg mujs-section:nth-child(odd) select option:hover {
- background: var(--mujs-odd-row, hsl(222, 14%, 33%)) !important;
- }
- .mujs-cfg mujs-section[data-name=theme] .sub-section {
- border-radius: 4px;
- }
- .mujs-cfg mujs-section[data-name=theme] .sub-section:nth-child(even) {
- background: var(--mujs-even-row, hsl(222, 14%, 18%));
- }
- .mujs-cfg mujs-section[data-name=theme] .sub-section:nth-child(odd) {
- background: var(--mujs-odd-row, hsl(222, 14%, 33%));
- }
- .mujs-cfg mujs-section[data-name=theme] input,
- .mujs-cfg mujs-section[data-name=theme] select {
- background: inherit;
- }
- .mujs-cfg mujs-section[data-name=theme] select option {
- background: inherit;
- }
- .mujs-cfg mujs-section[data-name=theme] select option:hover {
- background: var(--mujs-even-row, hsl(222, 14%, 18%)) !important;
- }
- .mujs-cfg mujs-section[data-name=exp], .mujs-cfg mujs-section[data-name=blacklist] {
- display: flex;
- justify-content: space-between;
- flex-direction: column;
- gap: 0.25em;
- }
- .mujs-cfg mujs-section[data-name=exp] > mujs-btn, .mujs-cfg mujs-section[data-name=blacklist] > mujs-btn {
- width: 100%;
- width: -moz-available;
- width: -webkit-fill-available;
- }
- .mujs-cfg mujs-section[data-name=exp] > mujs-btn:hover, .mujs-cfg mujs-section[data-name=blacklist] > mujs-btn:hover {
- background: var(--mujs-even-row, hsl(222, 14%, 18%)) !important;
- }
- .mujs-cfg mujs-section input[type=text]::-webkit-input-placeholder {
- color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- }
- .mujs-cfg mujs-section input[type=text]::-moz-placeholder {
- color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- }
- .mujs-cfg mujs-section input[type=text]:-ms-input-placeholder {
- color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- }
- .mujs-cfg mujs-section input[type=text]::-ms-input-placeholder {
- color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- }
- .mujs-cfg mujs-section input[type=text]::placeholder {
- color: var(--mujs-placeholder, hsl(81, 56%, 54%));
- }
- .mujs-cfg mujs-section > label:not([data-blacklist]) {
- display: flex;
- justify-content: space-between;
- }
- .mujs-cfg mujs-section > label[data-blacklist] {
- display: grid;
- grid-auto-flow: column;
- }
- .mujs-cfg mujs-section > label[data-blacklist]:not(.new-list) {
- grid-template-columns: repeat(2, 1fr);
- }
- .mujs-cfg mujs-section > label.new-list {
- order: 999999999999;
- }
- .mujs-cfg mujs-section > label.new-list mujs-add {
- font-size: 20px;
- }
- .mujs-cfg mujs-section > label input:not([type=checkbox]) {
- font-size: 14px;
- position: relative;
- border-radius: 4px;
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- .mujs-cfg mujs-section select,
- .mujs-cfg mujs-section select option {
- color: var(--mujs-txt-color, hsl(0, 0%, 100%));
- border: 1px solid transparent;
- list-style: none;
- outline-style: none;
- pointer-events: auto;
- }
- .mujs-cfg mujs-section select {
- text-align: center;
- border-radius: 4px;
- }
- .mujs-cfg mujs-section > *.sub-section {
- padding: 0.2em;
- }
- .mujs-cfg mujs-section > *.sub-section[data-engine] {
- flex-wrap: wrap;
- }
- .mujs-cfg mujs-section > *.sub-section[data-engine] input {
- width: 100%;
- width: -moz-available;
- width: -webkit-fill-available;
- }
- .mujs-cfg mujs-section > *.sub-section input[type=text] {
- margin: 0.2em 0px;
- }
- .mujs-cfg .mujs-inlab {
- position: relative;
- width: 38px;
- }
- .mujs-cfg .mujs-inlab input[type=checkbox] {
- display: none;
- }
- .mujs-cfg .mujs-inlab input[type=checkbox]:checked + label {
- margin-left: 0;
- background: var(--mujs-chck-color, hsla(0, 0%, 100%, 0.568));
- }
- .mujs-cfg .mujs-inlab input[type=checkbox]:checked + label:before {
- right: 0px;
- }
- .mujs-cfg .mujs-inlab input[type=checkbox][data-name=greasyfork]:checked + label {
- background: var(--mujs-gf-color, hsl(204, 100%, 40%));
- }
- .mujs-cfg .mujs-inlab input[type=checkbox][data-name=sleazyfork]:checked + label {
- background: var(--mujs-sf-color, hsl(12, 86%, 50%));
- }
- .mujs-cfg .mujs-inlab input[type=checkbox][data-name=openuserjs]:checked + label {
- background: var(--mujs-chck-open, hsla(12, 86%, 50%, 0.568));
- }
- .mujs-cfg .mujs-inlab input[type=checkbox][data-name=github]:checked + label {
- background: var(--mujs-chck-git, hsla(213, 13%, 16%, 0.568));
- }
- .mujs-cfg .mujs-inlab label {
- padding: 0;
- display: block;
- overflow: hidden;
- height: 16px;
- border-radius: 20px;
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- .mujs-cfg .mujs-inlab label:before {
- content: "";
- display: block;
- width: 20px;
- height: 20px;
- margin: -2px;
- background: var(--mujs-txt-color, hsl(0, 0%, 100%));
- position: absolute;
- top: 0;
- right: 20px;
- border-radius: 20px;
- }
- .mujs-cfg .mujs-sty-flex mujs-btn {
- margin: auto;
- }
- .mujs-cfg .mujs-sty-flex mujs-btn[data-command=reset] {
- background: var(--mujs-sf-btn-color, hsl(12, 86%, 50%));
- border-color: var(--mujs-sf-btn-color, hsl(12, 86%, 50%));
- }
- .mujs-cfg .mujs-sty-flex mujs-btn[data-command=reset]:hover {
- background: var(--mujs-sf-txt-color, hsl(12, 79%, 55%));
- border-color: var(--mujs-sf-txt-color, hsl(12, 79%, 55%));
- }
- .mujs-cfg .mujs-sty-flex mujs-btn[data-command=save] {
- background: var(--mujs-gf-color, hsl(204, 100%, 40%));
- border-color: var(--mujs-gf-color, hsl(204, 100%, 40%));
- }
- .mujs-cfg .mujs-sty-flex mujs-btn[data-command=save]:hover {
- background: var(--mujs-gf-btn-color, hsl(211, 87%, 56%));
- border-color: var(--mujs-gf-btn-color, hsl(211, 87%, 56%));
- }
- .mujs-cfg:not(.webext-page) {
- margin: 1rem 25rem;
- }
- @media screen and (max-height: 720px) {
- .mujs-cfg:not(.webext-page) {
- height: 100%;
- height: -moz-available;
- height: -webkit-fill-available;
- width: 100%;
- width: -moz-available;
- width: -webkit-fill-available;
- overflow-x: auto;
- padding: 0.5em;
- }
- }
- mujs-a {
- display: inline-block;
- }
- .mujs-name {
- display: flex;
- flex-flow: column wrap;
- gap: 0.5em;
- }
- .mujs-name span {
- font-size: 0.8em !important;
- }
- mujs-btn {
- font-style: normal;
- font-weight: 500;
- font-variant: normal;
- text-transform: none;
- text-rendering: auto;
- text-align: center;
- border: 1px solid var(--mujs-txt-color, hsl(0, 0%, 100%));
- font-size: 16px;
- border-radius: 4px;
- line-height: 1;
- padding: 6px 15px;
- }
- mujs-btn svg {
- width: 14px;
- height: 14px;
- fill: var(--mujs-txt-color, hsl(0, 0%, 100%));
- }
- mu-jsbtn {
- font-size: 14px;
- border-radius: 4px;
- font-style: normal;
- padding: 7px 15%;
- font-weight: 400;
- font-variant: normal;
- line-height: normal;
- display: block;
- text-align: center;
- }
- mujs-a,
- mu-jsbtn,
- .mujs-pointer,
- .mujs-cfg mujs-section *:not(input[type=text], input[type=number], [data-theme], [data-blacklist]),
- .mainbtn,
- .mainframe,
- mujs-btn {
- cursor: pointer !important;
- }`;
- /******************************************************************************/
- // #region Console
- const con = {
- title: '[%cMagic Userscript+%c]',
- color: 'color: rgb(29, 155, 240);',
- dbg(...msg) {
- const dt = new Date();
- console.debug(
- `${con.title} %cDBG`,
- con.color,
- '',
- 'color: rgb(255, 212, 0);',
- `[${dt.getHours()}:${('0' + dt.getMinutes()).slice(-2)}:${('0' + dt.getSeconds()).slice(-2)}]`,
- ...msg
- );
- },
- err(...msg) {
- console.error(
- `${con.title} %cERROR`,
- con.color,
- '',
- 'color: rgb(249, 24, 128);',
- ...msg
- );
- const a = typeof alert !== 'undefined' && alert;
- for (const ex of msg) {
- if (typeof ex === 'object' && 'cause' in ex && a) {
- a(`[Magic Userscript+] (${ex.cause}) ${ex.message}`);
- }
- }
- },
- info(...msg) {
- console.info(
- `${con.title} %cINF`,
- con.color,
- '',
- 'color: rgb(0, 186, 124);',
- ...msg
- );
- },
- log(...msg) {
- console.log(
- `${con.title} %cLOG`,
- con.color,
- '',
- 'color: rgb(219, 160, 73);',
- ...msg
- );
- }
- };
- const { err, info } = con;
- // #endregion
- /**
- * @type { import("../typings/types.d.ts").config }
- */
- let cfg;
- const BLANK_FN = function () {};
- const BLANK_ASYNC_FN = async function () {};
- const BLANK_PAGE = 'about:blank';
- /**
- * @param {string} hn
- */
- const normalizedHostname = (hn) => hn.replace(/^www\./, '');
- /**
- * @param {string} txt
- */
- const formatURL = (txt) =>
- txt
- .split('.')
- .splice(-2)
- .join('.')
- .replace(/\/|https:/g, '');
- /**
- * @param {string} str
- */
- const getHostname = (str) => formatURL(normalizedHostname(str));
- /**
- * @type {URL | undefined}
- */
- let url;
- try {
- url = new URL(window.location.href ?? BLANK_PAGE);
- } catch {
- /* empty */
- }
- // #region Validators
- const objToStr = (obj) => Object.prototype.toString.call(obj);
- const isRegExp = (obj) => /RegExp/.test(objToStr(obj));
- const isElem = (obj) => /Element/.test(objToStr(obj));
- const isHTML = (obj) => /object HTML/.test(objToStr(obj));
- const isObj = (obj) => /Object/.test(objToStr(obj));
- const isFN = (obj) => /Function/.test(objToStr(obj));
- const isUserCSS = (str) => /\.user\.css$/.test(str);
- const isUserJS = (str) => /\.user\.js$/.test(str);
- /**
- * @type { import("../typings/types.d.ts").isNull }
- */
- const isNull = (obj) => {
- return Object.is(obj, null) || Object.is(obj, undefined);
- };
- /**
- * @type { import("../typings/types.d.ts").isBlank }
- */
- const isBlank = (obj) => {
- return (
- (typeof obj === 'string' && Object.is(obj.trim(), '')) ||
- ((obj instanceof Set || obj instanceof Map) && Object.is(obj.size, 0)) ||
- (Array.isArray(obj) && Object.is(obj.length, 0)) ||
- (isObj(obj) && Object.is(Object.keys(obj).length, 0))
- );
- };
- /**
- * @type { import("../typings/types.d.ts").isEmpty }
- */
- const isEmpty = (obj) => {
- return isNull(obj) || isBlank(obj);
- };
- // #endregion
- // #region Globals
- /**
- * https://github.com/zloirock/core-js/blob/master/packages/core-js/internals/global-this.js
- * @returns {typeof globalThis}
- */
- function globalWin() {
- const check = function (it) {
- return it && it.Math === Math && it;
- };
- return (
- check(typeof globalThis == 'object' && globalThis) ||
- check(typeof window == 'object' && window) ||
- check(typeof self == 'object' && self) ||
- check(typeof this == 'object' && this) ||
- (function () {
- return this;
- })() ||
- Function('return this')()
- );
- }
- class Safe {
- /** @type { import("../typings/UserJS.d.ts").safeHandles } */
- _safe;
- create() {
- try {
- const g = globalWin();
- /** @type { import("../typings/UserJS.d.ts").safeHandles } */
- const safe = {
- XMLHttpRequest: g.XMLHttpRequest,
- CustomEvent: g.CustomEvent,
- createElement: g.document.createElement.bind(g.document),
- createElementNS: g.document.createElementNS.bind(g.document),
- createTextNode: g.document.createTextNode.bind(g.document),
- setTimeout: g.setTimeout,
- clearTimeout: g.clearTimeout,
- navigator: g.navigator,
- scheduler: {
- postTask(callback, options) {
- if ('scheduler' in g && 'postTask' in g.scheduler) {
- return g.scheduler.postTask(callback, options);
- }
- options = Object.assign({}, options);
- if (options.delay === undefined) options.delay = 0;
- options.delay = Number(options.delay);
- if (options.delay < 0) {
- return Promise.reject(new TypeError('"delay" must be a positive number.'));
- }
- return new Promise((resolve) => {
- g.setTimeout(() => {
- resolve(callback());
- }, options.delay);
- });
- },
- yield() {
- if ('scheduler' in g && 'yield' in g.scheduler) {
- scheduler.yield();
- return g.scheduler.yield();
- }
- return new Promise((resolve) => {
- g.setTimeout(resolve, 0);
- });
- }
- },
- groupBy(arr, callback) {
- if (isFN(Object.groupBy)) {
- return Object.groupBy(arr, callback);
- }
- /** [Object.groupBy polyfill](https://gist.github.com/gtrabanco/7c97bd41aa74af974fa935bfb5044b6e) */
- return arr.reduce((acc = {}, ...args) => {
- const key = callback(...args);
- acc[key] ??= [];
- acc[key].push(args[0]);
- return acc;
- }, {});
- }
- };
- for (const [k, v] of Object.entries(safe)) {
- if (/scheduler|navigator/.test(k) || isFN(v)) continue;
- throw new Error(`Safe handles "${k}" returned "${v}"`, { cause: 'safeSelf' });
- }
- this._safe = safe;
- } catch (e) {
- err(e);
- this._safe = null;
- }
- return this._safe;
- }
- get _self() {
- return this._safe ?? this.create();
- }
- set _self(obj) {
- this._safe = obj;
- }
- }
- const { _self } = new Safe();
- // #endregion
- // #region Constants
- /**
- * @type { import("../typings/types.d.ts").cfgBase }
- */
- const cfgBase = [];
- const cfgSec = new Set();
- /** Lets highlight me :) */
- const authorID = 166061;
- /**
- * Some UserJS I personally enjoy - `https://greasyfork.org/scripts/{id}`
- */
- const goodUserJS = [
- 33005,
- 394820,
- 438684,
- 4870,
- 394420,
- 25068,
- 483444,
- 1682,
- 22587,
- 789,
- 28497,
- 386908,
- 24204,
- 404443,
- 4336,
- 368183,
- 393396,
- 473830,
- 12179,
- 423001,
- 376510,
- 23840,
- 40525,
- 6456,
- 'https://openuserjs.org/install/Patabugen/Always_Remember_Me.user.js',
- 'https://openuserjs.org/install/nokeya/Direct_links_out.user.js',
- 'https://github.com/jijirae/y2monkey/raw/main/y2monkey.user.js',
- 'https://github.com/jijirae/r2monkey/raw/main/r2monkey.user.js',
- 'https://github.com/TagoDR/MangaOnlineViewer/raw/master/Manga_OnlineViewer.user.js',
- 'https://github.com/j###s2099/konami-command/raw/master/INSTALL-USER-SCRIPT.user.js',
- 'https://github.com/TagoDR/MangaOnlineViewer/raw/master/dist/Manga_OnlineViewer_Adult.user.js'
- ];
- /** Remove UserJS from banned accounts */
- const badUserJS = [478597];
- /** Unsupport host for search engines */
- const engineUnsupported = {
- greasyfork: ['pornhub.com'],
- sleazyfork: ['pornhub.com'],
- openuserjs: [],
- github: []
- };
- const isMobile = (() => {
- if (userjs.isMobile !== undefined) {
- return userjs.isMobile;
- }
- try {
- const { navigator } = _self;
- if (navigator) {
- const { userAgent, userAgentData } = navigator;
- const { platform, mobile } = userAgentData ? Object(userAgentData) : {};
- userjs.isMobile =
- /Mobile|Tablet/.test(userAgent ? String(userAgent) : '') ||
- Boolean(mobile) ||
- /Android|Apple/.test(platform ? String(platform) : '');
- } else {
- userjs.isMobile = false;
- }
- } catch (ex) {
- userjs.isMobile = false;
- ex.cause = 'getUAData';
- err(ex);
- }
- return userjs.isMobile;
- })();
- const isGM = typeof GM !== 'undefined';
- const builtinList = {
- local: /localhost|router|###|(\d+\.){3}\d+/,
- finance:
- /school|pay|bank|money|cart|checkout|authorize|bill|wallet|venmo|zalo|skrill|bluesnap|coin|crypto|currancy|insurance|finance/,
- social: /login|join|signin|signup|sign-up|password|reset|password_reset/,
- unsupported: {
- host: 'fakku.net',
- pathname: '/hentai/.+/read/page/.+'
- }
- };
- // #endregion
- // #region DEFAULT_CONFIG
- /**
- * @type { import("../typings/types.d.ts").config }
- */
- const DEFAULT_CONFIG = {
- autofetch: true,
- autoinject: true,
- autoSort: 'daily_installs',
- clearTabCache: true,
- cache: true,
- autoexpand: false,
- filterlang: false,
- sleazyredirect: false,
- time: 10000,
- blacklist: ['userjs-local', 'userjs-finance', 'userjs-social', 'userjs-unsupported'],
- preview: {
- code: false,
- metadata: false
- },
- engines: [
- {
- enabled: true,
- name: 'greasyfork',
- query: encodeURIComponent('https://greasyfork.org/scripts/by-site/{host}.json?language=all')
- },
- {
- enabled: false,
- name: 'sleazyfork',
- query: encodeURIComponent('https://sleazyfork.org/scripts/by-site/{host}.json?language=all')
- },
- {
- enabled: false,
- name: 'openuserjs',
- query: encodeURIComponent('https://openuserjs.org/?q={host}')
- },
- {
- enabled: false,
- name: 'github',
- token: '',
- query: encodeURIComponent(
- 'https://api.github.com/search/repositories?q=topic:{domain}+topic:userscript'
- )
- }
- ],
- theme: {
- 'even-row': '',
- 'odd-row': '',
- 'even-err': '',
- 'odd-err': '',
- 'background-color': '',
- 'gf-color': '',
- 'sf-color': '',
- 'border-b-color': '',
- 'gf-btn-color': '',
- 'sf-btn-color': '',
- 'sf-txt-color': '',
- 'txt-color': '',
- 'chck-color': '',
- 'chck-gf': '',
- 'chck-git': '',
- 'chck-open': '',
- placeholder: '',
- 'position-top': '',
- 'position-bottom': '',
- 'position-left': '',
- 'position-right': '',
- 'font-family': ''
- },
- recommend: {
- author: true,
- others: true
- },
- filters: {
- ASCII: {
- enabled: false,
- name: 'Non-ASCII',
- regExp: '[^\\x00-\\x7F\\s]+'
- },
- Latin: {
- enabled: false,
- name: 'Non-Latin',
- regExp: '[^\\u0000-\\u024F\\u2000-\\u214F\\s]+'
- },
- Games: {
- enabled: false,
- name: 'Games',
- flag: 'iu',
- regExp:
- 'Aimbot|AntiGame|Agar|agar\\.io|alis\\.io|angel\\.io|ExtencionRipXChetoMalo|AposBot|DFxLite|ZTx-Lite|AposFeedingBot|AposLoader|Balz|Blah Blah|Orc Clan Script|Astro\\s*Empires|^\\s*Attack|^\\s*Battle|BiteFight|Blood\\s*Wars|Bloble|Bonk|Bots|Bots4|Brawler|\\bBvS\\b|Business\\s*Tycoon|Castle\\s*Age|City\\s*Ville|chopcoin\\.io|Comunio|Conquer\\s*Club|CosmoPulse|cursors\\.io|Dark\\s*Orbit|Dead\\s*Frontier|Diep\\.io|\\bDOA\\b|doblons\\.io|DotD|Dossergame|Dragons\\s*of\\s*Atlantis|driftin\\.io|Dugout|\\bDS[a-z]+\\n|elites\\.io|Empire\\s*Board|eRep(ublik)?|Epicmafia|Epic.*War|ExoPlanet|Falcon Tools|Feuerwache|Farming|FarmVille|Fightinfo|Frontier\\s*Ville|Ghost\\s*Trapper|Gladiatus|Goalline|Gondal|gota\\.io|Grepolis|Hobopolis|\\bhwm(\\b|_)|Ikariam|\\bIT2\\b|Jellyneo|Kapi\\s*Hospital|Kings\\s*Age|Kingdoms?\\s*of|knastv(o|oe)gel|Knight\\s*Fight|\\b(Power)?KoC(Atta?ck)?\\b|\\bKOL\\b|Kongregate|Krunker|Last\\s*Emperor|Legends?\\s*of|Light\\s*Rising|lite\\.ext\\.io|Lockerz|\\bLoU\\b|Mafia\\s*(Wars|Mofo)|Menelgame|Mob\\s*Wars|Mouse\\s*Hunt|Molehill\\s*Empire|MooMoo|MyFreeFarm|narwhale\\.io|Neopets|NeoQuest|Nemexia|\\bOGame\\b|Ogar(io)?|Pardus|Pennergame|Pigskin\\s*Empire|PlayerScripts|pokeradar\\.io|Popmundo|Po?we?r\\s*(Bot|Tools)|PsicoTSI|Ravenwood|Schulterglatze|Skribbl|slither\\.io|slitherplus\\.io|slitheriogameplay|SpaceWars|splix\\.io|Survivio|\\bSW_[a-z]+\\n|\\bSnP\\b|The\\s*Crims|The\\s*West|torto\\.io|Travian|Treasure\\s*Isl(and|e)|Tribal\\s*Wars|TW.?PRO|Vampire\\s*Wars|vertix\\.io|War\\s*of\\s*Ninja|World\\s*of\\s*####s|West\\s*Wars|wings\\.io|\\bWoD\\b|World\\s*of\\s*Dungeons|wtf\\s*battles|Wurzelimperium|Yohoho|Zombs'
- },
- SocialNetworks: {
- enabled: false,
- name: 'Social Networks',
- flag: 'iu',
- regExp:
- 'Face\\s*book|Google(\\+| Plus)|\\bHabbo|Kaskus|\\bLepra|Leprosorium|MySpace|meinVZ|odnoklassniki|Одноклассники|Orkut|sch(ue|ü)ler(VZ|\\.cc)?|studiVZ|Unfriend|Valenth|VK|vkontakte|ВКонтакте|Qzone|Twitter|TweetDeck'
- },
- Clutter: {
- enabled: false,
- name: 'Clutter',
- flag: 'iu',
- regExp:
- "^\\s*(.{1,3})\\1+\\n|^\\s*(.+?)\\n+\\2\\n*$|^\\s*.{1,5}\\n|do\\s*n('|o)?t (install|download)|nicht installieren|(just )?(\\ban? |\\b)test(ing|s|\\d|\\b)|^\\s*.{0,4}test.{0,4}\\n|\\ntest(ing)?\\s*|^\\s*(\\{@|Smolka|Hacks)|\\[\\d{4,5}\\]|free\\s*download|theme|(night|dark) ?(mode)?"
- }
- }
- };
- // #endregion
- // #region i18n
- /** @type {Map<string, string>} */
- const i18nMap = new Map();
- class i18nHandler {
- constructor() {
- for (const [k, v] of Object.entries(translations)) {
- if (!i18nMap.has(k)) i18nMap.set(k, v);
- }
- }
- /**
- * @param {string | Date | number} str
- */
- toDate(str = '') {
- const { navigator } = _self;
- return new Intl.DateTimeFormat(navigator.language).format(
- typeof str === 'string' ? new Date(str) : str
- );
- }
- /**
- * @param {number | bigint} number
- */
- toNumber(number) {
- const { navigator } = _self;
- return new Intl.NumberFormat(navigator.language).format(number);
- }
- /**
- * @type { import("../typings/UserJS.d.ts").i18n$ }
- */
- i18n$(key) {
- const { navigator } = _self;
- const current = navigator.language.split('-')[0] ?? 'en';
- try {
- return i18nMap.get(current)?.[key] ?? 'Invalid Key'
- } catch (e) {
- err(e);
- return 'error';
- }
- }
- get current() {
- const { navigator } = _self;
- return navigator.language.split('-')[0] ?? 'en';
- }
- }
- const language = new i18nHandler();
- const { i18n$ } = language;
- // #endregion
- // #region Utilities
- const union = (...arr) => [...new Set(arr.flat())];
- /**
- * @param {string} str
- */
- const decode = (str) => {
- try {
- if (decodeURI(str) !== decodeURIComponent(str)) {
- return decode(decodeURIComponent(str));
- }
- } catch (ex) {
- err(ex);
- }
- return str;
- };
- /**
- * @type { import("../typings/types.d.ts").normalizeTarget }
- */
- const normalizeTarget = (target, toQuery = true, root) => {
- if (Object.is(target, null) || Object.is(target, undefined)) {
- return [];
- }
- if (Array.isArray(target)) {
- return target;
- }
- if (typeof target === 'string') {
- return toQuery ? Array.from((root || document).querySelectorAll(target)) : Array.of(target);
- }
- if (/object HTML/.test(Object.prototype.toString.call(target))) {
- return Array.of(target);
- }
- return Array.from(target);
- };
- /**
- * @type { import("../typings/types.d.ts").qs }
- */
- const qs = (selector, root) => {
- try {
- return (root || document).querySelector(selector);
- } catch (ex) {
- err(ex);
- }
- return null;
- };
- /**
- * @type { import("../typings/types.d.ts").qsA }
- */
- const qsA = (selectors, root) => {
- try {
- return (root || document).querySelectorAll(selectors);
- } catch (ex) {
- err(ex);
- }
- return [];
- };
- /**
- * @type { import("../typings/types.d.ts").ael }
- */
- const ael = (el, type, listener, options = {}) => {
- for (const elem of normalizeTarget(el).filter(isHTML)) {
- if (isMobile && type === 'click') {
- elem.addEventListener('touchstart', listener, options);
- continue;
- }
- elem.addEventListener(type, listener, options);
- }
- };
- /**
- * @type { import("../typings/types.d.ts").formAttrs }
- */
- const formAttrs = (elem, attr = {}) => {
- if (!elem) {
- return elem;
- }
- for (const key in attr) {
- if (typeof attr[key] === 'object') {
- formAttrs(elem[key], attr[key]);
- } else if (isFN(attr[key])) {
- if (/^on/.test(key)) {
- elem[key] = attr[key];
- continue;
- }
- ael(elem, key, attr[key]);
- } else if (key === 'class') {
- elem.className = attr[key];
- } else {
- elem[key] = attr[key];
- }
- }
- return elem;
- };
- /**
- * @type { import("../typings/types.d.ts").make }
- */
- const make = (tagName, cname, attrs) => {
- let el;
- try {
- const { createElement } = _self;
- el = createElement(tagName);
- if (!isEmpty(cname)) {
- if (typeof cname === 'string') {
- el.className = cname;
- } else if (isObj(cname)) {
- formAttrs(el, cname);
- }
- }
- if (!isEmpty(attrs)) {
- if (typeof attrs === 'string') {
- el.textContent = attrs;
- } else if (isObj(attrs)) {
- formAttrs(el, attrs);
- }
- }
- } catch (ex) {
- if (ex instanceof DOMException) throw new Error(`${ex.name}: ${ex.message}`, { cause: 'make' });
- ex.cause = 'make';
- err(ex);
- }
- return el;
- };
- const $info = (() => {
- if (isGM) {
- if (isObj(GM.info)) {
- return GM.info;
- } else if (isObj(GM_info)) {
- return GM_info;
- }
- }
- return {
- script: {
- icon: '',
- name: 'Magic Userscript+',
- namespace: 'https://github.com/magicoflolis/Userscript-Plus',
- updateURL: 'https://github.com/magicoflolis/Userscript-Plus/raw/master/dist/magic-userjs.js',
- version: 'Bookmarklet',
- bugs: 'https://github.com/magicoflolis/Userscript-Plus/issues'
- }
- };
- })();
- // #endregion
- /**
- * @type { import("../typings/types.d.ts").dom }
- */
- const dom = {
- attr(target, attr, value = undefined) {
- for (const elem of normalizeTarget(target).filter(isHTML)) {
- if (value === undefined) {
- return elem.getAttribute(attr);
- }
- if (value === null) {
- elem.removeAttribute(attr);
- } else {
- elem.setAttribute(attr, value);
- }
- }
- },
- prop(target, prop, value = undefined) {
- for (const elem of normalizeTarget(target).filter(isHTML)) {
- if (value === undefined) {
- return elem[prop];
- }
- elem[prop] = value;
- }
- },
- text(target, text) {
- const targets = normalizeTarget(target).filter(isHTML);
- if (text === undefined) {
- return targets.length !== 0 ? targets[0].textContent : undefined;
- }
- for (const elem of targets) {
- elem.textContent = text;
- }
- },
- remove(target) {
- normalizeTarget(target)
- .filter(isHTML)
- .some((elem) => elem.remove());
- },
- cl: {
- add(target, token) {
- token = normalizeTarget(token, false);
- return normalizeTarget(target)
- .filter(isHTML)
- .some((elem) => elem.classList.add(...token));
- },
- remove(target, token) {
- token = normalizeTarget(token, false);
- return normalizeTarget(target)
- .filter(isHTML)
- .some((elem) => elem.classList.remove(...token));
- },
- toggle(target, token, force) {
- let r;
- for (const elem of normalizeTarget(target).filter(isHTML)) {
- r = elem.classList.toggle(token, force);
- }
- return r;
- },
- has(target, token) {
- return normalizeTarget(target)
- .filter(isHTML)
- .some((elem) => elem.classList.contains(token));
- }
- }
- };
- //#region Icon SVGs
- const iconSVG = {
- close: {
- viewBox: '0 0 384 512',
- html: '<path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/>'
- },
- code: {
- viewBox: '0 0 640 512',
- html: '<path d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/>'
- },
- collapse: {
- viewBox: '0 0 448 512',
- html: '<path d="M160 64c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96zM32 320c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM352 64c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 320c-17.7 0-32 14.3-32 32l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0z"/>'
- },
- download: {
- viewBox: '0 0 384 512',
- html: '<path d="M64 0C28.7 0 0 28.7 0 64L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-288-128 0c-17.7 0-32-14.3-32-32L224 0 64 0zM256 0l0 128 128 0L256 0zM216 232l0 102.1 31-31c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-72 72c-9.4 9.4-24.6 9.4-33.9 0l-72-72c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l31 31L168 232c0-13.3 10.7-24 24-24s24 10.7 24 24z"/>'
- },
- expand: {
- viewBox: '0 0 448 512',
- html: '<path d="M32 32C14.3 32 0 46.3 0 64l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-64 64 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 32zM64 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 96c0 17.7 14.3 32 32 32l96 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-64 0 0-64zM320 32c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0 0 64c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32l-96 0zM448 352c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 64-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l96 0c17.7 0 32-14.3 32-32l0-96z"/>'
- },
- gear: {
- viewBox: '0 0 512 512',
- html: '<path d="M495.9 166.6c3.2 8.7 .5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6c-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2c-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8c-13.8 2.3-28 3.5-42.5 3.5s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4L83.1 425.9c-8.8 2.8-18.6 .3-24.5-6.8c-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1c-6.1-11-11.4-22.4-15.8-34.3c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.6 273.1 64 264.6 64 256s.6-17.1 1.7-25.4L22.4 191.2c-6.9-6.2-9.6-15.9-6.4-24.6c4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2c5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1c2-9.1 9-16.3 18.2-17.8C227.3 1.2 241.5 0 256 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8c8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM256 336a80 80 0 1 0 0-160 80 80 0 1 0 0 160z"/>'
- },
- github: {
- viewBox: '0 0 496 512',
- html: '<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3 .3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5 .3-6.2 2.3zm44.2-1.7c-2.9 .7-4.9 2.6-4.6 4.9 .3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3 .7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3 .3 2.9 2.3 3.9 1.6 1 3.6 .7 4.3-.7 .7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3 .7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3 .7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/>'
- },
- globe: {
- viewBox: '0 0 512 512',
- html: '<path d="M352 256c0 22.2-1.2 43.6-3.3 64l-185.3 0c-2.2-20.4-3.3-41.8-3.3-64s1.2-43.6 3.3-64l185.3 0c2.2 20.4 3.3 41.8 3.3 64zm28.8-64l123.1 0c5.3 20.5 8.1 41.9 8.1 64s-2.8 43.5-8.1 64l-123.1 0c2.1-20.6 3.2-42 3.2-64s-1.1-43.4-3.2-64zm112.6-32l-116.7 0c-10-63.9-29.8-117.4-55.3-151.6c78.3 20.7 142 77.5 171.9 151.6zm-149.1 0l-176.6 0c6.1-36.4 15.5-68.6 27-94.7c10.5-23.6 22.2-40.7 33.5-51.5C239.4 3.2 248.7 0 256 0s16.6 3.2 27.8 13.8c11.3 10.8 23 27.9 33.5 51.5c11.6 26 20.9 58.2 27 94.7zm-209 0L18.6 160C48.6 85.9 112.2 29.1 190.6 8.4C165.1 42.6 145.3 96.1 135.3 160zM8.1 192l123.1 0c-2.1 20.6-3.2 42-3.2 64s1.1 43.4 3.2 64L8.1 320C2.8 299.5 0 278.1 0 256s2.8-43.5 8.1-64zM194.7 446.6c-11.6-26-20.9-58.2-27-94.6l176.6 0c-6.1 36.4-15.5 68.6-27 94.6c-10.5 23.6-22.2 40.7-33.5 51.5C272.6 508.8 263.3 512 256 512s-16.6-3.2-27.8-13.8c-11.3-10.8-23-27.9-33.5-51.5zM135.3 352c10 63.9 29.8 117.4 55.3 151.6C112.2 482.9 48.6 426.1 18.6 352l116.7 0zm358.1 0c-30 74.1-93.6 130.9-171.9 151.6c25.5-34.2 45.2-87.7 55.3-151.6l116.7 0z"/>'
- },
- install: {
- viewBox: '0 0 512 512',
- html: '<path d="M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 242.7-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7 288 32zM64 352c-35.3 0-64 28.7-64 64l0 32c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-32c0-35.3-28.7-64-64-64l-101.5 0-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352 64 352zm368 56a24 24 0 1 1 0 48 24 24 0 1 1 0-48z"/>'
- },
- issue: {
- viewBox: '0 0 512 512',
- html: '<path d="M256 0c53 0 96 43 96 96l0 3.6c0 15.7-12.7 28.4-28.4 28.4l-135.1 0c-15.7 0-28.4-12.7-28.4-28.4l0-3.6c0-53 43-96 96-96zM41.4 105.4c12.5-12.5 32.8-12.5 45.3 0l64 64c.7 .7 1.3 1.4 1.9 2.1c14.2-7.3 30.4-11.4 47.5-11.4l112 0c17.1 0 33.2 4.1 47.5 11.4c.6-.7 1.2-1.4 1.9-2.1l64-64c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3l-64 64c-.7 .7-1.4 1.3-2.1 1.9c6.2 12 10.1 25.3 11.1 39.5l64.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c0 24.6-5.5 47.8-15.4 68.6c2.2 1.3 4.2 2.9 6 4.8l64 64c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0l-63.1-63.1c-24.5 21.8-55.8 36.2-90.3 39.6L272 240c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 239.2c-34.5-3.4-65.8-17.8-90.3-39.6L86.6 502.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l64-64c1.9-1.9 3.9-3.4 6-4.8C101.5 367.8 96 344.6 96 320l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64.3 0c1.1-14.1 5-27.5 11.1-39.5c-.7-.6-1.4-1.2-2.1-1.9l-64-64c-12.5-12.5-12.5-32.8 0-45.3z"/>'
- },
- minus: {
- viewBox: '0 0 448 512',
- html: '<path d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/>'
- },
- nav: {
- viewBox: '0 0 448 512',
- html: '<path d="M0 96C0 78.3 14.3 64 32 64l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32L32 448c-17.7 0-32-14.3-32-32s14.3-32 32-32l384 0c17.7 0 32 14.3 32 32z"/>'
- },
- pager: {
- viewBox: '0 0 512 512',
- html: '<path d="M0 128C0 92.7 28.7 64 64 64l384 0c35.3 0 64 28.7 64 64l0 256c0 35.3-28.7 64-64 64L64 448c-35.3 0-64-28.7-64-64L0 128zm64 32l0 64c0 17.7 14.3 32 32 32l320 0c17.7 0 32-14.3 32-32l0-64c0-17.7-14.3-32-32-32L96 128c-17.7 0-32 14.3-32 32zM80 320c-13.3 0-24 10.7-24 24s10.7 24 24 24l56 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-56 0zm136 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l48 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-48 0z"/>'
- },
- verified: {
- viewBox: '0 0 56 56',
- fill: 'currentColor',
- stroke: 'currentColor',
- html: '<g stroke-width="0"/><g stroke-linecap="round" stroke-linejoin="round"/><g><path d="M 23.6641 52.3985 C 26.6407 55.375 29.3594 55.3516 32.3126 52.3985 L 35.9219 48.8125 C 36.2969 48.4610 36.6250 48.3203 37.1172 48.3203 L 42.1797 48.3203 C 46.3749 48.3203 48.3204 46.3985 48.3204 42.1797 L 48.3204 37.1172 C 48.3204 36.625 48.4610 36.2969 48.8124 35.9219 L 52.3749 32.3125 C 55.3749 29.3594 55.3514 26.6407 52.3749 23.6641 L 48.8124 20.0547 C 48.4610 19.7031 48.3204 19.3516 48.3204 18.8829 L 48.3204 13.7969 C 48.3204 9.625 46.3985 7.6563 42.1797 7.6563 L 37.1172 7.6563 C 36.6250 7.6563 36.2969 7.5391 35.9219 7.1875 L 32.3126 3.6016 C 29.3594 .6250 26.6407 .6485 23.6641 3.6016 L 20.0547 7.1875 C 19.7032 7.5391 19.3516 7.6563 18.8828 7.6563 L 13.7969 7.6563 C 9.6016 7.6563 7.6563 9.5782 7.6563 13.7969 L 7.6563 18.8829 C 7.6563 19.3516 7.5391 19.7031 7.1876 20.0547 L 3.6016 23.6641 C .6251 26.6407 .6485 29.3594 3.6016 32.3125 L 7.1876 35.9219 C 7.5391 36.2969 7.6563 36.625 7.6563 37.1172 L 7.6563 42.1797 C 7.6563 46.3750 9.6016 48.3203 13.7969 48.3203 L 18.8828 48.3203 C 19.3516 48.3203 19.7032 48.4610 20.0547 48.8125 Z M 26.2891 49.7734 L 21.8828 45.3438 C 21.3672 44.8047 20.8282 44.5938 20.1016 44.5938 L 13.7969 44.5938 C 11.7110 44.5938 11.3828 44.2656 11.3828 42.1797 L 11.3828 35.875 C 11.3828 35.1719 11.1719 34.6329 10.6563 34.1172 L 6.2266 29.7109 C 4.7501 28.2109 4.7501 27.7891 6.2266 26.2891 L 10.6563 21.8829 C 11.1719 21.3672 11.3828 20.8282 11.3828 20.1016 L 11.3828 13.7969 C 11.3828 11.6875 11.6876 11.3829 13.7969 11.3829 L 20.1016 11.3829 C 20.8282 11.3829 21.3672 11.1953 21.8828 10.6563 L 26.2891 6.2266 C 27.7891 4.7500 28.2110 4.7500 29.7110 6.2266 L 34.1172 10.6563 C 34.6328 11.1953 35.1719 11.3829 35.8750 11.3829 L 42.1797 11.3829 C 44.2657 11.3829 44.5938 11.7109 44.5938 13.7969 L 44.5938 20.1016 C 44.5938 20.8282 44.8282 21.3672 45.3439 21.8829 L 49.7733 26.2891 C 51.2498 27.7891 51.2498 28.2109 49.7733 29.7109 L 45.3439 34.1172 C 44.8282 34.6329 44.5938 35.1719 44.5938 35.875 L 44.5938 42.1797 C 44.5938 44.2656 44.2657 44.5938 42.1797 44.5938 L 35.8750 44.5938 C 35.1719 44.5938 34.6328 44.8047 34.1172 45.3438 L 29.7110 49.7734 C 28.2110 51.2500 27.7891 51.2500 26.2891 49.7734 Z M 24.3438 39.2266 C 25.0235 39.2266 25.5391 38.9453 25.8907 38.5234 L 38.8985 20.3360 C 39.1563 19.9609 39.2969 19.5391 39.2969 19.1407 C 39.2969 18.1094 38.5001 17.2891 37.4219 17.2891 C 36.6485 17.2891 36.2266 17.5469 35.7579 18.2266 L 24.2735 34.3985 L 18.3438 27.8594 C 17.9454 27.4141 17.5001 27.2266 16.9141 27.2266 C 15.7657 27.2266 14.9454 28.0000 14.9454 29.0782 C 14.9454 29.5469 15.1094 29.9922 15.4376 30.3203 L 22.8907 38.6172 C 23.2423 38.9922 23.6876 39.2266 24.3438 39.2266 Z"/></g>'
- },
- refresh: {
- viewBox: '0 0 512 512',
- fill: 'currentColor',
- html: '<path d="M463.5 224l8.5 0c13.3 0 24-10.7 24-24l0-128c0-9.7-5.8-18.5-14.8-22.2s-19.3-1.7-26.2 5.2L413.4 96.6c-87.6-86.5-228.7-86.2-315.8 1c-87.5 87.5-87.5 229.3 0 316.8s229.3 87.5 316.8 0c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0c-62.5 62.5-163.8 62.5-226.3 0s-62.5-163.8 0-226.3c62.2-62.2 162.7-62.5 225.3-1L327 183c-6.9 6.9-8.9 17.2-5.2 26.2s12.5 14.8 22.2 14.8l119.5 0z"/>'
- },
- load(type, container) {
- const { createElementNS } = _self;
- const svgElem = createElementNS('http://www.w3.org/2000/svg', 'svg');
- for (const [k, v] of Object.entries(iconSVG[type])) {
- if (k === 'html') {
- continue;
- }
- svgElem.setAttributeNS(null, k, v);
- }
- try {
- if (typeof iconSVG[type].html === 'string') {
- svgElem.innerHTML = iconSVG[type].html;
- svgElem.setAttribute('id', `mujs_${type ?? 'Unknown'}`);
- }
- // eslint-disable-next-line no-unused-vars
- } catch (ex) {
- /* empty */
- }
- if (container) {
- container.appendChild(svgElem);
- return svgElem;
- }
- return svgElem.outerHTML;
- }
- };
- //#endregion
- /**
- * @type { import("../typings/UserJS.d.ts").StorageSystem }
- */
- const StorageSystem = {
- prefix: 'MUJS',
- events: new Set(),
- getItem(key) {
- return window.localStorage.getItem(key);
- },
- has(key) {
- return !this.getItem(key);
- },
- setItem(key, value) {
- window.localStorage.setItem(key, value);
- },
- remove(key) {
- window.localStorage.removeItem(key);
- },
- async setValue(key, v) {
- if (!v) {
- return;
- }
- v = typeof v === 'string' ? v : JSON.stringify(v);
- if (isGM) {
- if (isFN(GM.setValue)) {
- await GM.setValue(key, v);
- } else if (isFN(GM_setValue)) {
- GM_setValue(key, v);
- }
- } else {
- this.setItem(`${this.prefix}-${key}`, v);
- }
- },
- async getValue(key, def = {}) {
- try {
- if (isGM) {
- let GMType;
- if (isFN(GM.getValue)) {
- GMType = await GM.getValue(key, JSON.stringify(def));
- } else if (isFN(GM_getValue)) {
- GMType = GM_getValue(key, JSON.stringify(def));
- }
- if (!isNull(GMType)) {
- return JSON.parse(GMType);
- }
- }
- return this.has(`${this.prefix}-${key}`)
- ? JSON.parse(this.getItem(`${this.prefix}-${key}`))
- : def;
- } catch (ex) {
- ex.cause = 'getValue';
- err(ex);
- return def;
- }
- }
- };
- const Command = {
- cmds: new Set(),
- register(text, command) {
- if (!isGM) {
- return;
- }
- if (isFN(command)) {
- if (this.cmds.has(command)) {
- return;
- }
- this.cmds.add(command);
- }
- if (isFN(GM.registerMenuCommand)) {
- GM.registerMenuCommand(text, command);
- } else if (isFN(GM_registerMenuCommand)) {
- GM_registerMenuCommand(text, command);
- }
- }
- };
- /**
- * @type { import("../typings/UserJS.d.ts").Network }
- */
- const Network = {
- async req(url, method = 'GET', responseType = 'json', data, useFetch = false) {
- if (isEmpty(url)) {
- throw new Error('"url" parameter is empty');
- }
- data = Object.assign({}, data);
- method = this.bscStr(method, false);
- responseType = this.bscStr(responseType, true);
- const params = {
- method,
- ...data
- };
- if (isGM && !useFetch) {
- if (params.credentials) {
- Object.assign(params, {
- anonymous: false
- });
- if (Object.is(params.credentials, 'omit')) {
- Object.assign(params, {
- anonymous: true
- });
- }
- delete params.credentials;
- }
- } else if (params.onprogress) {
- delete params.onprogress;
- }
- return new Promise((resolve, reject) => {
- if (isGM && !useFetch) {
- Network.xmlRequest({
- url,
- responseType,
- ...params,
- onerror: (r_1) => {
- reject(new Error(`${r_1.status} ${url}`));
- },
- onload: (r_1) => {
- if (r_1.status !== 200) reject(new Error(`${r_1.status} ${url}`));
- if (responseType.match(/basic/)) resolve(r_1);
- resolve(r_1.response);
- }
- });
- } else {
- fetch(url, params)
- .then((response_1) => {
- if (!response_1.ok) reject(response_1);
- const check = (str_2 = 'text') => {
- return isFN(response_1[str_2]) ? response_1[str_2]() : response_1;
- };
- if (responseType.match(/buffer/)) {
- resolve(check('arrayBuffer'));
- } else if (responseType.match(/json/)) {
- resolve(check('json'));
- } else if (responseType.match(/text/)) {
- resolve(check('text'));
- } else if (responseType.match(/blob/)) {
- resolve(check('blob'));
- } else if (responseType.match(/formdata/)) {
- resolve(check('formData'));
- } else if (responseType.match(/clone/)) {
- resolve(check('clone'));
- } else if (responseType.match(/document/)) {
- const respTxt = check('text');
- const domParser = new DOMParser();
- if (respTxt instanceof Promise) {
- respTxt.then((txt) => {
- const doc = domParser.parseFromString(txt, 'text/html');
- resolve(doc);
- });
- } else {
- const doc = domParser.parseFromString(respTxt, 'text/html');
- resolve(doc);
- }
- } else {
- resolve(response_1);
- }
- })
- .catch(reject);
- }
- });
- },
- format(bytes, decimals = 2) {
- if (Number.isNaN(bytes)) return `0 ${this.sizes[0]}`;
- const k = ####;
- const dm = decimals < 0 ? 0 : decimals;
- const i = Math.floor(Math.log(bytes) / Math.log(k));
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${this.sizes[i]}`;
- },
- sizes: ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
- async xmlRequest(details) {
- if (isGM) {
- if (isFN(GM.xmlHttpRequest)) {
- return GM.xmlHttpRequest(details);
- } else if (isFN(GM_xmlhttpRequest)) {
- return GM_xmlhttpRequest(details);
- }
- }
- return await new Promise((resolve, reject) => {
- const { XMLHttpRequest } = _self;
- const req = new XMLHttpRequest();
- let method = 'GET';
- let url = BLANK_PAGE;
- let body;
- for (const [key, value] of Object.entries(details)) {
- if (key === 'onload') {
- req.addEventListener('load', () => {
- if (isFN(value)) {
- value(req);
- }
- resolve(req);
- });
- } else if (key === 'onerror') {
- req.addEventListener('error', (evt) => {
- if (isFN(value)) {
- value(evt);
- }
- reject(evt);
- });
- } else if (key === 'onabort') {
- req.addEventListener('abort', (evt) => {
- if (isFN(value)) {
- value(evt);
- }
- reject(evt);
- });
- } else if (key === 'onprogress') {
- req.addEventListener('progress', value);
- } else if (key === 'responseType') {
- if (value === 'buffer') {
- req.responseType = 'arraybuffer';
- } else {
- req.responseType = value;
- }
- } else if (key === 'method') {
- method = value;
- } else if (key === 'url') {
- url = value;
- } else if (key === 'body') {
- body = value;
- }
- }
- req.open(method, url);
- if (isEmpty(req.responseType)) {
- req.responseType = 'text';
- }
- if (body) {
- req.send(body);
- } else {
- req.send();
- }
- });
- },
- bscStr(str = '', lowerCase = true) {
- const txt = str[lowerCase ? 'toLowerCase' : 'toUpperCase']();
- return txt.replaceAll(/\W/g, '');
- }
- };
- const Counter = {
- cnt: {
- total: {
- count: 0
- }
- },
- set(engine) {
- if (!this.cnt[engine.name]) {
- const counter = make('count-frame', engine.enabled ? '' : 'hidden', {
- dataset: {
- counter: engine.name
- },
- title: decode(engine.query ?? engine.url),
- textContent: '0'
- });
- this.cnt[engine.name] = {
- root: counter,
- count: 0
- };
- return counter;
- }
- return this.cnt[engine.name].root;
- },
- update(count, engine) {
- this.cnt[engine.name].count += count;
- this.cnt.total.count += count;
- this.updateAll();
- },
- updateAll() {
- for (const v of Object.values(this.cnt)) dom.text(v.root, v.count);
- },
- reset() {
- for (const [k, v] of Object.entries(this.cnt)) {
- dom.text(v.root, 0);
- v.count = 0;
- const engine = cfg.engines.find((engine) => k === engine.name);
- if (engine) {
- dom.cl[engine.enabled ? 'remove' : 'add'](v.root, 'hidden');
- }
- }
- }
- };
- // #region Container
- /**
- * @type { import("../typings/UserJS.d.ts").Container }
- */
- class Container {
- webpage;
- host;
- ready;
- injected;
- shadowRoot;
- supported;
- frame;
- userjsCache;
- root;
- unsaved;
- isBlacklisted;
- rebuild;
- opacityMin;
- opacityMax;
- constructor() {
- this.remove = this.remove.bind(this);
- this.refresh = this.refresh.bind(this);
- this.showError = this.showError.bind(this);
- this.toElem = this.toElem.bind(this);
- this.webpage = url;
- this.host = getHostname(url?.hostname ?? BLANK_PAGE);
- this.ready = false;
- this.injected = false;
- this.shadowRoot = undefined;
- this.supported = isFN(make('main-userjs').attachShadow);
- this.frame = this.supported
- ? make('main-userjs', {
- dataset: {
- insertedBy: $info.script.name,
- role: 'primary-container'
- }
- })
- : make('iframe', 'mujs-iframe', {
- dataset: {
- insertedBy: $info.script.name,
- role: 'primary-iframe'
- },
- loading: 'lazy',
- src: BLANK_PAGE,
- style:
- 'position: fixed;bottom: 1rem;right: 1rem;height: 525px;width: 90%;margin: 0px 1rem;z-index: 100000000000000020 !important;',
- onload: (iFrame) => {
- /**
- * @type { HTMLIFrameElement }
- */
- const target = iFrame.target;
- if (!target.contentDocument) {
- return;
- }
- this.shadowRoot = target.contentDocument.documentElement;
- this.ready = true;
- dom.cl.add([this.shadowRoot, target.contentDocument.body], 'mujs-iframe');
- }
- });
- if (this.supported) {
- this.shadowRoot = this.frame.attachShadow({ mode: 'closed' });
- this.ready = true;
- }
- this.hostCache = new Map();
- this.userjsCache = new Map();
- this.root = make('mujs-root');
- this.unsaved = false;
- this.isBlacklisted = false;
- this.rebuild = false;
- this.opacityMin = '0.15';
- this.opacityMax = '1';
- this.elementsReady = this.init();
- const Timeout = class {
- constructor() {
- this.ids = [];
- }
- set(delay, reason) {
- const { setTimeout } = _self;
- return new Promise((resolve, reject) => {
- const id = setTimeout(() => {
- Object.is(reason, null) || Object.is(reason, undefined) ? resolve() : reject(reason);
- this.clear(id);
- }, delay);
- this.ids.push(id);
- });
- }
- clear(...ids) {
- const { clearTimeout } = _self;
- this.ids = this.ids.filter((id) => {
- if (ids.includes(id)) {
- clearTimeout(id);
- return false;
- }
- return true;
- });
- }
- };
- this.timeouts = {
- frame: new Timeout(),
- mouse: new Timeout()
- };
- this.injFN = BLANK_FN;
- window.addEventListener('beforeunload', this.remove);
- }
- /**
- * @param { function(): * } callback
- * @param { Document } doc
- */
- async inject(callback, doc) {
- if (this.checkBlacklist(this.host)) {
- err(`Blacklisted "${this.host}"`);
- this.remove();
- return;
- }
- if (!this.shadowRoot) {
- return;
- }
- if (doc === null) {
- return;
- }
- while (this.ready === false) {
- await new Promise((resolve) => requestAnimationFrame(resolve));
- }
- try {
- doc.documentElement.appendChild(this.frame);
- if (this.injected) {
- if (isFN(this.injFN.build)) {
- this.injFN.build();
- }
- return;
- }
- this.shadowRoot.append(this.root);
- if (isNull(this.loadCSS(main_css, 'primary-stylesheet')))
- throw new Error('Failed to initialize script!', { cause: 'loadCSS' });
- this.injected = true;
- this.initFn();
- if (isFN(callback) && this.elementsReady) this.injFN = callback.call(this, this.shadowRoot);
- } catch (ex) {
- err(ex);
- this.remove();
- }
- }
- initFn() {
- this.setTheme();
- Counter.cnt.total.root = this.mainbtn;
- if (this.countframe)
- for (const engine of cfg.engines) this.countframe.append(Counter.set(engine));
- const { cfgpage, table, supported, frame, refresh, hostCache, urlBar, host } = this;
- class Tabs {
- /**
- * @param { HTMLElement } root
- */
- constructor(root) {
- /**
- * @type { Set<HTMLElement> }
- */
- this.pool = new Set();
- this.blank = BLANK_PAGE;
- this.protocal = 'mujs:';
- this.protoReg = new RegExp(`${this.protocal}(.+)`, 'i');
- this.el = {
- add: make('mujs-addtab', {
- textContent: '+',
- dataset: {
- command: 'new-tab'
- }
- }),
- head: make('mujs-tabs'),
- root
- };
- this.el.head.append(this.el.add);
- this.el.root.append(this.el.head);
- this.custom = BLANK_FN;
- }
- /**
- * @param {string} hostname
- */
- getTab(hostname) {
- return [...this.pool].find(({ dataset }) => hostname === dataset.host);
- }
- getActive() {
- return [...this.pool].find((tab) => tab.classList.contains('active'));
- }
- /**
- * @param {string} hostname
- */
- intFN(hostname) {
- const p = this.protoReg.exec(hostname);
- if (!p) {
- return;
- }
- if (p[1] === 'settings') {
- dom.cl.remove(cfgpage, 'hidden');
- dom.cl.add(table, 'hidden');
- urlBar.placeholder = 'Search settings';
- if (!supported) {
- dom.attr(frame, 'style', 'height: 100%;');
- }
- }
- }
- /**
- * @param {HTMLElement} tab
- * @param {boolean} [build]
- */
- active(tab, build = true) {
- if (!this.pool.has(tab)) this.pool.add(tab);
- dom.cl.add([table, cfgpage], 'hidden');
- dom.cl.remove([...this.pool], 'active');
- dom.cl.add(tab, 'active');
- if (!build) {
- dom.cl.remove(table, 'hidden');
- return;
- }
- const host = tab.dataset.host ?? this.blank;
- if (host === this.blank) {
- dom.cl.add(cfgpage, 'hidden');
- dom.cl.remove(table, 'hidden');
- refresh();
- } else if (host.startsWith(this.protocal)) {
- this.intFN(host);
- } else {
- dom.cl.add(cfgpage, 'hidden');
- dom.cl.remove(table, 'hidden');
- this.custom(host);
- }
- }
- /** @param { HTMLElement } tab */
- close(tab) {
- if (this.pool.has(tab)) this.pool.delete(tab);
- const host = tab.dataset.host;
- if (cfg.clearTabCache && hostCache.has(host)) hostCache.delete(host);
- if (tab.classList.contains('active')) refresh();
- const sibling = tab.nextElementSibling ?? tab.previousElementSibling;
- if (sibling) {
- if (sibling.dataset.command !== 'new-tab') {
- this.active(sibling);
- }
- }
- tab.remove();
- }
- /**
- * @param {string} [hostname]
- */
- create(hostname = undefined) {
- if (typeof hostname === 'string') {
- const createdTab = this.getTab(hostname);
- if (this.protoReg.test(hostname) && createdTab) {
- this.active(createdTab);
- return;
- }
- }
- const tab = make('mujs-tab', {
- dataset: {
- command: 'switch-tab'
- },
- style: `order: ${this.el.head.childElementCount};`
- });
- const tabClose = make('mu-js', {
- dataset: {
- command: 'close-tab'
- },
- title: i18n$('close'),
- textContent: 'X'
- });
- const tabHost = make('mujs-host');
- const p = this.protoReg.exec(hostname);
- tab.append(tabHost, tabClose);
- this.el.head.append(tab);
- this.active(tab, false);
- if (isNull(hostname)) {
- refresh();
- tab.dataset.host = this.blank;
- tabHost.title = i18n$('newTab');
- tabHost.textContent = i18n$('newTab');
- } else if (p) {
- tab.dataset.host = hostname || host;
- tabHost.title = p[1] || tab.dataset.host;
- tabHost.textContent = tabHost.title;
- this.intFN(hostname);
- } else {
- tab.dataset.host = hostname || host;
- tabHost.title = hostname || host;
- tabHost.textContent = tabHost.title;
- }
- return tab;
- }
- }
- this.Tabs = new Tabs(this.toolbar);
- this.Tabs.create(host);
- const tabbody = this.tabbody;
- const getCellValue = (tr, idx) =>
- tr.children[idx].dataset.value || tr.children[idx].textContent;
- const comparer = (idx, asc) => (a, b) =>
- ((v1, v2) =>
- v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2)
- ? v1 - v2
- : v1.toString().localeCompare(v2))(
- getCellValue(asc ? a : b, idx),
- getCellValue(asc ? b : a, idx)
- );
- for (const th of this.tabhead.rows[0].cells) {
- if (dom.text(th) === i18n$('install')) continue;
- dom.cl.add(th, 'mujs-pointer');
- ael(th, 'click', () => {
- /** [Stack Overflow Reference](https://stackoverflow.com/questions/14267781/sorting-html-table-with-javascript/53880407#53880407) */
- Array.from(tabbody.querySelectorAll('tr'))
- .sort(comparer(Array.from(th.parentNode.children).indexOf(th), (this.asc = !this.asc)))
- .forEach((tr) => tabbody.appendChild(tr));
- });
- }
- }
- init() {
- try {
- // #region Elements
- this.mainframe = make('mu-js', 'mainframe', {
- style: `opacity: ${this.opacityMin};`
- });
- this.countframe = make('mujs-column');
- this.mainbtn = make('count-frame', 'mainbtn', {
- textContent: '0'
- });
- this.urlBar = make('input', 'mujs-url-bar', {
- autocomplete: 'off',
- spellcheck: false,
- type: 'text',
- placeholder: i18n$('search_placeholder')
- });
- this.rateContainer = make('mujs-column', 'rate-container');
- this.footer = make('mujs-row', 'mujs-footer');
- this.tabbody = make('tbody');
- this.promptElem = make('mujs-row', 'mujs-prompt');
- this.toolbar = make('mujs-toolbar');
- this.table = make('table');
- this.tabhead = make('thead');
- this.header = make('mujs-header');
- this.tbody = make('mujs-body');
- this.cfgpage = make('mujs-row', 'mujs-cfg hidden');
- this.main = make('mujs-main', 'hidden');
- this.urlContainer = make('mujs-url');
- this.btnframe = make('mujs-column', 'btn-frame');
- this.btnHandles = make('mujs-column', 'btn-handles');
- this.btnHide = make('mujs-btn', 'hide-list', {
- title: i18n$('min'),
- innerHTML: iconSVG.load('minus'),
- dataset: {
- command: 'hide-list'
- }
- });
- this.btnfullscreen = make('mujs-btn', 'fullscreen', {
- title: i18n$('max'),
- innerHTML: iconSVG.load('expand'),
- dataset: {
- command: 'fullscreen'
- }
- });
- this.closebtn = make('mujs-btn', 'close', {
- title: i18n$('close'),
- innerHTML: iconSVG.load('close'),
- dataset: {
- command: 'close'
- }
- });
- this.btncfg = make('mujs-btn', 'settings hidden', {
- title: 'Settings',
- innerHTML: iconSVG.load('gear'),
- dataset: {
- command: 'settings'
- }
- });
- this.btnhome = make('mujs-btn', 'github hidden', {
- title: `GitHub (v${
- /\d+\.\d+\.\d+|Book/.test($info.script.version)
- ? $info.script.version
- : $info.script.version.slice(0, 5)
- })`,
- innerHTML: iconSVG.load('github'),
- dataset: {
- command: 'open-tab',
- webpage: $info.script.namespace
- }
- });
- this.btnissue = make('mujs-btn', 'issue hidden', {
- innerHTML: iconSVG.load('issue'),
- title: i18n$('issue'),
- dataset: {
- command: 'open-tab',
- webpage: $info.script.bugs ?? 'https://github.com/magicoflolis/Userscript-Plus/issues'
- }
- });
- this.btngreasy = make('mujs-btn', 'greasy hidden', {
- title: 'Greasy Fork',
- innerHTML: iconSVG.load('globe'),
- dataset: {
- command: 'open-tab',
- webpage: 'https://greasyfork.org/scripts/421603'
- }
- });
- this.btnnav = make('mujs-btn', 'nav', {
- title: 'Navigation',
- innerHTML: iconSVG.load('nav'),
- dataset: {
- command: 'navigation'
- }
- });
- const makeTHead = (rows = []) => {
- const tr = make('tr');
- for (const r of rows) {
- const tparent = make('th', r.class ?? '', r);
- tr.append(tparent);
- }
- this.tabhead.append(tr);
- this.table.append(this.tabhead, this.tabbody);
- };
- makeTHead([
- {
- class: 'mujs-header-name',
- textContent: i18n$('name')
- },
- {
- textContent: i18n$('createdby')
- },
- {
- textContent: i18n$('daily_installs')
- },
- {
- textContent: i18n$('updated')
- },
- {
- textContent: i18n$('install')
- }
- ]);
- // #endregion
- if (isMobile) {
- dom.cl.add([this.btnHide, this.btnfullscreen, this.closebtn], 'hidden');
- this.btnframe.append(
- this.btnHide,
- this.btnfullscreen,
- this.closebtn,
- this.btnhome,
- this.btngreasy,
- this.btnissue,
- this.btncfg,
- this.btnnav
- );
- } else {
- this.btnHandles.append(this.btnHide, this.btnfullscreen, this.closebtn);
- this.btnframe.append(this.btnhome, this.btngreasy, this.btnissue, this.btncfg, this.btnnav);
- }
- this.toolbar.append(this.btnHandles);
- this.urlContainer.append(this.urlBar);
- this.header.append(this.urlContainer, this.rateContainer, this.countframe, this.btnframe);
- this.tbody.append(this.table, this.cfgpage);
- this.main.append(this.toolbar, this.header, this.tbody, this.footer, this.promptElem);
- this.mainframe.append(this.mainbtn);
- this.root.append(this.mainframe, this.main);
- return true;
- } catch (ex) {
- err(ex);
- }
- return false;
- }
- remove() {
- this.hostCache.clear();
- this.userjsCache.clear();
- dom.remove(this.frame);
- }
- async save() {
- this.unsaved = false;
- await StorageSystem.setValue('Config', cfg);
- info('Saved config:', cfg);
- this.redirect();
- return cfg;
- }
- /**
- * @param { string } css - CSS to inject
- * @param { string } name - Name of stylesheet
- * @return { HTMLStyleElement | undefined } Style element
- */
- loadCSS(css, name = 'CSS') {
- try {
- if (typeof name !== 'string')
- throw new Error('"name" must be a typeof "string"', { cause: 'loadCSS' });
- if (qs(`style[data-role="${name}"]`, this.root))
- return qs(`style[data-role="${name}"]`, this.root);
- if (typeof css !== 'string')
- throw new Error('"css" must be a typeof "string"', { cause: 'loadCSS' });
- if (isBlank(css))
- throw new Error(`"${name}" contains empty CSS string`, { cause: 'loadCSS' });
- const parent = isEmpty(this.root.shadowRoot) ? this.root : this.root.shadowRoot;
- if (isGM) {
- const fn = isFN(GM.addElement)
- ? GM.addElement
- : isFN(GM_addElement)
- ? GM_addElement
- : BLANK_FN;
- const sty = fn(parent, 'style', { textContent: css });
- if (isElem(sty)) {
- sty.dataset.insertedBy = $info.script.name;
- sty.dataset.role = name;
- return sty;
- }
- }
- const sty = make('style', {
- textContent: css,
- dataset: {
- insertedBy: $info.script.name,
- role: name
- }
- });
- parent.appendChild(sty);
- return sty;
- } catch (ex) {
- err(ex);
- }
- }
- checkBlacklist(str) {
- str = str || this.host;
- if (/accounts*\.google\./.test(this.webpage.host)) {
- this.isBlacklisted = true;
- return this.isBlacklisted;
- }
- let blacklisted = false;
- for (const b of normalizeTarget(cfg.blacklist)) {
- if (typeof b === 'string') {
- if (b.startsWith('userjs-')) {
- const r = /userjs-(\w+)/.exec(b)[1];
- const biList = builtinList[r];
- if (isRegExp(biList)) {
- if (!biList.test(str)) continue;
- blacklisted = true;
- } else if (isObj(biList) && biList.host === this.host) {
- blacklisted = true;
- }
- }
- } else if (isObj(b)) {
- if (!b.enabled) {
- continue;
- }
- if (b.regex === true) {
- const reg = new RegExp(b.url, b.flags);
- if (!reg.test(str)) continue;
- blacklisted = true;
- }
- if (Array.isArray(b.url)) {
- for (const c of b.url) {
- if (!str.includes(c)) continue;
- blacklisted = true;
- }
- }
- if (!str.includes(b.url)) continue;
- blacklisted = true;
- }
- }
- this.isBlacklisted = blacklisted;
- return this.isBlacklisted;
- }
- setTheme() {
- const theme = cfg.theme ?? DEFAULT_CONFIG.theme;
- if (theme === DEFAULT_CONFIG.theme) {
- return;
- }
- const sty = this.root.style;
- for (const [k, v] of Object.entries(theme)) {
- const str = `--mujs-${k}`;
- const prop = sty.getPropertyValue(str);
- if (isEmpty(v)) theme[k] = prop;
- if (prop === v) continue;
- sty.removeProperty(str);
- sty.setProperty(str, v);
- }
- }
- makePrompt(txt, dataset = {}, usePrompt = true) {
- for (const elem of normalizeTarget(qsA('.prompt', this.promptElem))) {
- if (elem.dataset.prompt) elem.remove();
- }
- const el = make('mu-js', 'prompt', {
- dataset: {
- prompt: txt
- }
- });
- const elHead = make('mu-js', 'prompt-head', {
- innerHTML: `${iconSVG.load('refresh')} ${txt}`
- });
- el.append(elHead);
- if (usePrompt) {
- const elPrompt = make('mu-js', 'prompt-body', { dataset });
- const elYes = make('mujs-btn', 'prompt-confirm', {
- innerHTML: 'Confirm',
- dataset: {
- command: 'prompt-confirm'
- }
- });
- const elNo = make('mujs-btn', 'prompt-deny', {
- innerHTML: 'Deny',
- dataset: {
- command: 'prompt-deny'
- }
- });
- elPrompt.append(elYes, elNo);
- el.append(elPrompt);
- } else {
- const elPrompt = make('mu-js', 'prompt-body');
- const elNo = make('mujs-btn', 'prompt-deny', {
- textContent: i18n$('close')
- });
- ael(elNo, isMobile ? 'touchend' : 'click', () => {
- el.remove();
- });
- elPrompt.append(elNo);
- el.append(elPrompt);
- }
- this.promptElem.append(el);
- return el;
- }
- /**
- * @template {string | Error} E
- * @param {...E} ex
- */
- showError(...ex) {
- err(...ex);
- const error = make('mu-js', 'error');
- let str = '';
- for (const e of ex) {
- str += `${typeof e === 'string' ? e : `${e.cause ? `[${e.cause}] ` : ''}${e.message}${e.stack ? ` ${e.stack}` : ''}`}\n`;
- }
- const { createTextNode } = _self;
- error.appendChild(createTextNode(str));
- this.footer.append(error);
- }
- refresh() {
- this.urlBar.placeholder = i18n$('newTab');
- Counter.reset();
- dom.cl.remove(this.toElem(), 'hidden');
- dom.cl.remove(cfgSec, 'hidden');
- dom.prop([this.tabbody, this.rateContainer, this.footer], 'innerHTML', '');
- }
- /**
- * Redirects sleazyfork userscripts from greasyfork.org to sleazyfork.org
- *
- * Taken from: https://greasyfork.org/scripts/23840
- */
- redirect() {
- const locObj = window.top.location;
- const { hostname } = locObj;
- const gfSite = /greasyfork\.org/.test(hostname);
- if (!gfSite && cfg.sleazyredirect) {
- return;
- }
- const otherSite = gfSite ? 'sleazyfork' : 'greasyfork';
- if (!qs('span.sign-in-link')) {
- return;
- }
- if (!/scripts\/\d+/.test(locObj.href)) {
- return;
- }
- if (
- !qs('#script-info') &&
- (otherSite == 'greasyfork' || qs('div.width-constraint>section>p>a'))
- ) {
- const str = locObj.href.replace(
- /\/\/([^.]+\.)?(greasyfork|sleazyfork)\.org/,
- '//$1' + otherSite + '.org'
- );
- info(`Redirecting to "${str}"`);
- if (isFN(locObj.assign)) {
- locObj.assign(str);
- } else {
- locObj.href = str;
- }
- }
- }
- /**
- * @param {number} [time]
- */
- async timeoutFrame(time) {
- const frameTimeout = this.timeouts.frame;
- frameTimeout.clear(...frameTimeout.ids);
- if (dom.cl.has(this.mainframe, 'hidden')) {
- return;
- }
- time = time ?? cfg.time ?? DEFAULT_CONFIG.time;
- let n = 10000;
- if (typeof time === 'number' && !Number.isNaN(time)) {
- n = this.isBlacklisted ? time / 2 : time;
- }
- await frameTimeout.set(n);
- this.remove();
- frameTimeout.clear(...frameTimeout.ids);
- }
- toElem() {
- return Array.from(this).map(({ _mujs }) => {
- return _mujs.root;
- });
- }
- *[Symbol.iterator]() {
- const arr = Array.from(this.userjsCache.values()).filter(({ _mujs }) => {
- return !isEmpty(_mujs) && _mujs.info.engine.enabled;
- });
- for (const userjs of arr) {
- yield userjs;
- }
- }
- }
- const container = new Container();
- // #endregion
- // #region Primary Function
- function primaryFN() {
- const respHandles = {
- build: BLANK_ASYNC_FN
- };
- try {
- const { scheduler } = _self;
- const {
- mainframe,
- urlBar,
- rateContainer,
- footer,
- tabbody,
- cfgpage,
- btnfullscreen,
- main,
- Tabs,
- showError
- } = container;
- const reloadCfg = () => {
- for (const base of cfgBase) {
- const nm = /^(\w+)-(.+)/.exec(base.value);
- const d = (() => {
- if (base.tag === 'engine') {
- const engine = DEFAULT_CONFIG.engines.find((engine) => engine.name === base.value);
- if (engine) {
- return engine;
- }
- }
- if (nm) {
- return DEFAULT_CONFIG[nm[1]][nm[2]];
- }
- return DEFAULT_CONFIG[base.value];
- })();
- const v = (() => {
- if (base.tag === 'engine') {
- const engine = cfg.engines.find((engine) => engine.name === base.value);
- if (engine) {
- return engine;
- }
- }
- if (nm) {
- return cfg[nm[1]][nm[2]];
- }
- return cfg[base.value];
- })();
- base.cache = v;
- if (base.type === 'checkbox') {
- if (nm) {
- if (nm[1] === 'filters') {
- base.elem.checked = cfg[nm[1]][nm[2]].enabled;
- } else {
- base.elem.checked = v;
- }
- } else if (base.tag === 'engine') {
- base.elem.checked = v.enabled;
- base.elemUrl.value = decode(v.query);
- base.elemUrl.placeholder = decode(d.query);
- if (base.elemToken) {
- base.elemToken = v.token;
- }
- }
- } else {
- base.elem.value = v;
- }
- }
- container.setTheme();
- };
- const doInstallProcess = async (installLink) => {
- const locObj = window.top.location;
- if (isFN(locObj.assign)) {
- locObj.assign(installLink.href);
- } else {
- locObj.href = installLink.href;
- }
- installLink.remove();
- await init();
- };
- const doDownloadProcess = async (details) => {
- if (!details.url) {
- return;
- }
- const a = make('a');
- a.href = details.url;
- a.setAttribute('download', details.filename || '');
- a.setAttribute('type', 'text/plain');
- a.dispatchEvent(new MouseEvent('click'));
- await init();
- };
- const applyTo = (ujs, name, elem, root) => {
- const n = ujs._mujs.code[name] ?? ujs._mujs.code.data_meta[name];
- if (isEmpty(n)) {
- const el = make('mujs-a', {
- textContent: i18n$('listing_none')
- });
- elem.append(el);
- return;
- }
- dom.prop(elem, 'innerHTML', '');
- dom.cl.remove(root, 'hidden');
- if (isObj(n)) {
- if (name === 'resource') {
- for (const [k, v] of Object.entries(n)) {
- const el = make('mujs-a', {
- textContent: k ?? 'ERROR'
- });
- if (v.startsWith('http')) {
- el.dataset.command = 'open-tab';
- el.dataset.webpage = v;
- }
- elem.append(el);
- }
- } else {
- const el = make('mujs-a', {
- textContent: n.text
- });
- if (n.domain) {
- el.dataset.command = 'open-tab';
- el.dataset.webpage = `https://${n.text}`;
- }
- elem.append(el);
- }
- } else if (typeof n === 'string') {
- const el = make('mujs-a', {
- textContent: n
- });
- elem.append(el);
- } else {
- for (const c of n) {
- if (typeof c === 'string' && c.startsWith('http')) {
- const el = make('mujs-a', {
- textContent: c,
- dataset: {
- command: 'open-tab',
- webpage: c
- }
- });
- elem.append(el);
- } else if (isObj(c)) {
- const el = make('mujs-a', {
- textContent: c.text
- });
- if (c.domain) {
- el.dataset.command = 'open-tab';
- el.dataset.webpage = `https://${c.text}`;
- }
- elem.append(el);
- } else {
- const el = make('mujs-a', {
- textContent: c
- });
- elem.append(el);
- }
- }
- }
- };
- // #region Main event handlers
- const frameTimeout = container.timeouts.frame;
- ael(main, isMobile ? 'touchend' : 'click', async (evt) => {
- try {
- /** @type { HTMLElement } */
- const target = evt.target.closest('[data-command]');
- if (!target) {
- return;
- }
- let dataset = target.dataset;
- let cmd = dataset.command;
- if (/^prompt-/.test(target.dataset.command)) {
- dataset = target.parentElement.dataset;
- cmd = dataset.command;
- let pElem = target.parentElement.parentElement;
- if (/prompt-install/.test(target.dataset.command)) {
- pElem = target.parentElement.parentElement.parentElement;
- const a = make('a', {
- onclick(evt) {
- evt.preventDefault();
- doInstallProcess(evt.target);
- }
- });
- a.href = target.dataset.code_url;
- a.click();
- } else if (/prompt-download/.test(target.dataset.command)) {
- pElem = target.parentElement.parentElement.parentElement;
- const dataUserJS = container.userjsCache.get(+target.dataset.userjs);
- if (dataUserJS) {
- const code_obj = await dataUserJS._mujs.code.request(false, target.dataset.code_url);
- if (typeof code_obj.code === 'string')
- doDownloadProcess({
- url: 'data:text/plain;charset=utf-8,' + encodeURIComponent(code_obj.code),
- filename: `${dataUserJS.name}${isUserCSS(target.dataset.code_url) ? '.user.css' : '.user.js'}`
- });
- }
- }
- pElem.remove();
- return;
- }
- if (cmd === 'install-script') {
- const dataUserJS = container.userjsCache.get(+dataset.userjs);
- if (isNull(dataUserJS)) {
- return;
- }
- if (dataUserJS.code_urls.length > 1) {
- const list = make('mujs-list', {
- style: 'display: flex; flex-direction: column;'
- });
- for (const ujs of dataUserJS.code_urls) {
- const a = make('mujs-a', {
- title: ujs.code_url,
- textContent: ujs.name,
- dataset: {
- command: 'prompt-install',
- code_url: ujs.code_url
- }
- });
- list.append(a);
- }
- container.makePrompt(`Multiple detected: ${list.outerHTML}`, dataset, false);
- } else {
- const a = make('a', {
- onclick(evt) {
- evt.preventDefault();
- doInstallProcess(evt.target);
- }
- });
- a.href = dataUserJS.code_url;
- a.click();
- }
- } else if (cmd === 'open-tab' && dataset.webpage) {
- if (isGM) {
- if (isFN(GM.openInTab)) {
- return GM.openInTab(dataset.webpage);
- } else if (isFN(GM_openInTab)) {
- return GM_openInTab(dataset.webpage, {
- active: true,
- insert: true
- });
- }
- }
- return window.open(dataset.webpage, '_blank');
- } else if (cmd === 'navigation') {
- for (const e of normalizeTarget(qsA('mujs-btn', target.parentElement)).filter(
- (e) => !dom.cl.has(e, 'nav')
- )) {
- dom.cl.toggle(e, 'hidden');
- }
- } else if (cmd === 'list-description') {
- const arr = [];
- const ignoreTags = new Set(['TD', 'MUJS-A', 'MU-JS']);
- for (const node of Object.values(target.parentElement._mujs)) {
- if (ignoreTags.has(node.tagName)) {
- continue;
- }
- if (node.tagName === 'TEXTAREA' && isEmpty(node.value)) {
- continue;
- }
- arr.push(node);
- }
- if (target.nextElementSibling) {
- arr.push(target.nextElementSibling);
- if (target.nextElementSibling.nextElementSibling) {
- arr.push(target.nextElementSibling.nextElementSibling);
- }
- }
- if (dom.cl.has(arr[0], 'hidden')) {
- dom.cl.remove(arr, 'hidden');
- } else {
- dom.cl.add(arr, 'hidden');
- }
- } else if (cmd === 'close') {
- container.remove();
- } else if (cmd === 'fullscreen') {
- if (dom.cl.has(btnfullscreen, 'expanded')) {
- dom.cl.remove([btnfullscreen, main], 'expanded');
- dom.prop(btnfullscreen, 'innerHTML', iconSVG.load('expand'));
- } else {
- dom.cl.add([btnfullscreen, main], 'expanded');
- dom.prop(btnfullscreen, 'innerHTML', iconSVG.load('collapse'));
- }
- } else if (cmd === 'hide-list') {
- dom.cl.add(main, 'hidden');
- dom.cl.remove(mainframe, 'hidden');
- container.timeoutFrame();
- } else if (cmd === 'save') {
- container.rebuild = true;
- dom.prop(rateContainer, 'innerHTML', '');
- if (!dom.prop(target, 'disabled')) {
- const config = await container.save();
- if (container.rebuild) {
- if (config.autofetch) {
- respHandles.build();
- }
- }
- container.unsaved = false;
- container.rebuild = false;
- }
- } else if (cmd === 'reset') {
- cfg = DEFAULT_CONFIG;
- dom.remove(qsA('.error', footer));
- container.unsaved = true;
- container.rebuild = true;
- reloadCfg();
- } else if (cmd === 'settings') {
- if (container.unsaved) {
- showError('Unsaved changes');
- }
- Tabs.create('mujs:settings');
- container.rebuild = false;
- } else if (cmd === 'new-tab') {
- Tabs.create();
- } else if (cmd === 'switch-tab') {
- Tabs.active(target);
- } else if (cmd === 'close-tab' && target.parentElement) {
- Tabs.close(target.parentElement);
- } else if (cmd === 'download-userjs') {
- const dataUserJS = container.userjsCache.get(+dataset.userjs);
- if (isNull(dataUserJS)) {
- return;
- }
- if (dataUserJS.code_urls.length > 1) {
- const list = make('mujs-list', {
- style: 'display: flex; flex-direction: column;'
- });
- for (const ujs of dataUserJS.code_urls) {
- const a = make('mujs-a', {
- title: ujs.code_url,
- textContent: ujs.name,
- dataset: {
- command: 'prompt-download',
- code_url: ujs.code_url,
- userjs: dataset.userjs
- }
- });
- list.append(a);
- }
- container.makePrompt(`Multiple detected: ${list.outerHTML}`, dataset, false);
- } else {
- const code_obj = await dataUserJS._mujs.code.request(false);
- if (typeof code_obj.code === 'string')
- doDownloadProcess({
- url: 'data:text/plain;charset=utf-8,' + encodeURIComponent(code_obj.code),
- filename: `${dataUserJS.name}${isUserCSS(dataUserJS.code_url) ? '.user.css' : '.user.js'}`
- });
- }
- } else if (cmd === 'load-userjs' || cmd === 'load-header') {
- if (!container.userjsCache.has(+dataset.userjs)) {
- return;
- }
- const codeArea = qs('textarea', target.parentElement.parentElement);
- if (!isEmpty(codeArea.value) && cmd === codeArea.dataset.load) {
- dom.cl.toggle(codeArea, 'hidden');
- return;
- }
- codeArea.dataset.load = cmd;
- const dataUserJS = container.userjsCache.get(+dataset.userjs);
- const code_obj = await dataUserJS._mujs.code.request();
- if (typeof code_obj.data_code_block !== 'string') {
- codeArea.value = 'An error occured';
- return;
- }
- codeArea.value =
- cmd === 'load-userjs' ? code_obj.data_code_block : code_obj.data_meta_block;
- dom.cl.remove(codeArea, 'hidden');
- for (const e of qsA(
- 'mujs-column[data-el="matches"]',
- target.parentElement.parentElement
- )) {
- applyTo(dataUserJS, e.dataset.type, qs('.mujs-grants', e), e);
- }
- } else if (cmd === 'load-page') {
- if (!container.userjsCache.has(+dataset.userjs)) {
- return;
- }
- let pageArea = qs('mujs-page', target.parentElement.parentElement);
- if (!pageArea) {
- pageArea = make('mujs-page');
- target.parentElement.parentElement.append(pageArea);
- const dataUserJS = container.userjsCache.get(+dataset.userjs);
- const engine = dataUserJS._mujs.info.engine;
- let pageURL;
- if (engine.name.includes('fork')) {
- const { navigator } = _self;
- const current = navigator.language.split('-')[0] ?? 'en';
- pageURL = dataUserJS.url.replace(
- /\/scripts/,
- `/${/^(zh|fr|es)/.test(current) ? navigator.language : current}/scripts`
- );
- } else if (engine.name.includes('github')) {
- const page_url = await Network.req(dataUserJS.page_url, 'GET', 'json', {
- headers: {
- Accept: 'application/vnd.github+json',
- Authorization: `Bearer ${engine.token}`,
- 'X-GitHub-Api-Version': '2022-11-28'
- }
- }).catch(() => {
- return {};
- });
- if (!page_url.download_url) {
- return;
- }
- const page = await Network.req(page_url.download_url, 'GET', 'text');
- if (container.supported) {
- const shadow = pageArea.attachShadow({ mode: 'closed' });
- const div = make('div', {
- innerHTML: page
- });
- shadow.append(div);
- }
- return;
- } else {
- pageURL = dataUserJS.url;
- }
- if (!pageURL) {
- return;
- }
- const page = await Network.req(pageURL, 'GET', 'document');
- const getContent = () => {
- let content = 'An error occured';
- const h = new URL(dataUserJS.url);
- const root = qs('.user-content', page.documentElement);
- for (const e of qsA('[href]', root)) {
- e.target = '_blank';
- e.style = 'pointer-events: auto;';
- if (e.href.startsWith('/')) {
- e.href = `${h.origin}${e.href}`;
- }
- }
- for (const e of qsA('img[src]', root)) {
- e.style =
- 'max-width: 25em; max-height: 25em; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;';
- }
- if (root) {
- content = root.innerHTML;
- } else {
- content = 'No additional info available';
- }
- return content;
- };
- if (container.supported) {
- const shadow = pageArea.attachShadow({ mode: 'closed' });
- const div = make('div', {
- style: 'pointer-events: none;',
- innerHTML: getContent()
- });
- shadow.append(div);
- }
- return;
- }
- if (!dom.cl.has(pageArea, 'hidden')) {
- dom.cl.add(pageArea, 'hidden');
- return;
- }
- dom.cl.remove(pageArea, 'hidden');
- } else if (/export-/.test(cmd)) {
- const toCfg = cmd === 'export-cfg';
- doDownloadProcess({
- url:
- 'data:text/plain;charset=utf-8,' +
- encodeURIComponent(JSON.stringify(toCfg ? cfg : cfg.theme, null, ' ')),
- filename: `Magic_Userscript_${toCfg ? 'config' : 'theme'}.json`
- });
- } else if (/import-/.test(cmd)) {
- if (qs('input', target.parentElement)) {
- qs('input', target.parentElement).click();
- return;
- }
- const inpJSON = make('input', 'hidden', {
- type: 'file',
- accept: '.json',
- onchange(evt) {
- const file = evt.target.files[0];
- if (file === undefined || file.name === '') {
- return;
- }
- const fr = new FileReader();
- fr.onload = function () {
- if (typeof fr.r###lt !== 'string') {
- return;
- }
- const content = JSON.parse(fr.r###lt);
- if (content.blacklist) {
- cfg = content;
- container.unsaved = true;
- container.rebuild = true;
- reloadCfg();
- container.save().then((config) => {
- if (config.autofetch) {
- respHandles.build();
- }
- container.unsaved = false;
- container.rebuild = false;
- });
- } else {
- cfg.theme = content;
- container.setTheme();
- }
- inpJSON.remove();
- };
- fr.readAsText(file);
- }
- });
- target.parentElement.append(inpJSON);
- inpJSON.click();
- }
- } catch (ex) {
- showError(ex);
- }
- });
- ael(main, 'auxclick', (evt) => {
- if (evt.button !== 1) {
- return;
- }
- /** @type { HTMLElement } */
- const target = evt.target.closest('[data-command]');
- if (!target) {
- return;
- }
- const dataset = target.dataset;
- const cmd = dataset.command;
- if (cmd === 'switch-tab' || cmd === 'close-tab') {
- Tabs.close(target);
- } else if (cmd === 'new-tab') {
- Tabs.create();
- }
- });
- if (!isMobile) {
- const fade = async (target, type) => {
- if (type === 'mouseenter') {
- frameTimeout.clear(...frameTimeout.ids);
- container.timeouts.mouse.clear(...container.timeouts.mouse.ids);
- target.style.opacity = container.opacityMax;
- } else if (type === 'mouseleave') {
- await container.timeouts.mouse.set(cfg.time);
- target.style.opacity = container.opacityMin;
- }
- };
- for (const e of ['mouseenter', 'mouseleave']) {
- ael(main, e, (evt) => {
- evt.preventDefault();
- evt.stopPropagation();
- fade(evt.target, evt.type);
- });
- }
- }
- /**
- * @param {CustomEvent<import("../typings/types.d.ts").GSForkQuery>} evt
- */
- const updatedItem = (evt) => {
- const ujs = evt.detail;
- if (!ujs._mujs) return;
- if (ujs.deleted === true) {
- ujs._mujs.root.remove();
- container.userjsCache.delete(ujs.id);
- Counter.reset();
- MUList.sortRecords();
- return;
- }
- if (!isEmpty(ujs.code_urls)) ujs.code_url = ujs.code_urls[0].code_url;
- for (const elem of qsA('[data-name]', ujs._mujs.root)) {
- const name = elem.dataset.name;
- if (name === 'code') {
- if (ujs._mujs.code.data_code_block) {
- if (cfg.preview.code && !cfg.preview.metadata) {
- elem.value = ujs._mujs.code.data_code_block;
- } else if (cfg.preview.metadata && !cfg.preview.code) {
- elem.value = ujs._mujs.code.data_meta_block;
- } else {
- elem.value = `${ujs._mujs.code.META_START_COMMENT}${ujs._mujs.code.data_meta_block}${ujs._mujs.code.META_END_COMMENT}${ujs._mujs.code.data_code_block}`;
- }
- }
- continue;
- }
- if (!ujs[name]) continue;
- if (name === 'license') {
- dom.attr(elem, 'title', ujs.license ?? i18n$('no_license'));
- dom.text(elem, `${i18n$('license')}: ${ujs.license ?? i18n$('no_license')}`);
- } else if (name === 'code_updated_at') {
- dom.text(elem, language.toDate(ujs.code_updated_at));
- elem.dataset.value = new Date(ujs.code_updated_at).toISOString();
- } else if (name === 'created_date') {
- dom.text(elem, `${i18n$('created_date')}: ${language.toDate(ujs.created_at)}`);
- elem.dataset.value = new Date(ujs.created_at).toISOString();
- } else if (name === 'total_installs') {
- dom.text(elem, `${i18n$('total_installs')}: ${language.toNumber(ujs.total_installs)}`);
- } else {
- dom.text(elem, ujs[name]);
- }
- }
- if (ujs._mujs.code.data_code_block) {
- for (const e of qsA('mujs-column[data-el="matches"]', ujs._mujs.root)) {
- applyTo(ujs, e.dataset.type, qs('.mujs-grants', e), e);
- }
- }
- if (container.userjsCache.has(ujs.id)) container.userjsCache.set(ujs.id, ujs);
- };
- ael(main, 'updateditem', updatedItem);
- // #endregion
- const TLD_EXPANSION = ['com', 'net', 'org', 'de', 'co.uk'];
- const APPLIES_TO_ALL_PATTERNS = [
- 'http://*',
- 'https://*',
- 'http://*/*',
- 'https://*/*',
- 'http*://*',
- 'http*://*/*',
- '*',
- '*://*',
- '*://*/*',
- 'http*'
- ];
- class ParseUserJS {
- /**
- * @type { string }
- */
- code;
- /**
- * @type { string }
- */
- data_meta_block;
- /**
- * @type { string }
- */
- data_code_block;
- /**
- * @type { { [meta: string]: string | string[] | { [resource: string]: string } } }
- */
- data_meta;
- /**
- * @type { {text: string;domain: boolean;tld_extra: boolean}[] }
- */
- data_names;
- constructor(code, isCSS) {
- this.isUserCSS = isCSS === true;
- this.META_START_COMMENT = this.isUserCSS ? '/* ==UserStyle==' : '// ==UserScript==';
- this.META_END_COMMENT = this.isUserCSS ? '==/UserStyle== */' : '// ==/UserScript==';
- if (code) {
- this.code = code;
- this.get_meta_block();
- this.get_code_block();
- this.parse_meta();
- this.calculate_applies_to_names();
- }
- }
- get_meta_block() {
- if (isEmpty(this.code)) {
- return '';
- }
- if (this.data_meta_block) {
- return this.data_meta_block;
- }
- const start_block = this.code.indexOf(this.META_START_COMMENT);
- if (isNull(start_block)) {
- return '';
- }
- const end_block = this.code.indexOf(this.META_END_COMMENT, start_block);
- if (isNull(end_block)) {
- return '';
- }
- const meta_block = this.code.substring(
- start_block + this.META_START_COMMENT.length,
- end_block
- );
- this.data_meta_block = meta_block;
- return this.data_meta_block;
- }
- get_code_block() {
- if (isEmpty(this.code)) {
- return '';
- }
- if (this.data_code_block) {
- return this.data_code_block;
- }
- const start_block = this.code.indexOf(this.META_START_COMMENT);
- if (isNull(start_block)) {
- return null;
- }
- const end_block = this.code.indexOf(this.META_END_COMMENT, start_block);
- if (isNull(end_block)) {
- return null;
- }
- const code_block = this.code.substring(
- end_block + this.META_END_COMMENT.length,
- this.code.length
- );
- this.data_code_block = code_block.split('\n').filter(Boolean).join('\n');
- return this.data_code_block;
- }
- parse_meta() {
- if (isEmpty(this.code)) {
- return {};
- }
- if (this.data_meta) {
- return this.data_meta;
- }
- const meta = {};
- const meta_block_map = new Map();
- for (const meta_line of this.get_meta_block().split('\n').filter(Boolean)) {
- const meta_match = /\/\/\s+@([a-zA-Z:-]+)\s+(.*)/.exec(meta_line);
- if (!meta_match) continue;
- const key = meta_match[1].trim();
- const value = meta_match[2].trim();
- if (!meta_block_map.has(key)) meta_block_map.set(key, []);
- const meta_map = meta_block_map.get(key);
- meta_map.push(value);
- meta_block_map.set(key, meta_map);
- }
- for (const [key, value] of meta_block_map) {
- if (value.length > 1) {
- meta[key] = value;
- } else {
- meta[key] = value[0];
- }
- }
- this.data_meta = meta;
- return this.data_meta;
- }
- calculate_applies_to_names() {
- if (isEmpty(this.code)) {
- return [];
- }
- if (this.data_names) {
- return this.data_names;
- }
- let patterns = [];
- for (const [k, v] of Object.entries(this.parse_meta())) {
- if (/include|match/i.test(k)) {
- if (Array.isArray(v)) {
- patterns = patterns.concat(v);
- } else {
- patterns = patterns.concat([v]);
- }
- }
- }
- if (isEmpty(patterns)) {
- return [];
- }
- if (this.intersect(patterns, APPLIES_TO_ALL_PATTERNS)) {
- this.data_names = [
- {
- domain: false,
- text: 'All sites',
- tld_extra: false
- }
- ];
- return this.data_names;
- }
- this.data_names = ParseUserJS.getNames(patterns);
- return this.data_names;
- }
- intersect(a, ...arr) {
- return !isBlank([...new Set(a)].filter((v) => arr.every((b) => b.includes(v))));
- }
- static getNames(patterns = []) {
- const name_map = new Map();
- const addObj = (obj) => {
- if (name_map.has(obj.text)) {
- return;
- }
- name_map.set(obj.text, obj);
- };
- for (let p of patterns) {
- const original_pattern = p;
- let pre_wildcards = [];
- if (p.match(/^\/(.*)\/$/)) {
- pre_wildcards = [p];
- } else {
- let m = /^\*(https?:.*)/i.exec(p);
- if (m) {
- p = m[1];
- }
- p = p
- .replace(/^\*:/i, 'http:')
- .replace(/^\*\/\//i, 'http://')
- .replace(/^http\*:/i, 'http:')
- .replace(/^(https?):([^/])/i, '$1://$2');
- m = /^([a-z]+:\/\/)\*\.?([a-z0-9-]+(?:.[a-z0-9-]+)+.*)/i.exec(p);
- if (m) {
- p = m[1] + m[2];
- }
- m = /^\*\.?([a-z0-9-]+\.[a-z0-9-]+.*)/i.exec(p);
- if (m) {
- p = `http://${m[1]}`;
- }
- m = /^http\*(?:\/\/)?\.?((?:[a-z0-9-]+)(?:\.[a-z0-9-]+)+.*)/i.exec(p);
- if (m) {
- p = `http://${m[1]}`;
- }
- m = /^([a-z]+:\/\/([a-z0-9-]+(?:\.[a-z0-9-]+)*\.))\*(.*)/.exec(p);
- if (m) {
- if (m[2].match(/A([0-9]+\.){2,}z/)) {
- p = `${m[1]}tld${m[3]}`;
- pre_wildcards = [p.split('*')[0]];
- } else {
- pre_wildcards = [p];
- }
- } else {
- pre_wildcards = [p];
- }
- }
- for (const pre_wildcard of pre_wildcards) {
- try {
- const urlObj = new URL(pre_wildcard);
- const { host } = urlObj;
- if (isNull(host)) {
- addObj({ text: original_pattern, domain: false, tld_extra: false });
- } else if (!host.includes('.') && host.includes('*')) {
- addObj({ text: original_pattern, domain: false, tld_extra: false });
- } else if (host.endsWith('.tld')) {
- for (let i = 0; i < TLD_EXPANSION.length; i++) {
- const tld = TLD_EXPANSION[i];
- addObj({
- text: host.replace(/tld$/i, tld),
- domain: true,
- tld_extra: i != 0
- });
- }
- } else if (host.endsWith('.')) {
- addObj({
- text: host.slice(0, -1),
- domain: true,
- tld_extra: false
- });
- } else {
- addObj({
- text: host,
- domain: true,
- tld_extra: false
- });
- }
- } catch {
- addObj({ text: original_pattern, domain: false, tld_extra: false });
- }
- }
- }
- return [...name_map.values()];
- }
- /**
- * @template {import("../typings/types.d.ts").GSForkQuery} O
- * @param {boolean} translate
- * @param {O["code_url"]} code_url
- * @param {O} [obj]
- */
- async request(translate = false, code_url, obj) {
- if (this.data_code_block) {
- return this;
- }
- /** @type { string } */
- const code = await Network.req(code_url, 'GET', 'text').catch(err);
- if (typeof code !== 'string') {
- return this;
- }
- this.isUserCSS = isUserCSS(code_url);
- this.META_START_COMMENT = this.isUserCSS ? '/* ==UserStyle==' : '// ==UserScript==';
- this.META_END_COMMENT = this.isUserCSS ? '==/UserStyle== */' : '// ==/UserScript==';
- this.code = code;
- this.get_meta_block();
- this.get_code_block();
- this.parse_meta();
- this.calculate_applies_to_names();
- const { data_meta } = this;
- if (translate) {
- if (data_meta[`name:${language.current}`]) {
- Object.assign(obj, {
- name: data_meta[`name:${language.current}`]
- });
- this.translated = true;
- }
- if (data_meta[`description:${language.current}`]) {
- Object.assign(obj, {
- description: data_meta[`description:${language.current}`]
- });
- this.translated = true;
- }
- }
- if (Array.isArray(data_meta.grant)) {
- data_meta.grant = union(data_meta.grant);
- }
- if (data_meta.resource) {
- const obj = {};
- if (typeof data_meta.resource === 'string') {
- const reg = /(.+)\s+(.+)/.exec(data_meta.resource);
- if (reg) {
- obj[reg[1].trim()] = reg[2];
- }
- } else {
- for (const r of data_meta.resource) {
- const reg = /(.+)\s+(http.+)/.exec(r);
- if (reg) {
- obj[reg[1].trim()] = reg[2];
- }
- }
- }
- data_meta.resource = obj;
- }
- Object.assign(this, {
- code_size: [Network.format(code.length)],
- meta: data_meta
- });
- return this;
- }
- }
- const template = {
- id: 0,
- bad_ratings: 0,
- good_ratings: 0,
- ok_ratings: 0,
- daily_installs: 0,
- total_installs: 0,
- name: 'NOT FOUND',
- description: 'NOT FOUND',
- version: '0.0.0',
- url: BLANK_PAGE,
- code_url: BLANK_PAGE,
- created_at: Date.now(),
- code_updated_at: Date.now(),
- locale: 'NOT FOUND',
- deleted: false,
- users: []
- };
- const mkList = (txt = '', obj = {}) => {
- if (!obj.root || !obj.type) return;
- const { root, type } = obj;
- const appliesTo = make('mu-js', 'mujs-list', {
- textContent: `${txt}: `
- });
- const applyList = make('mu-js', 'mujs-grants');
- const ujsURLs = make('mujs-column', 'mujs-list', {
- dataset: {
- el: 'matches',
- type
- }
- });
- ujsURLs.append(appliesTo, applyList);
- root.append(ujsURLs);
- const list = obj.list ?? [];
- if (isEmpty(list)) {
- const elem = make('mujs-a', {
- textContent: i18n$('listing_none')
- });
- applyList.append(elem);
- dom.cl.add(ujsURLs, 'hidden');
- return;
- }
- for (const c of list) {
- if (typeof c === 'string' && c.startsWith('http')) {
- const elem = make('mujs-a', {
- textContent: c,
- dataset: {
- command: 'open-tab',
- webpage: c
- }
- });
- applyList.append(elem);
- } else if (isObj(c)) {
- if (type === 'resource') {
- for (const [k, v] of Object.entries(c)) {
- const elem = make('mujs-a', {
- textContent: k ?? 'ERROR'
- });
- if (v.startsWith('http')) {
- elem.dataset.command = 'open-tab';
- elem.dataset.webpage = v;
- }
- applyList.append(elem);
- }
- } else {
- const elem = make('mujs-a', {
- textContent: c.text
- });
- if (c.domain) {
- elem.dataset.command = 'open-tab';
- elem.dataset.webpage = `https://${c.text}`;
- }
- applyList.append(elem);
- }
- } else {
- const elem = make('mujs-a', {
- textContent: c
- });
- applyList.append(elem);
- }
- }
- };
- // #region Create UserJS
- /**
- * @param { import("../typings/types.d.ts").GSForkQuery } ujs
- * @param { string } engine
- */
- const createjs = (ujs, engine) => {
- const a = [
- ujs.deleted === true,
- ujs.id === 421603, // Lets not add this UserJS to the list
- badUserJS.includes(ujs.id),
- badUserJS.includes(ujs.url)
- ].some((t) => t === true);
- if (a) {
- return;
- }
- if (!container.userjsCache.has(ujs.id)) container.userjsCache.set(ujs.id, ujs);
- const eframe = make('td', 'install-btn');
- const uframe = make('td', 'mujs-uframe');
- const fdaily = make('td', 'mujs-list', {
- textContent: ujs.daily_installs,
- dataset: {
- name: 'daily_installs'
- }
- });
- const fupdated = make('td', 'mujs-list', {
- textContent: language.toDate(ujs.code_updated_at),
- dataset: {
- name: 'code_updated_at',
- value: new Date(ujs.code_updated_at).toISOString()
- }
- });
- const fname = make('td', 'mujs-name');
- const fmore = make('mujs-column', 'mujs-list hidden', {
- dataset: {
- el: 'more-info'
- }
- });
- const fBtns = make('mujs-column', 'mujs-list hidden');
- const jsInfo = make('mujs-row', 'mujs-list');
- const jsInfoB = make('mujs-row', 'mujs-list');
- const ratings = make('mujs-column', 'mujs-list');
- const ftitle = make('mujs-a', 'mujs-homepage', {
- textContent: ujs.name,
- title: ujs.url,
- dataset: {
- command: 'open-tab',
- webpage: ujs.url
- }
- });
- const fver = make('mu-js', 'mujs-list', {
- textContent: `${i18n$('version_number')}: ${ujs.version}`
- });
- const fcreated = make('mu-js', 'mujs-list', {
- textContent: `${i18n$('created_date')}: ${language.toDate(ujs.created_at)}`,
- dataset: {
- name: 'created_at',
- value: new Date(ujs.created_at).toISOString()
- }
- });
- const flicense = make('mu-js', 'mujs-list', {
- title: ujs.license ?? i18n$('no_license'),
- textContent: `${i18n$('license')}: ${ujs.license ?? i18n$('no_license')}`,
- dataset: {
- name: 'license'
- }
- });
- const ftotal = make('mu-js', 'mujs-list', {
- textContent: `${i18n$('total_installs')}: ${language.toNumber(ujs.total_installs)}`,
- dataset: {
- name: 'total_installs'
- }
- });
- const fratings = make('mu-js', 'mujs-list', {
- title: i18n$('ratings'),
- textContent: `${i18n$('ratings')}:`
- });
- const fgood = make('mu-js', 'mujs-list mujs-ratings', {
- title: i18n$('good'),
- textContent: ujs.good_ratings,
- dataset: {
- name: 'good_ratings',
- el: 'good'
- }
- });
- const fok = make('mu-js', 'mujs-list mujs-ratings', {
- title: i18n$('ok'),
- textContent: ujs.ok_ratings,
- dataset: {
- name: 'ok_ratings',
- el: 'ok'
- }
- });
- const fbad = make('mu-js', 'mujs-list mujs-ratings', {
- title: i18n$('bad'),
- textContent: ujs.bad_ratings,
- dataset: {
- name: 'bad_ratings',
- el: 'bad'
- }
- });
- const fdesc = make('mu-js', 'mujs-list mujs-pointer', {
- title: ujs.description,
- textContent: ujs.description,
- dataset: {
- command: 'list-description'
- }
- });
- const scriptInstall = make('mu-jsbtn', 'install', {
- innerHTML: `${iconSVG.load('install')} ${i18n$('install')}`,
- title: `${i18n$('install')} "${ujs.name}"`,
- dataset: {
- command: 'install-script',
- userjs: ujs.id
- }
- });
- const scriptDownload = make('mu-jsbtn', {
- innerHTML: `${iconSVG.load('download')} ${i18n$('saveFile')}`,
- dataset: {
- command: 'download-userjs',
- userjs: ujs.id,
- userjsName: ujs.name
- }
- });
- const tr = make('tr', 'frame', {
- dataset: {
- scriptId: ujs.id
- }
- });
- const codeArea = make('textarea', 'code-area hidden', {
- dataset: {
- name: 'code'
- },
- rows: '10',
- autocomplete: false,
- spellcheck: false,
- wrap: 'soft'
- });
- const loadCode = make('mu-jsbtn', {
- innerHTML: `${iconSVG.load('code')} ${i18n$('code')}`,
- dataset: {
- command: 'load-userjs',
- userjs: ujs.id
- }
- });
- const loadMetadata = make('mu-jsbtn', {
- innerHTML: `${iconSVG.load('code')} ${i18n$('metadata')}`,
- dataset: {
- command: 'load-header',
- userjs: ujs.id
- }
- });
- tr.dataset.engine = engine;
- if (!engine.includes('fork') && cfg.recommend.others && goodUserJS.includes(ujs.url)) {
- tr.dataset.good = 'upsell';
- }
- for (const u of ujs.users) {
- const user = make('mujs-a', {
- innerHTML: u.name,
- title: u.url,
- dataset: {
- command: 'open-tab',
- webpage: u.url
- }
- });
- if (
- cfg.recommend.author &&
- (u.id === authorID || u.url === 'https://github.com/magicoflolis')
- ) {
- tr.dataset.author = 'upsell';
- dom.prop(user, 'innerHTML', `${u.name} ${iconSVG.load('verified')}`);
- }
- uframe.append(user);
- }
- if (cfg.recommend.others && goodUserJS.includes(ujs.id)) {
- tr.dataset.good = 'upsell';
- }
- eframe.append(scriptInstall);
- ratings.append(fratings, fgood, fok, fbad);
- jsInfo.append(ftotal, ratings, fver, fcreated);
- mkList(i18n$('code_size'), {
- list: ujs._mujs.code.code_size,
- type: 'code_size',
- root: jsInfo
- });
- jsInfoB.append(flicense);
- const data_meta = ujs._mujs.code?.data_meta ?? {};
- mkList(i18n$('antifeatures'), {
- list: data_meta.antifeatures ?? [],
- type: 'antifeatures',
- root: jsInfoB
- });
- mkList(i18n$('applies_to'), {
- list: ujs._mujs.code?.data_names ?? [],
- type: 'data_names',
- root: jsInfoB
- });
- mkList('@grant', {
- list: data_meta.grant ?? [],
- type: 'grant',
- root: jsInfoB
- });
- mkList('@require', {
- list: data_meta.require,
- type: 'require',
- root: jsInfoB
- });
- mkList('@resource', {
- list: isNull(data_meta.resource) ? [] : [data_meta.resource],
- type: 'resource',
- root: jsInfoB
- });
- fmore.append(jsInfo, jsInfoB);
- fBtns.append(scriptDownload, loadCode, loadMetadata);
- fname.append(ftitle, fdesc, fmore, fBtns, codeArea);
- fname._mujs = { fmore, fBtns, codeArea };
- const loadPage = make('mu-jsbtn', {
- innerHTML: `${iconSVG.load('pager')} Page`,
- dataset: {
- command: 'load-page',
- userjs: ujs.id
- }
- });
- fBtns.append(loadPage);
- if (ujs._mujs.code?.translated) tr.classList.add('translated');
- for (const e of [fname, uframe, fdaily, fupdated, eframe]) tr.append(e);
- ujs._mujs.root = tr;
- return ujs._mujs.root;
- };
- // #endregion
- const loadFilters = () => {
- /** @type {Map<string, import("../typings/types.d.ts").Filters >} */
- const pool = new Map();
- const handles = {
- pool,
- enabled() {
- return [...pool.values()].filter((o) => o.enabled);
- },
- refresh() {
- if (!Object.is(pool.size, 0)) pool.clear();
- for (const [key, value] of Object.entries(cfg.filters)) {
- if (!pool.has(key))
- pool.set(key, {
- ...value,
- reg: new RegExp(value.regExp, value.flag),
- keyReg: new RegExp(key.trim().toLocaleLowerCase(), 'gi'),
- valueReg: new RegExp(value.name.trim().toLocaleLowerCase(), 'gi')
- });
- }
- return this;
- },
- get(str) {
- return [...pool.values()].find((v) => v.keyReg.test(str) || v.valueReg.test(str));
- },
- /**
- * @param { import("../typings/types.d.ts").GSForkQuery } param0
- */
- match({ name, users }) {
- const p = handles.enabled();
- if (Object.is(p.length, 0)) return true;
- for (const v of p) {
- if ([{ name }, ...users].find((o) => o.name.match(v.reg))) return false;
- }
- return true;
- }
- };
- for (const [key, value] of Object.entries(cfg.filters)) {
- if (!pool.has(key))
- pool.set(key, {
- ...value,
- reg: new RegExp(value.regExp, value.flag),
- keyReg: new RegExp(key.trim().toLocaleLowerCase(), 'gi'),
- valueReg: new RegExp(value.name.trim().toLocaleLowerCase(), 'gi')
- });
- }
- return handles.refresh();
- };
- // #region List
- class List {
- intEngines;
- intHost;
- constructor(hostname = undefined) {
- this.build = this.build.bind(this);
- this.groupBy = this.groupBy.bind(this);
- this.dispatch = this.dispatch.bind(this);
- this.sortRecords = this.sortRecords.bind(this);
- this.container = container;
- this.intEngines = cfg.engines ?? [];
- this.host = hostname;
- }
- setEngines(engines = []) {
- const { host } = this;
- return engines.filter((e) => {
- if (!e.enabled) {
- return false;
- }
- const v = engineUnsupported[e.name] ?? [];
- if (v.includes(host)) {
- showError(`Engine: "${e.name}" unsupported on "${host}"`);
- container.timeoutFrame();
- return false;
- }
- return true;
- });
- }
- dispatch(ujs) {
- const { CustomEvent } = _self;
- const customEvent = new CustomEvent('updateditem', { detail: ujs });
- main.dispatchEvent(customEvent);
- }
- set engines(engines) {
- this.intEngines = this.setEngines(engines);
- }
- get engines() {
- return this.intEngines;
- }
- set host(hostname) {
- if (isEmpty(hostname)) hostname = this.container.host;
- this.intHost = hostname;
- this.blacklisted = this.container.checkBlacklist(hostname);
- this.intEngines = this.setEngines(this.engines);
- this.domain = this.getDomain(this.intHost);
- if (this.blacklisted) {
- showError(`Blacklisted "${hostname}"`);
- this.container.timeoutFrame();
- }
- }
- get host() {
- return this.intHost;
- }
- /**
- * @template { string } S
- * @param { S } str
- */
- getDomain(str = '') {
- if (str === '*') {
- return 'all-sites';
- }
- return str.split('.').at(-2) ?? BLANK_PAGE;
- }
- // #region Builder
- build() {
- try {
- container.refresh();
- const { blacklisted, engines, host, domain, dispatch } = this;
- if (blacklisted || isEmpty(engines)) {
- container.opacityMin = '0';
- mainframe.style.opacity = container.opacityMin;
- return;
- }
- const fetchRecords = [];
- const bsFilter = loadFilters();
- const hostCache = Array.from(this);
- info('Building list', { hostCache, engines, container, list: this });
- const g = this.groupBy();
- const toFetch = engines.filter((engine) => !g[engine.name]);
- const isCached = toFetch.filter((engine) =>
- hostCache.find(({ _mujs }) => engine.name === _mujs.info.engine.name)
- );
- if (!isBlank(toFetch) && isBlank(isCached)) {
- for (const engine of engines) {
- info(`Fetching from "${engine.name}" for "${host}"`);
- const respError = (error) => {
- if (!error.cause) error.cause = engine.name;
- if (error.message.startsWith('429')) {
- showError(`Engine: "${engine.name}" Too many requests...`);
- return;
- }
- showError(`Engine: "${engine.name}"`, error.message);
- };
- const _mujs = (d) => {
- /**
- * @type {import("../typings/types.d.ts").GSForkQuery}
- */
- const ujs = {
- ...template,
- ...d,
- code_urls: [],
- _mujs: {
- root: {},
- info: {
- engine,
- host
- },
- code: {
- meta: {}
- }
- }
- };
- ujs._mujs.code.request = async (translate = false, code_url) => {
- if (typeof ujs._mujs.code.data_code_block === 'string') {
- return ujs._mujs.code;
- }
- const p = new ParseUserJS();
- await p.request(translate, code_url ?? ujs.code_url, ujs);
- if (code_url) {
- return p;
- }
- for (const [k, v] of Object.entries(p)) ujs._mujs.code[k] = v;
- return ujs._mujs.code;
- };
- return ujs;
- };
- /**
- * Prior to UserScript v7.0.0
- * @template {string} F
- * @param {F} fallback
- * @returns {F}
- */
- const toQuery = (fallback) => {
- if (engine.query) {
- return decode(engine.query)
- .replace(/\{host\}/g, host)
- .replace(/\{domain\}/g, domain);
- }
- return fallback;
- };
- /**
- * @param { import("../typings/types.d.ts").GSFork } dataQ
- */
- const forkFN = async (dataQ) => {
- if (!dataQ) {
- showError('Invalid data received from the server, check internet connection');
- return;
- }
- const dq = Array.isArray(dataQ)
- ? dataQ
- : Array.isArray(dataQ.query)
- ? dataQ.query
- : [];
- const dataA = dq
- .filter(Boolean)
- .filter((d) => !d.deleted)
- .filter(bsFilter.match);
- if (isBlank(dataA)) {
- return;
- }
- const { groupBy } = _self;
- /**
- * @type { {[key: string]: import("../typings/types.d.ts").GSForkQuery[]} }
- */
- const g = groupBy(dataA.map(_mujs), ({ locale }) => {
- return locale.split('-')[0] ?? locale;
- });
- for (const [k, list] of Object.entries(g)) {
- for (const ujs of list) {
- if (cfg.filterlang && k !== language.current) {
- const c = await ujs._mujs.code.request(true);
- if (!c.translated) continue;
- }
- if (
- !ujs._mujs.code.data_code_block &&
- (cfg.preview.code || cfg.preview.metadata)
- ) {
- ujs._mujs.code.request().then(() => {
- dispatch(ujs);
- });
- }
- if (isUserCSS(ujs.code_url)) {
- ujs.code_urls.push(
- {
- name: `${ujs.name} (.user.css)`,
- code_url: ujs.code_url
- },
- {
- name: `${ujs.name} (.user.js)`,
- code_url: ujs.code_url.replace(/\.user\.css$/, '.user.js')
- }
- );
- }
- createjs(ujs, engine.name);
- }
- }
- };
- /**
- * @param {Document} htmlDocument
- */
- const openuserjs = async (htmlDocument) => {
- try {
- if (!htmlDocument) {
- showError('Invalid data received from the server, TODO fix this');
- return;
- }
- const selected = htmlDocument.documentElement;
- if (/openuserjs/gi.test(engine.name)) {
- const col = qsA('.col-sm-8 .tr-link', selected) ?? [];
- for (const i of col) {
- while (isNull(qs('.script-version', i))) {
- await new Promise((resolve) => requestAnimationFrame(resolve));
- }
- const fixurl = dom
- .prop(qs('.tr-link-a', i), 'href')
- .replace(
- new RegExp(document.location.origin, 'gi'),
- 'https://openuserjs.org'
- );
- const ujs = _mujs({
- name: dom.text(qs('.tr-link-a', i)),
- description: dom.text(qs('p', i)),
- version: dom.text(qs('.script-version', i)),
- url: fixurl,
- code_url: `${fixurl.replace(/\/scripts/gi, '/install')}.user.js`,
- total_installs: dom.text(qs('td:nth-child(2) p', i)),
- created_at: dom.attr(qs('td:nth-child(4) time', i), 'datetime'),
- code_updated_at: dom.attr(qs('td:nth-child(4) time', i), 'datetime'),
- users: [
- {
- name: dom.text(qs('.inline-block a', i)),
- url: dom.prop(qs('.inline-block a', i), 'href')
- }
- ]
- });
- if (bsFilter.match(ujs)) {
- continue;
- }
- if (
- !ujs._mujs.code.data_code_block &&
- (cfg.preview.code || cfg.preview.metadata)
- ) {
- ujs._mujs.code.request().then(() => {
- dispatch(ujs);
- });
- }
- createjs(ujs, engine.name);
- }
- }
- } catch (ex) {
- showError(ex);
- }
- };
- const gitFN = (data) => {
- try {
- if (isBlank(data.items)) {
- return;
- }
- for (const r of data.items) {
- const ujs = _mujs({
- id: r.id ?? 0,
- name: r.name,
- description: isEmpty(r.description) ? i18n$('no_license') : r.description,
- url: r.html_url,
- code_url: r.html_url,
- page_url: `${r.url}/contents/README.md`,
- created_at: r.created_at,
- code_updated_at: r.updated_at || Date.now(),
- daily_installs: r.watchers_count ?? 0,
- good_ratings: r.stargazers_count ?? 0,
- users: [
- {
- name: r.owner.login,
- url: r.owner.html_url
- }
- ]
- });
- if (r.license?.name) ujs.license = r.license.name;
- const rootPath = r.contents_url.replace(/\{\+path\}/, '');
- const fetchContent = async (dir) => {
- const contents = await Network.req(dir, 'GET', 'json', {
- headers: {
- Accept: 'application/vnd.github+json',
- Authorization: `Bearer ${engine.token}`,
- 'X-GitHub-Api-Version': '2022-11-28'
- }
- }).catch(respError);
- for (const content of contents) {
- if (content.type === 'file') {
- if (isUserJS(content.name)) {
- ujs.code_urls.push({
- name: content.name,
- code_url: content.download_url
- });
- } else if (isUserCSS(content.name)) {
- ujs.code_urls.push({
- name: content.name,
- code_url: content.download_url
- });
- }
- } else if (content.type === 'dir') {
- await fetchContent(`${rootPath}/${content.path}`);
- }
- }
- };
- fetchContent(rootPath).then(() => {
- if (isEmpty(ujs.code_urls)) {
- ujs.deleted = true;
- } else if (
- !ujs._mujs.code.data_code_block &&
- (cfg.preview.code || cfg.preview.metadata)
- ) {
- ujs._mujs.code.request().then(() => {
- dispatch(ujs);
- });
- return;
- }
- dispatch(ujs);
- });
- createjs(ujs, engine.name);
- }
- } catch (ex) {
- showError(ex);
- }
- };
- let netFN;
- if (/github/gi.test(engine.name)) {
- if (isEmpty(engine.token)) {
- showError(`"${engine.name}" requires a token to use`);
- continue;
- }
- Network.req(
- `https://api.github.com/search/repositories?q=topic:${domain}+topic:userstyle`,
- 'GET',
- 'json',
- {
- headers: {
- Accept: 'application/vnd.github+json',
- Authorization: `Bearer ${engine.token}`,
- 'X-GitHub-Api-Version': '2022-11-28'
- }
- }
- )
- .then(gitFN)
- .catch(respError);
- netFN = Network.req(
- toQuery(
- `https://api.github.com/search/repositories?q=topic:${domain}+topic:userscript`
- ),
- 'GET',
- 'json',
- {
- headers: {
- Accept: 'application/vnd.github+json',
- Authorization: `Bearer ${engine.token}`,
- 'X-GitHub-Api-Version': '2022-11-28'
- }
- }
- )
- .then(gitFN)
- .then(() => {
- Network.req('https://api.github.com/rate_limit', 'GET', 'json', {
- headers: {
- Accept: 'application/vnd.github+json',
- Authorization: `Bearer ${engine.token}`,
- 'X-GitHub-Api-Version': '2022-11-28'
- }
- })
- .then((data) => {
- for (const [key, value] of Object.entries(data.resources.code_search)) {
- const txt = make('mujs-row', 'rate-info', {
- textContent: `${key.toUpperCase()}: ${value}`
- });
- rateContainer.append(txt);
- }
- })
- .catch(respError);
- });
- } else if (/openuserjs/gi.test(engine.name)) {
- netFN = Network.req(toQuery(`${engine.url}${host}`), 'GET', 'document').then(
- openuserjs
- );
- } else {
- netFN = Network.req(
- toQuery(`${engine.url}/scripts/by-site/${host}.json?language=all`)
- ).then(forkFN);
- }
- if (netFN) {
- fetchRecords.push(netFN.catch(respError));
- }
- }
- } else {
- for (const ujs of hostCache) tabbody.append(ujs._mujs.root);
- }
- urlBar.placeholder = i18n$('search_placeholder');
- urlBar.value = '';
- if (isBlank(fetchRecords)) {
- this.sortRecords();
- return;
- }
- Promise.allSettled(fetchRecords).then(this.sortRecords).catch(showError);
- } catch (ex) {
- showError(ex);
- }
- }
- // #endregion
- sortRecords() {
- const arr = Array.from(this);
- for (const ujs of arr.flat().sort((a, b) => {
- const sortType = cfg.autoSort ?? 'daily_installs';
- return b[sortType] - a[sortType];
- })) {
- if (isElem(ujs._mujs.root)) tabbody.append(ujs._mujs.root);
- }
- for (const [name, value] of Object.entries(this.groupBy(arr)))
- Counter.update(value.length, { name });
- }
- groupBy() {
- const { groupBy } = _self;
- return groupBy(Array.from(this), ({ _mujs }) => _mujs.info.engine.name);
- }
- *[Symbol.iterator]() {
- const { intHost, engines } = this;
- const arr = Array.from(this.container).filter(
- ({ _mujs }) =>
- _mujs.info.host === intHost &&
- engines.find((engine) => engine.enabled && engine.name === _mujs.info.engine.name)
- );
- for (const userjs of arr) {
- yield userjs;
- }
- }
- }
- const MUList = new List();
- // #endregion
- // #region Make Config
- const makecfg = () => {
- const cbtn = make('mu-js', 'mujs-sty-flex');
- const savebtn = make('mujs-btn', 'save', {
- textContent: i18n$('save'),
- dataset: {
- command: 'save'
- },
- disabled: false
- });
- const resetbtn = make('mujs-btn', 'reset', {
- textContent: i18n$('reset'),
- dataset: {
- command: 'reset'
- }
- });
- cbtn.append(resetbtn, savebtn);
- const makesection = (name, tag) => {
- tag = tag ?? i18n$('no_license');
- name = name ?? i18n$('no_license');
- const sec = make('mujs-section', {
- dataset: {
- name: tag
- }
- });
- const lb = make('label', {
- dataset: {
- command: tag
- }
- });
- const divDesc = make('mu-js', {
- textContent: name
- });
- ael(sec, 'click', (evt) => {
- /** @type { HTMLElement } */
- const target = evt.target.closest('[data-command]');
- if (!target) {
- return;
- }
- const cmd = target.dataset.command;
- if (cmd === tag) {
- const a = qsA(`[data-${tag}]`, sec);
- if (dom.cl.has(a, 'hidden')) {
- dom.cl.remove(a, 'hidden');
- } else {
- dom.cl.add(a, 'hidden');
- }
- }
- });
- lb.append(divDesc);
- sec.append(lb);
- cfgpage.append(sec);
- !cfgSec.has(sec) && cfgSec.add(sec);
- return sec;
- };
- const sections = {
- general: makesection('General', 'general'),
- load: makesection('Automation', 'load'),
- list: makesection('List', 'list'),
- filters: makesection('List Filters', 'filters'),
- blacklist: makesection('Blacklist (WIP)', 'blacklist'),
- engine: makesection('Search Engines', 'engine'),
- theme: makesection('Theme Colors', 'theme'),
- exp: makesection('Import / Export', 'exp')
- };
- const makeRow = (text, value, type = 'checkbox', tag = 'general', attrs = {}) => {
- const lb = make('label', 'sub-section hidden', {
- textContent: text,
- dataset: {
- [tag]: text
- }
- });
- const getDefault = () => {
- if (tag === 'engine') {
- const engine = DEFAULT_CONFIG.engines.find((engine) => engine.name === value);
- if (engine) {
- return engine;
- }
- }
- const nm = /^(\w+)-(.+)/.exec(value);
- if (nm) {
- return DEFAULT_CONFIG[nm[1]][nm[2]];
- }
- return DEFAULT_CONFIG[value];
- };
- const getValue = () => {
- if (tag === 'engine') {
- const engine = cfg.engines.find((engine) => engine.name === value);
- if (engine) {
- return engine;
- }
- }
- const nm = /^(\w+)-(.+)/.exec(value);
- if (nm) {
- return cfg[nm[1]][nm[2]];
- }
- return cfg[value];
- };
- const obj = {
- text,
- tag,
- value,
- type,
- attrs,
- default: getDefault(),
- cache: getValue()
- };
- if (type === 'select') {
- const inp = make('select', {
- dataset: {
- [tag]: text
- },
- ...attrs
- });
- for (const selV of Object.keys(template)) {
- if (selV === 'deleted' || selV === 'users') continue;
- const o = make('option', {
- value: selV,
- textContent: selV
- });
- inp.append(o);
- }
- inp.value = cfg[value];
- lb.append(inp);
- if (sections[tag]) {
- sections[tag].append(lb);
- }
- obj.elem = inp;
- cfgBase.push(obj);
- return lb;
- }
- const inp = make('input', {
- type,
- dataset: {
- [tag]: text
- },
- ...attrs
- });
- if (tag === 'engine') {
- inp.dataset.name = value;
- }
- if (sections[tag]) {
- sections[tag].append(lb);
- }
- if (type === 'checkbox') {
- const inlab = make('mu-js', 'mujs-inlab');
- const la = make('label', {
- onclick() {
- inp.dispatchEvent(new MouseEvent('click'));
- }
- });
- inlab.append(inp, la);
- lb.append(inlab);
- const nm = /^(\w+)-(.+)/.exec(value);
- if (nm) {
- if (nm[1] === 'filters') {
- inp.checked = cfg[nm[1]][nm[2]].enabled;
- } else {
- inp.checked = cfg[nm[1]][nm[2]];
- }
- } else {
- inp.checked = cfg[value];
- }
- ael(inp, 'change', (evt) => {
- container.unsaved = true;
- if (/filterlang/i.test(value)) {
- container.rebuild = true;
- }
- if (nm) {
- if (nm[1] === 'filters') {
- cfg[nm[1]][nm[2]].enabled = evt.target.checked;
- } else {
- cfg[nm[1]][nm[2]] = evt.target.checked;
- }
- } else {
- cfg[value] = evt.target.checked;
- }
- });
- if (tag === 'engine') {
- const engine = cfg.engines.find((engine) => engine.name === value);
- if (engine) {
- inp.checked = engine.enabled;
- inp.dataset.engine = engine.name;
- ael(inp, 'change', (evt) => {
- container.unsaved = true;
- container.rebuild = true;
- engine.enabled = evt.target.checked;
- MUList.engines = cfg.engines;
- });
- if (engine.query) {
- const d = DEFAULT_CONFIG.engines.find((e) => e.name === engine.name);
- const urlInp = make('input', {
- type: 'text',
- defaultValue: '',
- value: decode(engine.query),
- placeholder: decode(d.query),
- dataset: {
- name: nm,
- engine: engine.name
- },
- onchange(evt) {
- container.unsaved = true;
- container.rebuild = true;
- try {
- engine.query = encodeURIComponent(new URL(evt.target.value).toString());
- MUList.engines = cfg.engines;
- } catch (ex) {
- err(ex);
- }
- }
- });
- obj.elemUrl = urlInp;
- lb.append(urlInp);
- }
- if (engine.name === 'github') {
- const ghToken = make('input', {
- type: 'text',
- defaultValue: '',
- value: engine.token ?? '',
- placeholder: 'Paste Access Token',
- dataset: {
- engine: 'github-token'
- },
- onchange(evt) {
- container.unsaved = true;
- container.rebuild = true;
- engine.token = evt.target.value;
- MUList.engines = cfg.engines;
- }
- });
- obj.elemToken = ghToken;
- lb.append(ghToken);
- }
- }
- }
- } else {
- if (type === 'text') {
- inp.defaultValue = '';
- inp.value = value ?? '';
- inp.placeholder = value ?? '';
- if (tag === 'theme') {
- inp.dataset[tag] = text;
- ael(inp, 'change', (evt) => {
- let isvalid = true;
- try {
- const val = evt.target.value;
- const sty = container.root.style;
- const str = `--mujs-${text}`;
- const prop = sty.getPropertyValue(str);
- if (isEmpty(val)) {
- cfg.theme[text] = DEFAULT_CONFIG.theme[text];
- sty.removeProperty(str);
- return;
- }
- if (prop === val) {
- return;
- }
- sty.removeProperty(str);
- sty.setProperty(str, val);
- cfg.theme[text] = val;
- } catch (ex) {
- err(ex);
- isvalid = false;
- } finally {
- if (isvalid) {
- dom.cl.remove(evt.target, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', false);
- } else {
- dom.cl.add(evt.target, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', true);
- }
- }
- });
- }
- }
- lb.append(inp);
- }
- obj.elem = inp;
- cfgBase.push(obj);
- return lb;
- };
- if (isGM) {
- makeRow(i18n$('userjs_sync'), 'cache');
- makeRow(i18n$('userjs_autoinject'), 'autoinject', 'checkbox', 'load');
- }
- makeRow(i18n$('redirect'), 'sleazyredirect');
- makeRow(`${i18n$('dtime')} (ms)`, 'time', 'number', 'general', {
- defaultValue: 10000,
- value: cfg.time,
- min: 0,
- step: 500,
- onbeforeinput(evt) {
- if (evt.target.validity.badInput) {
- dom.cl.add(evt.target, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', true);
- } else {
- dom.cl.remove(evt.target, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', false);
- }
- },
- oninput(evt) {
- container.unsaved = true;
- const t = evt.target;
- if (t.validity.badInput || (t.validity.rangeUnderflow && t.value !== '-1')) {
- dom.cl.add(t, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', true);
- } else {
- dom.cl.remove(t, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', false);
- cfg.time = isEmpty(t.value) ? cfg.time : parseFloat(t.value);
- }
- }
- });
- makeRow(i18n$('auto_fetch'), 'autofetch', 'checkbox', 'load');
- makeRow(i18n$('userjs_fullscreen'), 'autoexpand', 'checkbox', 'load', {
- onchange(e) {
- if (e.target.checked) {
- dom.cl.add([btnfullscreen, main], 'expanded');
- dom.prop(btnfullscreen, 'innerHTML', iconSVG.load('collapse'));
- } else {
- dom.cl.remove([btnfullscreen, main], 'expanded');
- dom.prop(btnfullscreen, 'innerHTML', iconSVG.load('expand'));
- }
- }
- });
- makeRow('Clear on Tab close', 'clearTabCache', 'checkbox', 'load');
- makeRow(i18n$('default_sort'), 'autoSort', 'select', 'list');
- makeRow(i18n$('filter'), 'filterlang', 'checkbox', 'list');
- makeRow(i18n$('preview_code'), 'preview-code', 'checkbox', 'list');
- makeRow(i18n$('preview_metadata'), 'preview-metadata', 'checkbox', 'list');
- makeRow(i18n$('recommend_author'), 'recommend-author', 'checkbox', 'list');
- makeRow(i18n$('recommend_other'), 'recommend-others', 'checkbox', 'list');
- for (const [k, v] of Object.entries(cfg.filters))
- makeRow(v.name, `filters-${k}`, 'checkbox', 'filters');
- makeRow('Greasy Fork', 'greasyfork', 'checkbox', 'engine');
- makeRow('Sleazy Fork', 'sleazyfork', 'checkbox', 'engine');
- makeRow('Open UserJS', 'openuserjs', 'checkbox', 'engine');
- makeRow('GitHub API', 'github', 'checkbox', 'engine');
- for (const [k, v] of Object.entries(cfg.theme)) makeRow(k, v, 'text', 'theme');
- // const blacklist = make('textarea', {
- // dataset: {
- // name: 'blacklist'
- // },
- // rows: '10',
- // autocomplete: false,
- // spellcheck: false,
- // wrap: 'soft',
- // value: JSON.stringify(cfg.blacklist, null, ' '),
- // oninput(evt) {
- // let isvalid = true;
- // try {
- // cfg.blacklist = JSON.parse(evt.target.value);
- // isvalid = true;
- // } catch (ex) {
- // err(ex);
- // isvalid = false;
- // } finally {
- // if (isvalid) {
- // dom.cl.remove(evt.target, 'mujs-invalid');
- // dom.prop(savebtn, 'disabled', false);
- // } else {
- // dom.cl.add(evt.target, 'mujs-invalid');
- // dom.prop(savebtn, 'disabled', true);
- // }
- // }
- // }
- // });
- // const addList = make('mujs-add', {
- // textContent: '+',
- // dataset: {
- // command: 'new-list'
- // }
- // });
- // const n = make('input', {
- // type: 'text',
- // defaultValue: '',
- // value: '',
- // placeholder: 'Name',
- // });
- // const inpValue = make('input', {
- // type: 'text',
- // defaultValue: '',
- // value: '',
- // placeholder: 'Value',
- // });
- // const label = make('label', 'new-list hidden', {
- // dataset: {
- // blacklist: 'new-list'
- // }
- // });
- // label.append(n, inpValue, addList);
- // listSec.append(label);
- // ael(addList, 'click', () => {
- // if (isEmpty(n.value) || isEmpty(inpValue.value)) {
- // return
- // };
- // createList(n.value, n.value, inpValue.value);
- // });
- const createList = (key, v = '', disabled = false, type = 'String') => {
- let txt = key;
- if (typeof key === 'string') {
- if (key.startsWith('userjs-')) {
- disabled = true;
- const s = key.substring(7);
- txt = `Built-in "${s}"`;
- v = builtinList[s];
- }
- } else {
- if (!key.enabled) {
- return;
- }
- }
- if (isRegExp(v)) {
- v = v.toString();
- type = 'RegExp';
- } else {
- v = JSON.stringify(v);
- type = 'Object';
- }
- const lb = make('label', 'hidden', {
- textContent: txt,
- dataset: {
- blacklist: key
- }
- });
- const inp = make('input', {
- type: 'text',
- defaultValue: '',
- value: v ?? '',
- placeholder: v ?? '',
- dataset: {
- blacklist: key
- },
- onchange(evt) {
- let isvalid = true;
- try {
- const val = evt.target.value;
- if (isEmpty(val)) {
- return;
- }
- isvalid = true;
- } catch (ex) {
- err(ex);
- isvalid = false;
- } finally {
- if (isvalid) {
- dom.cl.remove(evt.target, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', false);
- } else {
- dom.cl.add(evt.target, 'mujs-invalid');
- dom.prop(savebtn, 'disabled', true);
- }
- }
- }
- });
- const selType = make('select', {
- disabled,
- dataset: {
- blacklist: key
- }
- });
- if (disabled) {
- inp.readOnly = true;
- const o = make('option', {
- value: type,
- textContent: type
- });
- selType.append(o);
- } else {
- for (const selV of ['String', 'RegExp', 'Object']) {
- const o = make('option', {
- value: selV,
- textContent: selV
- });
- selType.append(o);
- }
- }
- selType.value = type;
- lb.append(inp, selType);
- sections.blacklist.append(lb);
- };
- for (const key of cfg.blacklist) createList(key);
- const transfers = {
- export: {
- cfg: make('mujs-btn', 'mujs-export sub-section hidden', {
- textContent: i18n$('export_config'),
- dataset: {
- command: 'export-cfg',
- exp: 'export-cfg'
- }
- }),
- theme: make('mujs-btn', 'mujs-export sub-section hidden', {
- textContent: i18n$('export_theme'),
- dataset: {
- command: 'export-theme',
- exp: 'export-theme'
- }
- })
- },
- import: {
- cfg: make('mujs-btn', 'mujs-import sub-section hidden', {
- textContent: i18n$('import_config'),
- dataset: {
- command: 'import-cfg',
- exp: 'import-cfg'
- }
- }),
- theme: make('mujs-btn', 'mujs-import sub-section hidden', {
- textContent: i18n$('import_theme'),
- dataset: {
- command: 'import-theme',
- exp: 'import-theme'
- }
- })
- }
- };
- for (const value of Object.values(transfers)) {
- for (const v of Object.values(value)) {
- sections.exp.append(v);
- }
- }
- cfgpage.append(cbtn);
- };
- // #endregion
- container.Tabs.custom = (host) => {
- MUList.host = host;
- respHandles.build();
- };
- ael(mainframe, 'mouseenter', (evt) => {
- evt.preventDefault();
- evt.stopPropagation();
- evt.target.style.opacity = container.opacityMax;
- frameTimeout.clear(...frameTimeout.ids);
- });
- ael(mainframe, 'mouseleave', (evt) => {
- evt.preventDefault();
- evt.stopPropagation();
- evt.target.style.opacity = container.opacityMin;
- container.timeoutFrame();
- });
- ael(mainframe, 'click', (evt) => {
- evt.preventDefault();
- frameTimeout.clear(...frameTimeout.ids);
- dom.cl.remove(main, 'hidden');
- dom.cl.add(mainframe, 'hidden');
- if (cfg.autoexpand) {
- dom.cl.add([btnfullscreen, main], 'expanded');
- dom.prop(btnfullscreen, 'innerHTML', iconSVG.load('collapse'));
- }
- });
- ael(urlBar, 'input', (evt) => {
- evt.preventDefault();
- if (urlBar.placeholder === i18n$('newTab')) {
- return;
- }
- /**
- * @type { string }
- */
- const val = evt.target.value;
- const section = qsA('mujs-section[data-name]', cfgpage);
- if (isEmpty(val)) {
- dom.cl.remove(container.toElem(), 'hidden');
- dom.cl.remove(section, 'hidden');
- return;
- }
- const finds = new Set();
- if (!dom.cl.has(cfgpage, 'hidden')) {
- const reg = new RegExp(val, 'gi');
- for (const elem of section) {
- if (!isElem(elem)) continue;
- if (finds.has(elem)) continue;
- if (elem.dataset.name.match(reg)) finds.add(elem);
- }
- dom.cl.add(section, 'hidden');
- dom.cl.remove([...finds], 'hidden');
- return;
- }
- const cacheValues = Array.from(container).filter(({ _mujs }) => {
- return !finds.has(_mujs.root);
- });
- /**
- * @param {RegExpMatchArray} regExp
- * @param {keyof import("../typings/types.d.ts").GSForkQuery} key
- */
- const ezQuery = (regExp, key) => {
- const q_value = val.replace(regExp, '');
- const reg = new RegExp(q_value, 'gi');
- for (const v of cacheValues) {
- let k = v[key];
- if (typeof k === 'number') {
- k = `${v[key]}`;
- }
- if (k && k.match(reg)) {
- finds.add(v._mujs.root);
- }
- }
- };
- if (val.match(/^(code_url|url):/)) {
- ezQuery(/^(code_url|url):/, 'code_url');
- } else if (val.match(/^(author|users?):/)) {
- const parts = /^[\w_]+:(.+)/.exec(val);
- if (parts) {
- const reg = new RegExp(parts[1], 'gi');
- for (const v of cacheValues.filter((v) => !isEmpty(v.users))) {
- for (const user of v.users) {
- for (const value of Object.values(user)) {
- if (typeof value === 'string' && value.match(reg)) {
- finds.add(v._mujs.root);
- } else if (typeof value === 'number' && `${value}`.match(reg)) {
- finds.add(v._mujs.root);
- }
- }
- }
- }
- }
- } else if (val.match(/^(locale|i18n):/)) {
- ezQuery(/^(locale|i18n):/, 'locale');
- } else if (val.match(/^id:/)) {
- ezQuery(/^id:/, 'id');
- } else if (val.match(/^license:/)) {
- ezQuery(/^license:/, 'license');
- } else if (val.match(/^name:/)) {
- ezQuery(/^name:/, 'name');
- } else if (val.match(/^description:/)) {
- ezQuery(/^description:/, 'description');
- } else if (val.match(/^(search_engine|engine):/)) {
- const parts = /^[\w_]+:(\w+)/.exec(val);
- if (parts) {
- const reg = new RegExp(parts[1], 'gi');
- for (const { _mujs } of cacheValues)
- if (_mujs.info.engine.name.match(reg)) finds.add(_mujs.root);
- }
- } else if (val.match(/^filter:/)) {
- const parts = /^\w+:(.+)/.exec(val);
- if (parts) {
- const bsFilter = loadFilters();
- const filterType = bsFilter.get(parts[1].trim().toLocaleLowerCase());
- if (filterType) {
- const { reg } = filterType;
- for (const { name, users, _mujs } of cacheValues) {
- if ([{ name }, ...users].find((o) => o.name.match(reg))) continue;
- finds.add(_mujs.root);
- }
- }
- }
- } else if (val.match(/^recommend:/)) {
- for (const { url, id, users, _mujs } of cacheValues) {
- if (
- users.find((u) => u.id === authorID) ||
- goodUserJS.includes(url) ||
- goodUserJS.includes(id)
- ) {
- finds.add(_mujs.root);
- }
- }
- } else {
- const reg = new RegExp(val, 'gi');
- for (const v of cacheValues) {
- if (v.name && v.name.match(reg)) finds.add(v._mujs.root);
- if (v.description && v.description.match(reg)) finds.add(v._mujs.root);
- if (v._mujs.code.data_meta)
- for (const key of Object.keys(v._mujs.code.data_meta))
- if (/name|desc/i.test(key) && key.match(reg)) finds.add(v._mujs.root);
- }
- }
- dom.cl.add(qsA('tr[data-engine]', tabbody), 'hidden');
- dom.cl.remove([...finds], 'hidden');
- });
- ael(urlBar, 'change', (evt) => {
- evt.preventDefault();
- const val = evt.target.value;
- const tabElem = Tabs.getActive();
- if (urlBar.placeholder === i18n$('newTab') && tabElem) {
- const tabHost = tabElem.firstElementChild;
- const host = formatURL(normalizedHostname(val));
- if (Tabs.protoReg.test(val)) {
- const createdTab = Tabs.getTab(val);
- Tabs.close(tabElem);
- if (createdTab) {
- Tabs.active(createdTab);
- } else {
- Tabs.create(val);
- }
- evt.target.placeholder = i18n$('search_placeholder');
- evt.target.value = '';
- } else if (host === '*') {
- tabElem.dataset.host = host;
- tabHost.title = '<All Sites>';
- tabHost.textContent = '<All Sites>';
- MUList.host = host;
- respHandles.build();
- } else if (container.checkBlacklist(host)) {
- showError(`Blacklisted "${host}"`);
- } else {
- tabElem.dataset.host = host;
- tabHost.title = host;
- tabHost.textContent = host;
- MUList.host = host;
- respHandles.build();
- }
- }
- });
- scheduler.postTask(makecfg, { priority: 'background' });
- respHandles.build = async () => {
- await scheduler.postTask(MUList.build, { priority: 'background' });
- container.timeoutFrame();
- };
- if (cfg.autofetch) {
- respHandles.build();
- } else {
- container.timeoutFrame();
- }
- } catch (ex) {
- err(ex);
- container.remove();
- }
- return respHandles;
- }
- // #endregion
- /**
- * @template { Function } F
- * @param { (this: F, doc: Document) => * } onDomReady
- */
- const loadDOM = (onDomReady) => {
- if (isFN(onDomReady)) {
- if (document.readyState === 'interactive' || document.readyState === 'complete') {
- onDomReady(document);
- } else {
- document.addEventListener('DOMContentLoaded', (evt) => onDomReady(evt.target), {
- once: true
- });
- }
- }
- };
- const init = async (prefix = 'Config') => {
- const stored = await StorageSystem.getValue(prefix, DEFAULT_CONFIG);
- cfg = {
- ...DEFAULT_CONFIG,
- ...stored
- };
- info('Config:', cfg);
- loadDOM((doc) => {
- try {
- if (window.location === null)
- throw new Error('"window.location" is null, reload the webpage or use a different one', {
- cause: 'loadDOM'
- });
- if (doc === null)
- throw new Error('"doc" is null, reload the webpage or use a different one', {
- cause: 'loadDOM'
- });
- container.redirect();
- if (cfg.autoinject) {
- container.inject(primaryFN, doc);
- } else {
- container.timeoutFrame();
- }
- Command.register(i18n$('userjs_inject'), () => {
- container.inject(primaryFN, doc);
- });
- Command.register(i18n$('userjs_close'), () => {
- container.remove();
- });
- } catch (ex) {
- err(ex);
- }
- });
- };
- init();
- })();