USO - Display additional infos & fixes

Display additional information. Total installs, update date, initial release date. Fix site's navigability.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         USO - Display additional infos & fixes
// @namespace    https://github.com/Procyon-b 
// @version      0.3.4
// @description  Display additional information. Total installs, update date, initial release date. Fix site's navigability.
// @author       Achernar
// @match        https://userstyles.org/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
"use strict";

var initial=true, firstPage=true;

// catch site errors
if (location.pathname.startsWith('/styles/[styleId]/')) {
  let u=location.pathname.substr(17);
  history.replaceState({}, null, u);
  location.pathname=u;
  return;
  }


// XHR -- XML
self.XMLHttpRequest = class extends self.XMLHttpRequest {
  open(...args) {
    let t=this;
    // intercept and source code
    if ( arguments[1].startsWith('https://gateway.userstyles.org/styles/getStyleCss/') ) {
      styleLoaded=styleID || -1;
      loadCSS=1;
      this.addEventListener('load', function(){
        var id=t.responseURL.split('/').pop();
        if (styles[id] && !styles[id].sourceCode) styles[id].sourceCode=JP(t.response).result;
        });
      }
    return super.open(...args);
    }
  }

// JSON.parse
var JP=JSON.parse;
JSON.parse=function(){
  var r=JP(...arguments);
  getStyles(r);
  return r;
}

// stop svg js animation
window.requestAnimationFrame=function(){}

// handle data
var stylesA=[], styles={};
var total=0, styleLoaded;
var closeBut;

function getStyles(o) {
  stylesA=parseObj(o, [], ['styles', 'stylesList', 'style']);
  stylesA.forEach((e) => {
    if (e.id && !styles[e.id]) {
      styles[e.id]=Object.assign({}, e);
      total++;
      }
    });
  }

function parseObj(o, A, n=[]) {
  var k, v;
  if ( (typeof o != 'object') || !Array.isArray(A)) return;
  for (k in o) {
    v=o[k];
    if ((typeof v == 'object') && n.includes(k)) A=A.concat(v);
    if (typeof v == 'object') A=parseObj(v, A, n);
    }
  return A;
  }

var done, newL, Tit, title, title0='Website Themes & Skins by Stylish | Userstyles.org',
    userID, cancelNextRS=0, dontCancel='', site='',
    bgPage='/', blockTitle;

if (document.readyState != 'loading') init('"already done"', 1);
else {
  document.addEventListener('DOMContentLoaded', (ev) => { init('DOM');} );
  window.addEventListener('load', (ev) => { init('wLoad', 1);} );
  }


function chkState(a) {
  var u=a[2];
  if (u == '/styles/browse') {
    if (bgPage.startsWith(u)) u=bgPage;
    } 
  else if (u.startsWith('/styles/[styleId]/')) {
    title='';
    document.title=title0;
    u=bgPage;
    }
  else if (u.startsWith('/user-profile/[...userId]')) {
    if (userID || __NEXT_DATA__) {
      u='/user-profile/'+(userID || __NEXT_DATA__.query.userId);
      }
    }
  a[2]=u;
  }

// hide logo when scrolled. (saves cpu on old hardware)
var Logo, LHidden=false;
function hideLogo() {
  function toggle(set) {
    if ( Logo=(Logo && Logo.parentNode && Logo) || document.querySelector('[class^="welcome-banner_top_"] svg') )
      LHidden=Logo.classList.toggle('hideMe',set);
    else LHidden=set;
    }
  window.addEventListener('scroll', function() {
    if (window.scrollY > 200) {
      if (LHidden) return;
      toggle(true);
      }
    else if (LHidden) toggle(false);
    });
  }

var reactID;

function init(v, old) {
  if (done) return;
  newL=document.querySelector('#__next');
  if (!newL) {
    if (old && ST) ST.remove(); 
    return;
    }
  addSt();
  hideLogo();
  let t;
  done=true;
  reactID= (t=Object.keys(newL).find( (v) => v.startsWith('__react') )) && t.split('$')[1];
  
  if (__NEXT_DATA__.page == '/styles/[styleId]/[[...styleParams]]') bgPage='/';
  else if ( (__NEXT_DATA__.page == '/styles/browse/[[...categoryParams]]') || (__NEXT_DATA__.page == '/user-profile/[...userId]') )
    bgPage='/'+__NEXT_DATA__.props.metaTagsData.og.url.split('/').slice(3).join('/');
  
  let pushState=history.pushState;
  history.pushState=function(){
    let u=arguments[2];
    // ignore if same state
    if (cancelNextRS && (dontCancel == u) ) {
      dontCancel='';
      }
    else if (cancelNextRS || (u == location.pathname) ) {
      //cancelNextRS=false;
      cancelNextRS && cancelNextRS--;
      dontCancel='';
      selfTitle=blockTitle=true;
      return;
      }
    initial=false;
    firstPage=false;
    chkState(arguments);
    
    if (u.startsWith('/user-profile/') && (u[13] != '[') ) userID=u.split('/')[2];
    if ( (u == '/') || u.startsWith('/user-profile/') || u.startsWith('/styles/browse/') ) bgPage=u;
    
    pushState.apply(history, arguments);
    if (location.pathname.startsWith('/styles/')) {
      addData('from pushState (path)');
      }
    }

  var hback=history.back,
      hforward=history.forward,
      hgo=history.go,
      hreplaceState=history.replaceState;
  
  history.replaceState=function() {
    if (cancelNextRS && (dontCancel == arguments[2]) ) {
      dontCancel='';
      }
    else if (cancelNextRS || (arguments[2] == location.pathname) ) {
      cancelNextRS && cancelNextRS--;
      dontCancel='';
      selfTitle=blockTitle=true;
      return;
      }
    initial=false;
    firstPage=false;
    return hreplaceState.apply(history, arguments);
    }


  window.addEventListener('popstate', (ev) => {
    if (location.pathname.startsWith('/user-profile/')) {
      if (newL.querySelector(':scope > [class^="style_mainWrapper_"]')) {
        let e=newL.querySelector(':scope > [class^="style_mainWrapper_"] a[data-stylish="close-style-page-button"]');
        if (e) {
          e.click();
          }
        }
      }
    else if (location.pathname.startsWith('/styles/')) {
      let i, r, e=document.querySelector('a[href^="'+location.pathname+'"]');

      if (!e) {
        r=newL.querySelectorAll('[class^="styles-list_styleRow_"]');
        let st, ost;
        
        let ID=location.pathname.split('/')[2]
        
        for (i=0; i < r.length; i++) {
          if (r[i]['__reactFiber$'+reactID] && (ID == r[i]['__reactFiber$'+reactID].key.split('-').pop()) ) {
            e=r[i];
            break;
            }
          }
        }

      if (!e) {
        let A=document.querySelector('a[href^="/styles/"][href*="1"]');
        if (A) {
          let react=Object.keys(A).find( (v) => v.startsWith('__reactFiber') );
          e=document.createElement('a');
          e.href=location.pathname;
          e.style='display: none !important;';
          let r=newL.querySelector(':scope > div > [class^="Home_homepageWrapper_"]')
          if (r) r.appendChild(e);
          }
        }
      if (e) e.click();
      }
    else if (location.pathname == '/') {
      let e=newL.querySelector(':scope > [class^="style_mainWrapper_"] a[data-stylish="close-style-page-button"]');
      if (e) {
        cancelNextRS=1;
        e.click();
        }
      }
    });

  
  // check Title
  var Tit = document.querySelector('title'), selfTitle=false;
  new MutationObserver(function(mutations) {
    if (selfTitle) { selfTitle=false; return; }
    if (title && !Tit.textContent.startsWith(title) ) {
      document.title=title;
      selfTitle=true;
      }
    }).observe(Tit, { attributes: false, subtree: false, childList: true });

  site=document.title.split('|')[1] || '';
  if (site) site=' |'+site;

  // detect (no) popup
  new MutationObserver(function(mutations) {
    if (!newL.querySelector(':scope > [class^="style_mainWrapper_"]')) {
      title='';
      document.title=title0;
      if (location.pathname.startsWith('/styles/')) {
        if (firstPage && !initial) {
          }
        }
      }
    else {
      addData('from is popup');
      }
    
    }).observe(newL, { attributes: false, subtree: false, childList: true });

  // mutation add-er
  
    // sub Mut
    function mutToast() {
      let r=newL.querySelector(':scope > .Toastify ~ div[class=""], :scope > .Toastify ~ div[class^="MainLayout_mainLayout__"]');
      if (r && r.attributes.obs) {
        return;
        }
      if (r) {
        new MutationObserver(function(muts) {
        for (let mut of muts) {
          if (mut.addedNodes.length && mut.previousSibling && (mut.previousSibling.localName == 'header') ) {
            addDataTiles();
            watchGrid();
            break;
            }
          }          
        }).observe(r, { attributes: true, subtree: false, childList: true });
        r.setAttribute('obs', 'tiles');
        }

      // added cards ?
      watchGrid();
      }

    function watchGrid() {
      var r=newL.querySelector('[class^="styles-grid_gridItems_"]') ||
        newL.querySelector('[class^="styles-gallery_scrollWrapper_"] > div:not([class])');
      if (r.attributes.obs) {
        return;
        }
      if (r) {new MutationObserver(function(muts) {
        for (let mut of muts) {
          if (mut.addedNodes.length) { 
            addDataTiles();
            break;
            }
          }          
        }).observe(r, { attributes: true, subtree: false, childList: true });
        r.setAttribute('obs', 'grid');
        }
      }

  new MutationObserver(function(muts) {
    let mut;
    for (mut of muts) {
      
      // new body
      if (mut.addedNodes.length && mut.previousSibling && (mut.previousSibling.className == 'Toastify') ) {
        addDataTiles();

        // new list
        mutToast();
        break;
        }
      
      } 
    }).observe(newL, { attributes: false, subtree: false, childList: true });
  newL.setAttribute('obs', null);
  mutToast();
  addDataTiles();

  if (location.pathname.startsWith('/styles/')) {
        setTimeout((e) => {addData('from ini '+v)}, 0);
        }
  }

var totalI, styleID, showCSS, loadCSS;

function getCSS(id, callback) {
  if (id && (typeof callback == 'function') ) {
    fetch('https://gateway.userstyles.org/styles/getStyleCss/'+id)
      .then((response) => response.json())
      .then((data) => callback(data));
    }
  }

function addData() {
  var id=styleID=location.pathname.split('/')[2],
      s=styles[id];

  if (initial) {
    // this is the only case when this has to be done.
    var t=newL.querySelector('[class^="style-header_close_"]')
    if (!closeBut || (closeBut !== t) ) {
      closeBut=t;
      if (closeBut) {
        closeBut.addEventListener('click', function() {
          cancelNextRS=1;
          dontCancel='/';
          title='';
          document.title=title0;
          history.pushState({}, null, '/');
          });
        }
      }
    }
  
  if (!s) return;
  var a=document.querySelector('#weekly-installs');
  if (!a) return;

  if (!totalI || !totalI._root.parentNode) {
    totalI=a.cloneNode(true);
    totalI.id='totalInstalls';
    totalI.dataset.tooltipContent='';
    totalI._v=totalI.querySelector(':scope div span');
    totalI._v.textContent='';
    var tt=a.nextElementSibling, ttTI;
    if ( tt.attributes.role && (tt.attributes.role.value == 'tooltip') ) ttTI=tt.cloneNode(true);
    if (!ttTI) {
      ttTI=document.createElement('div');
      ttTI.innerHTML='<div role="tooltip" _model class="react-tooltip styles-module_tooltip__mnnfp styles-module_dark__xNqje react-tooltip__place-top styles-module_show__2NboJ" style="visibility: hidden;">test<div class="react-tooltip-arrow styles-module_arrow__K0L3T" style="left: 40px; bottom: -4px;"></div></div>';
      ttTI=ttTI.firstElementChild;
      tt=totalI;
      }
    if (ttTI) {
      a.parentNode.insertBefore(ttTI, tt.nextSibling);
      if (ttTI.childNodes.length == 1) {
        let T=document.createTextNode('Total installs');
        ttTI.insertBefore(T, ttTI.firstChild);
        }
      else ttTI.childNodes[0].textContent='Total installs';
      totalI.onmouseenter=function(){
        ttTI.style.opacity='0.9';
        ttTI.style.visibility='visible';
        if (ttTI._init) return;
        ttTI._init=true;
        if (ttTI.attributes._model) {
          ttTI.style.top=(totalI.offsetTop - 47) +'px'; 
          ttTI.style.left=(totalI.offsetLeft -10) +'px';
          }
        else {
          ttTI.style.left=(totalI.offsetLeft - a.offsetLeft + tt.offsetLeft)+'px';
          ttTI.style.top=tt.style.top;
          ttTI.firstElementChild.setAttribute('style', tt.firstElementChild.attributes.style.value);
          }
        };
      totalI.onmouseleave=function(){ttTI.style.opacity='0'; ttTI.style.visibility='hidden';};
      }
    var i=totalI.querySelector(':scope > svg'), i2;
    if (i) {
      i2=i.cloneNode(true);
      totalI.insertBefore(i2, i.nextSibling);
      i2.style='margin-left: -17px';
      }
    a.parentNode.insertBefore(totalI, (tt || a).nextSibling);
    totalI._root=totalI.closest('[class^="style_mainWrapper_"]');

    showCSS=totalI._root.querySelector('[class*="style-info_showCss_"]');
    if (showCSS) {
      new MutationObserver(function(mutations) {
        let e;
        if (e=showCSS.parentNode.querySelector('[class^="Popup_modalWrapper_"] textarea')) {
          if (loadCSS) {loadCSS=0; return;}
          if (styles[styleID].sourceCode) e.value=styles[styleID].sourceCode;
          else {
            e.value='';
            getCSS(styleID, function(v){e.value=styles[styleID].sourceCode=v.result;} );
            }
          }
        }).observe(showCSS.parentNode, { attributes: false, subtree: false, childList: true });
      }
    }
  else {
    let e=totalI._root.querySelector('[class^="Popup_modalWrapper_"] textarea');
    if (e) {
      if (styles[styleID].sourceCode) e.value=styles[styleID].sourceCode;
      else {
        e.value='';
        getCSS(styleID, function(v){e.value=styles[styleID].sourceCode=v.result;} );
        }
      }
    }

  let v=parseInt(s.totalInstallsCount);
  let vd=a.querySelector('span'), vdv=vd.innerText;
  if (vdv.endsWith('k')) vdv=Math.floor(parseFloat(vdv) * 1000);
  else vdv=parseInt(vdv);
  if (vdv > v) {vd.style='text-decoration: line-through; text-decoration-color: red;';}
  else vd.style='';
  if (v > 1000) v=(v/1000).toFixed(1)+'k';
  totalI._v.textContent=v;
  document.title=title=s.name+site;

  setTimeout(function(){
    if (!totalI._root.parentNode) addData('after');
    },10);
  }

function addDataTiles() {
  var a=document.querySelectorAll('[data-stylish^="strip-cube-styles"]:not(._done), [data-stylish^="grid-cube-styles"]:not(._done)');
  
  a.forEach((e) => e.classList.add('_done'));
  var i=0;
  add2Tiles();
  
  function add2Tiles() {
    var max=Date.now() + 100;
    for (; i < a.length; i++) {
      if (Date.now() > max) {
        setTimeout(add2Tiles, 0);
        return;
        }
      
      let e=a[i].querySelector('[class*="style-cube_activeUsers_"]');
      if (!e) continue;
      let h=a[i].querySelector('a[href^="/styles/"]');
      if (!h) continue;
      let s=styles[h.pathname.split('/')[2]];
      if (!s) continue;
  
      let r=a[i].querySelector('[class^="style-cube_styleDetails_"]');

      let tot=e.cloneNode(true);
      e.title='Weekly installs';
      tot.classList.add('_totalInstalls');
      tot.title='Total installs';
      let _v=tot.querySelector(':scope div span');
      _v.textContent='';
      
      let I=tot.querySelector(':scope > svg'), i2;
      if (I) {
        i2=I.cloneNode(true);
        tot.insertBefore(i2, I.nextSibling);
        i2.style='margin-left: -9px';
        }
      
      // insert total
      e.parentNode.insertBefore(tot, e);
  
      let v=parseInt(s.totalInstallsCount);
      if (v > 1000) v=(v/1000).toFixed(1)+'k';
      _v.textContent=v;
      
      // add dates
      e=document.createElement('div');
      e.className='_dates_';
      let C=s.created.split('T')[0], U=s.updated.split('T')[0];
      e.innerHTML=(C == U ? '':'<span title="Last updated">'+U+'</span>')+'<span title="Date created">'+C+'</span>';
      r.appendChild(e);
      
      // add user name
      e=a[i].querySelector('[class^="style-cube_authorAvatar_"]');
      if (e) e.title=s.user.name;
      }
    }
  }


var iST=`
.hideMe {
  display: none;
}
div[class^="style_mainWrapper__"] {
  padding-top: 0;
}

[data-stylish^="strip-cube-styles"] [class^="style-cube_topWrapper_"],
[data-stylish^="grid-cube-styles"] [class^="style-cube_topWrapper_"] {
  margin-bottom: 0;
}
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"],
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] {
  flex-direction: row wrap;
  background: var(--bg, gray);
  margin-top: 2px;
  transition: unset !important;
  transition-delay: unset !important;
  padding-top: 2px;
  color: white;
}
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"] > *,
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] > * {
  text-overflow: ellipsis;
  overflow: hidden;
  word-break: break-all;
}
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_activeUsers_"],
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_activeUsers_"] {
  width: auto !important;
  margin-left: auto;
}
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_activeUsers_"] + [class^="style-cube_activeUsers_"],
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_activeUsers_"] + [class^="style-cube_activeUsers_"] {
  margin-left: 1em;
}
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_activeUsers_"] svg,
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_activeUsers_"] svg {
  fill: white;
  display: block;
}
  
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_name_"] *,
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] [class^="style-cube_name_"] * {
  text-overflow: ellipsis;
  overflow: hidden;
}
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"] > [class^="style-cube_styleName_"],
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] > [class^="style-cube_styleName_"] {
  oline-height: normal;
  flex-basis: calc(100% - 40px);
}
[data-stylish^="strip-cube-styles"] [class^="style-cube_styleDetails_"] > [class^="style-cube_details_"],
[data-stylish^="grid-cube-styles"] [class^="style-cube_styleDetails_"] > [class^="style-cube_details_"] {
  width: auto !important;
  margin-left: auto;
  ooutline: 2px solid red !important;
}

[data-stylish^="strip-cube-styles"] [class*="style-cube_withHover_"]:hover,
[data-stylish^="grid-cube-styles"] [class*="style-cube_withHover_"]:hover {
  transform: unset !important;
  transition: unset !important;
  transition-delay: unset !important;
  background-color: unset !important;
  --bg: DarkSlateGrey;
}

._dates_._dates_ {
  flex-basis: 100%;
  margin-top: 2px;
  text-align: right;
}
._dates_ span {
  color: lightgray;
  font-size: 11px;
}
._dates_ span + span {
  margin-left: 1em;
}

[class^="styles-strip_stripItemsWrapper_"] > button {
  display: none !important;
}
[class^="styles-strip_stripItemsWrapper_"] {
  overflow-x: scroll;
  padding-bottom: 4px;
}
[class^="styles-strip_stripItemsWrapper_"]::-webkit-scrollbar {
  height: 8px !important;
}
[class^="styles-strip_items_"] {
  transform: unset !important;
}

:not(g):not(button):not([class^="style_mainWrapper_"])) {
  transform: unset !important;
  transition: unset !important;
  transition-delay: unset !important;
}
svg[transform*="rotate(-180)"] {
  transform: rotate(-180deg) !important;
}

[class^="category-filter_borderRadios_"] {
  display: none;
}

[class^="styles-list_styleName_"] {
  word-break: break-word;
}

[role="tooltip"] .react-tooltip-arrow {
  bottom: -7px !important;
  border-color: var(--rt-color-dark) transparent;
  border-style: solid;
  border-width: 7px 7px 0 7px;
  display: block;
  background: transparent;
  transform: none;
}

#totalInstalls {
  order: -1;
}

/* fix prothemes sliding right-left - 20230613*/
[class^="styles-strip_sliderWrapper_"][class*="styles-strip_lastPage_"] {
  left: -40px !important;
  right: auto !important;
}
`;

addSt();

var ST;
function addSt() {
  if (!iST) {
    document.documentElement.appendChild(ST);
    return;
    }
  try {
    ST=document.createElement('style');
    document.documentElement.appendChild(ST);
    ST.textContent=iST;
    iST='';
  }catch(e){
    setTimeout(addSt,0); }
}


})();