IMDb - fix rating

Recompute a new film rating value based on your criterias

2022-04-20 या दिनांकाला. सर्वात नवीन आवृत्ती पाहा.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         IMDb - fix rating
// @namespace    https://github.com/Procyon-b
// @version      0.5.3
// @description  Recompute a new film rating value based on your criterias
// @author       Achernar
// @include      /^https:\/\/www\.imdb\.com\/title\/[^\/]+\/(episodes|reference|ratings)?(\?.*)?$/
// @match        https://www.imdb.com/chart/*
// @match        https://www.imdb.com/search/title/*
// @match        https://www.imdb.com/list/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM.registerMenuCommand
// @grant        GM_listValues
// @grant        GM_deleteValue
// @run-at       document-end
// ==/UserScript==

(function() {
"use strict";

var E, Ep, Er, rt, tv, opts, dialog,
  Layouts={
    'title':{
      L:'[data-testid="hero-rating-bar__aggregate-rating"]',
      rt:'span[class^="AggregateRatingButton__RatingScore-sc-"], [data-testid="hero-rating-bar__aggregate-rating__score"] span',
      tv:'div[class^="AggregateRatingButton__TotalRatingAmount-sc-"], [data-testid="hero-rating-bar__aggregate-rating__score"] ~ :last-child',
      divide:true,
      type:'page'
      },
    'reference':{
      L:'.titlereference-header .ipl-rating-star',
      rt:'.titlereference-header .ipl-rating-star .ipl-rating-star__rating',
      tv:'.titlereference-header .ipl-rating-star .ipl-rating-star__total-votes',
      tvF:function(tv,r) {
        if (!tv || !r) return;
        let vtv=r.querySelector('.vtv');
        if (!vtv) {
          let RE=/^(.*?)([^()]+)(.*)$/s.exec(tv.innerText);
          tv.innerHTML=(RE[1]||'')+'<span class="vtv">'+RE[2]+'</span>'+(RE[3]||'');
          vtv=tv.querySelector('.vtv');
          }
        return vtv;
        },
      type:'page'
      },
    'ratings':{
      L:'.subpage_title_block__right-column .ipl-rating-widget',
      rt:'.subpage_title_block__right-column .ipl-rating-widget .ipl-rating-star__rating',
      type:'page'
      },
    'EpLst':{
      L:'.eplist .list_item',
      rt:'.ipl-rating-widget .ipl-rating-star .ipl-rating-star__rating',
      tv:'.ipl-rating-widget .ipl-rating-star .ipl-rating-star__total-votes',
      tvF:function(tv,r) {
        if (!tv || !r) return;
        let vtv=r.querySelector('.vtv');
        if (!vtv) {
          let RE=/^(.*?)([^()]+)(.*)$/s.exec(tv.innerText);
          tv.innerHTML=(RE[1]||'')+'<span class="vtv">'+RE[2]+'</span>'+(RE[3]||'');
          vtv=tv.querySelector('.vtv');
          }
        return vtv;
        },
      nm:'a[itemprop="url"]:only-child, a.add-image ~ div',
      url:'a[itemprop="name"]',
      tit:'page',
      type:'list'
      },
    'Chart':{
      k:'chart',
      L:'.lister-list > tr',
      rt:'.ratingColumn.imdbRating > strong',
      url:'.titleColumn a[href*="/title/"]',
      titF:function(tit, r){
        if (!tit || !r) return;
        let n=tit.nextElementSibling;
        return tit.innerText + (n?' '+n.innerText:'');
        },
      tit:'item',
      type:'list'
      },
    'List':{
      k:'list',
      L:'.article.listo .lister-list > div',
      rt:'.ipl-rating-widget .ipl-rating-star__rating',
      tv:'.lister-item-content > p.text-muted.text-small > span[name="nv"]',
      url:'.lister-item-content a[href*="/title/"]',
      titF:function(tit, r){
        if (!tit || !r) return;
        let n=tit.nextElementSibling;
        return tit.innerText + (n?' '+n.innerText:'');
        },
      tit:'item',
      type:'list'
      },
    'Search':{
      k:'search',
      L:'.lister-list > div',
      rt:'.inline-block.ratings-imdb-rating > strong',
      tv:'.sort-num_votes-visible [name="nv"]',
      url:'.lister-item-content a[href*="/title/"]',
      titF:function(tit, r){
        if (!tit || !r) return;
        let n=tit.nextElementSibling;
        return tit.innerText + (n?' '+n.innerText:'');
        },
      tit:'item',
      type:'list'
      },
    'SearchCompact':{
      k:'search',
      L:'.lister-list > div',
      rt:'.col-imdb-rating > strong',
      url:'.lister-item-header a[href*="/title/"]',
      titF:function(tit, r){
        if (!tit || !r) return;
        let n=tit.nextElementSibling;
        return tit.innerText + (n?' '+n.innerText:'');
        },
      tit:'item',
      type:'list'
      }
    };

var XHRqueue=[], XHRqueueV, purging;

function rstXHRq() {
  XHRqueue=[];
  XHRqueueV=Date.now();
  }

var defOpts={
    voters: '',
    k10: false,
    k10_max: false,
    k10_maxmax: false,
    k9_pc_10: 20,
    k9_max_do: false,
    k9_max: false,
    k9_max_10: false,
    k10_9_pcOn: false,
    k10_9_pc: 90,
    k1: false,
    purge: 16,
    search: false,
    chart: false,
    list: false
    };

var List, rtQS, tvQS, nmQS, urlQS, tvF, LO;
// look for rates
for (let k in Layouts) {
  LO=Layouts[k];
  if (LO.type=='page') {
    E=document.querySelector(LO.L);
    if (E) break;
    continue;
    }
  List=document.querySelectorAll(LO.L);
  if (List.length) {
    rtQS=LO.rt;
    // rating found?
    if (!rtQS || (!List[0].querySelector(rtQS) && (List[1] && !List[1].querySelector(rtQS)) && (List[2] && !List[2].querySelector(rtQS)) ) ) {
      List=[]; continue;}
    tvQS=LO.tv;
    nmQS=LO.nm;
    urlQS=LO.url;
    tvF=LO.tvF;
    break;
    }
  }


function getOpts() {
  opts=GM_getValue('opts', {});
  opts= Object.assign({}, defOpts, opts);
}
getOpts();

addSt(`
.oldVal::before {
  content: var(--oldSc);
  font-size: 0.8em;
  margin-right: 0.6em;
  text-decoration: line-through brown;
  line-height: 1em;
  color: gray;
}
.oldVal.noMod::before {
  content: "=" !important;
  text-decoration: none !important;
}
.waiting.oldVal::before {
  content: "?" !important;
  text-decoration: none !important;
}
div[class^="AggregateRatingButton__ContentWrap-sc-"]:hover .oldVal::before,
.rating-bar__base-button:hover .oldVal::before,
.ipl-rating-star.small:hover .oldVal::before, .oldVal:hover::before {
  text-decoration: none !important;
}

[data-testid="hero-rating-bar__aggregate-rating"] {
  position: relative;
}
#fix_rating_opt {
  position: absolute;
  color: black;
  background-color: white;
  top: 5em;
  z-index: 10000 !important;
  font-size: 13px;
  font-family: arial;
  line-height: 1.4em;
  padding: 3px 8px;
  border: 2px solid gray;
  margin: 0 50%;
}
#fix_rating_opt.list {
  position: fixed;
}
#fix_rating_opt {
  white-space: nowrap;
}
#fix_rating_opt #close {
  float: right;
  color: red;
  cursor: pointer;
  z-index: 2;
  position: relative;
}
#fix_rating_opt input[type="number"] {
  width: 3em;
}
#fix_rating_opt input[type="checkbox"] {
  vertical-align: middle;
}
#fix_rating_opt .mrg {
  margin-left: 1em;
}
#fix_rating_opt button, #fix_rating_opt input[type="button"] {
  font-weight: initial;
  padding: 1px 6px;
  cursor: initial;
}
#fix_rating_opt b {
  font-weight: bolder;
}
#fix_rating_opt.list #reset ~ *:not(.show) {
  display: none;
}
#fix_rating_opt span {
  font-size: inherit !important;
  line-height: inherit !important;
}
#fix_rating_opt input[type="checkbox"] {
  margin: 0 3px;
}
#fix_rating_opt input, #fix_rating_opt button {
  margin: 0 0 1px 0;
}
#fix_rating_opt input[type="number"] {
  padding: 0 !important;
  line-height: 1em !important;
}
#fix_rating_opt hr {
  border: none !important;
  height: 0 !important;
  margin-block-start: 0.3em !important;
  margin-block-end: 0.3em !important;
}
#fix_rating_opt #cached {
  display: inline-block;
  vertical-align: top;
}
#fix_rating_opt [name="k9_max_do"]:not(:checked) + .mrg {
  display: none;
}
#fix_rating_opt #hdr {
  cursor: grab;
  background: lightgray;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  padding: 3px 8px;
}
#fix_rating_opt.grabbed #hdr {
  cursor: grabbing;
}
`);

GM.registerMenuCommand('Settings', function(){
  showCfg();
  });

var trig=E || document.querySelector('h1.header');

if (trig) trig.addEventListener('click', function(ev){
  if (ev.ctrlKey && ev.altKey) {
    ev.preventDefault();
    ev.stopPropagation();
    showCfg();
    }
  }, {capture:true});

// init dialog
if (!E) if ( (!opts.search && (LO.k=='search'))
    || (!opts.chart && (LO.k=='chart'))
    || (!opts.list && (LO.k=='list'))
   ) {
  List=[];
  }


function getListRating() {
  if (!List || !List.length) return;
  rstXHRq();
  getOpts();
  let w=10;
  List.forEach(function(Ep){
    var url=urlQS && Ep.querySelector(urlQS),
      tit=(LO.titF && LO.titF(url,Ep)) || (url && url.innerText),
      nm=nmQS && Ep.querySelector(nmQS),
      num=nm? nm.innerText.replace(/^.*?(\d+).*?(\d+).*$/ms, '$1.$2') :'',
      rt=rtQS && Ep.querySelector(rtQS),
      tv=tvQS && Ep.querySelector(tvQS);

    if (!rt && !tv) return;
    if (tvF) tv=tvF(tv,Ep);
    if (rt && !decSep) {
      let RE=/^.*([\D]).*$/.exec(rt.innerText);
      if (RE) decSep=RE[1];
      }
    if (tv && !thSep) {
      let RE=/\d([\D])\d\d\d$/.exec(tv.innerText);
      if (RE) thSep=RE[1];
      }

    if (tit && (LO.tit=='page')) tit=document.title.replace(/ +- imdb *$/i,'')+(num?' - '+num:'')+' - '+tit;
    setTimeout(function(){display(url.pathname, rt, tv, tit);},w);
    w+=10;
    });
  }


var decSep, thSep;

if (E) {
  rt=document.querySelector(LO.rt);
  tv=document.querySelector(LO.tv);
  if (!rt) return;
  if (tv && LO.tvF) tv=LO.tvF(tv,E);
  if (rt && !decSep) {
    let RE=/^.*([\D]).*$/.exec(rt.innerText);
    if (RE) decSep=RE[1];
    }
  if (tv && !thSep) {
    let RE=/\d([\D])\d\d\d$/.exec(tv.innerText);
    if (RE) thSep=RE[1];
    }
  let RE=/^.*([\D]).*$/.exec(rt.innerText);
  if (RE) decSep=RE[1];
  // imdb script rewriting the values
  let obs=new MutationObserver(function(mutL){
    for (let mut of mutL) {
      if (mut.type=='characterData') {
        let n=mut.target.parentNode;
        if (n.curV && (n.curV != n.innerText)) {
          n.innerText=n.curV;
          }
        }
      }
    });
  obs.observe(E, {childList: false, subtree: true, characterData:true});

  display(location.pathname, rt, tv, '', {divide:LO.divide});
  }
else {
  getListRating();
  if (List.length) {
    var ec=document.querySelector('#episodes_content');
    if (ec) {
      new MutationObserver(function(mutL){
        if (mutL[0].addedNodes.length) {
          setTimeout(function(){
            List=document.querySelectorAll(LO.L);
            getListRating();
            },0);
          }
        }).observe(ec, {childList: true, subtree: false});
      }
    else if (ec=document.querySelector('.lister.list.detail.sub-list > .row.lister-working.hidden')) {
      new MutationObserver(function(mutL){
        if ( (mutL[0].attributeName == 'style') && (mutL[0].target.style.display == 'none') ) {
          setTimeout(function(){
            List=document.querySelectorAll(LO.L);
            getListRating();
            },0);
          }
        }).observe(ec, {childList: true, subtree: false, attributes: true});
      }
    }
  }

// init dialog
if (!dialog) display();


function addSt(s,t) {
  let st=document.createElement('style');
  try{
    (document.head || document.documentElement).appendChild(st);
    st.textContent=s;
  }catch(e){
    if (t) document.addEventListener('DOMContentLoaded',function(){addSt(s);});
    else setTimeout(function(){addSt(s,t);},0);
    }
  }

function showCfg() {
  let xy=E && E.getBoundingClientRect();
  if (E) dialog.style='top:'+(window.scrollY+parseInt(xy.y)+80)+'px;';
  else dialog.classList.add('list');
  document.body.appendChild(dialog);
  }


function display(href, rt, tv, tit='', o={}) {

function waiting(v) {
  rt && rt.classList.toggle('waiting', v);
  tv && tv.classList.toggle('waiting', v);
}

rt && rt.classList.add('oldVal');
tv && tv.classList.add('oldVal');

function sendXHR(a) {
  if (!a || !a.R) return;
  a.R.open('GET', '/title/'+a.id+'/ratings'+a.v);
  a.R.send();
  }

function getRatings(id, vt=opts.voters) {
  waiting(true);
  var v, R=new XMLHttpRequest(), XHRqV=XHRqueueV;
  R.addEventListener('error',function(){
    if (XHRqV != XHRqueueV) return;
    setTimeout(function(){
      sendXHR(XHRqueue.shift());
      },0);
    });

  R.addEventListener('load',function(r){
    if (XHRqV != XHRqueueV) return;
    parse(this.responseText, vt);
    setTimeout(function(){
      sendXHR(XHRqueue.shift());
      },50);
    });

  switch(vt) {
    case '': v=''; break;
    case 'us': v='?demo=us_users'; break;
    case 'nus': v='?demo=non_us_users'; break;
    case 'top': v='?demo=top_1000_voters'; break;
    default: return;
    }

  if (!XHRqueue.length) {
    setTimeout(function(){ sendXHR(XHRqueue.shift()); },0);
    setTimeout(function(){ sendXHR(XHRqueue.shift()); },400);
    }
  XHRqueue.push({R,id,v});
  } // END getRatings()

var v, pc, tot, A={}, A0={}, A8={}, voters, votersL, h=[-1,-1], H=[], mod;

function fill_H(a) {
  H=[];
  for (let k in a) {
    H.push( ('000000000'+a[k].tot).substr(-10) +'_'+ ('0'+k).substr(-2) );
    }
  H.sort().reverse();
  for (let i in H) H[i]=[ parseInt(H[i].split('_')[1]), parseInt(H[i].split('_')[0])];
  }

function parse(s,voters='') {
  var parser=new DOMParser(), S=Date.now(),
    h=parser.parseFromString(s, 'text/html'),
    data=h.querySelectorAll('table td'),
    R={};

  // extract rating value % tot
  var i, j, k;
  k=pc=tot=null; A={}; A0={}; h=[-1,-1]; /*H=[];/**/
  // error in parsing
  if ( (v=parseInt(data[0].innerText)) !==10 ) {
    R.status='data unavailable';
    R.maxAge=S+3600000; // +1h
    for (k=1; k<11 ; k++) {
      A0[k]={k,pc:0,tot:0};
      }
    }
  else for (i=0; v=data[i].innerText; i++) {
    if (k==null) k=parseInt(v);
    else if (pc==null) pc=parseFloat(v) || 0;
    else if (tot==null) {
      tot=parseInt(v.replace(/\D/g,'')) || 0;
      if (tot>h[1]) h=[k,tot];
      A0[k]={k,pc,tot};
      if (k==1) break;
      k=pc=tot=null;
      }
    }

  data=h=null;

  fill_H(A0);

  let d=new Date(), key=id+voters;
  let ep=document.querySelector('[class*="EpisodeNavigationForEpisode__SeasonEpisodeNumbers-"]') || '';
  if (ep) ep=ep.innerText.replace(/^.*?(\d+).*?(\d+).*$/s, '$1.$2');
  let t=d.getFullYear()+'/'+String(d.getMonth() + 1).padStart(2, '0')+'/'+ String(d.getDate()).padStart(2, '0') +' '+
    String(d.getHours()).padStart(2, '0')+':'+String(d.getMinutes()).padStart(2, '0');

  Object.assign(R,
   {t:S, key, cmt: t +' -- '+
    ( tit? tit : document.title.replace(/ +- +imdb *$/i,'').replace(/"(.+?)"/, ep?'$1 - '+ep+' -':'$1') )
    , data:JSON.stringify({A0,H}) });
  GM_setValue(key, R);
  fill_vars(R);
  upd_ratings();
  // upd cache date
  upd_dialog();
  } // END parse()

function upd_ratings() {
  if (!ratings || !ratings.key || (ratings.key != id+opts.voters) ) {
    loadRatings();
    return;
    }

  A=JSON.parse(JSON.stringify(A0));
  mod=false;

  if (opts.k10_maxmax && (H[0][0]==10) ) {
    if (A[9].tot < (A[10].tot * opts.k9_pc_10 /100) ) { delete A[10]; mod=true; }
    }

  if (opts.k10_max && (H[0][0]==10) ) {
    let noCv=true;
    if (noCv) {
      delete A[10]; mod=true;
      if (H[1][0]==9) {
        let _9=A[9].tot, _7=A[7].tot;
        if (opts.k9_7_pcOn && opts.k9_7_pc) if (A[7].tot / H[1][1] < (opts.k9_7_pc / 100) ) {delete A[9]; mod=true;}
        }
      }
    }
  if ( (H[0][0]==9) && opts.k9_max_do) {
    let _9=A[9].tot, _10=A[10].tot;
    if (opts.k9_max) { delete A[9]; mod=true; }
    if (opts.k9_max_10) { delete A[10]; mod=true; }
    else if (opts.k10_9_pcOn && opts.k10_9_pc) if (_10 >= (_9 * opts.k10_9_pc / 100) ) {delete A[10]; mod=true;}
    }
  if (opts.k10) delete A[10];
  if (opts.k1) delete A[1];
  var e, newR=0, newRAlt=0;
  tot=v=0;
  for (let i in A) {
    let k=A[i];
    tot += k.tot;
    v += k.k * k.tot;
    }

  // !!!!! temp
  mod=true;

  newR=(v/tot) || 0;

  for (let i in A) {
    let k=A[i];
    newRAlt += k.k * k.tot / tot;
    }

  waiting(false);

  if (e=rt) {
    if (!e.style.cssText) {
      e.style='--oldSc:"'+e.innerText+'"';
      e.oldV=e.innerText;
      if (decSep) e.oldV=e.oldV.replace( new RegExp('\\'+decSep), '.');
      }
    let t=newR && newR.toFixed(1);
    if (o.no0) t=t.replace(/\.0$/,'');
    e.curV=t;
    e.innerText= t || '!';
    e.classList.toggle('noMod',t == e.oldV);
    }
  if (e=tv) {
    if (!e.style.cssText) {
      e.style='--oldSc:"'+e.innerText+'"';
      e.oldV=e.innerText;
      if (thSep) e.oldV=e.oldV.replace( new RegExp('\\'+thSep,'g'), '');
      if (decSep) e.oldV=e.oldV.replace( new RegExp('\\'+decSep), '.');
      }
    let t = (o.divide && tot)? round(tot) : tot;
    e.curV=t;
    e.innerText=t || '!';
    e.classList.toggle('noMod', parseFloat(t) == parseFloat(e.oldV) );
    }
  // upd cache date
  upd_dialog();
  } // END upd_ratings()

function round(n) {
  var U='';
  for (let u of ['K','M']) {
    if (n>1000) {
      n=(n/1000).toFixed( n<10000? 1:0 );
      U=u;
      }
    }
  return n.toString().replace(/\.0$/,'')+U;
  }

function fill_vars(v) {
  ratings=v;
  ratings.data=JSON.parse(ratings.data);
  A0=ratings.data.A0;
  H=ratings.data.H;
  }

function purge_cache() {
  purging=false;
  var all=GM_listValues(), purge=1000*60*60* (opts.purge||8), now=Date.now();
  for (let i of all) {
    let d=GM_getValue(i);
    if (d && d.t &&
        ( (d.t + purge < now )
        || (d.maxAge && (d.maxAge < now))
        )
       ) {
      GM_deleteValue(i);
      }
    }
}

function getValues(k) {
  ratings=GM_getValue(k, false);
  let now=Date.now();
  if (ratings &&
     ( (ratings.t + (1000*60*60* (opts.purge||8)) < now)
      || (ratings.maxAge && (ratings.maxAge < now) )
     ) 
    ) {
    return 0;
    }
  return Boolean(ratings);
  }

function loadRatings() {
  var unk=[];
  if (!voters) {
    A8={}; ratings8={t:[], key:id+opts.voters, data:{}};
    if (opts.voters=='usnus') {
      voters=['us','nus'];
      }
    else voters=[opts.voters];
    votersL=voters.length;
    }

  for (let i=0,vt; i < voters.length; i++) {
    vt=voters[i];
    if (!getValues(id+vt)) {
      unk.push(vt);
      if (ratings) {
        ratings=null;
        }
      if (voters.length == votersL) { 
        getRatings(id, vt);
        if (!purging) setTimeout(purge_cache,3000);
        purging=true;
        }
      continue;
      }

    fill_vars(ratings);

    if (votersL > 1) {
      merge_A();
      ratings8.t.push(ratings.t);
      }
    else unk=null;
    }

  voters=unk;
  if (votersL > 1) {
    if (!voters.length) {
      voters=null;
      ratings=ratings8;
      A0=ratings.data.A0=A8;
      fill_H(A0);
      ratings.data.H=H;
      }
    }

  if (!voters) {
    upd_ratings();
    }
  }

function merge_A() {
  for (let k in A0) {
    let a=A8[k], b=A0[k];
    if (!a && !b) return;
    A8[k]={k, 'tot': (a?a.tot:0)+b.tot};
    }
  } 


var ratings, ratings8, id, re= /^\/title\/([^\/]+)\/(rating)?/.exec(href);

if (re && re[1]) {
  id=re[1];
  loadRatings();
  }

// exit if dialog already created.
if (dialog) return;

dialog=document.createElement('div');
dialog.id='fix_rating_opt';
dialog.innerHTML=`<div id="close">&#10062;</div>
<!--h3>(Userscript) Fix rating - Settings</h3><!-->
<b id="hdr">Fix rating - Settings</b><hr><br>
<hr>
Count votes from: <select name="voters"><option value="">all voters</option>
<option value="us">US voters</option>
<option value="nus">non-US voters</option>
<option value="top">Top 1000 voters</option>
<option value="usnus">US & non-US voters</option></select>
<hr>
<input name="k10" type="checkbox" data-group="10">Ignore "10"<br>
<input name="k10_max" type="checkbox" data-group="10">Ignore "10" if is highest count<br>
<input name="k10_maxmax" type="checkbox" data-group="10">... "10" highest and if "9" is &lt; <input name="k9_pc_10" type="number" min="1" max="99">% of "10"<br>
<input name="k1" type="checkbox">Ignore "1"<br>
<hr>
<b>If "9" is highest : </b><input name="k9_max_do" type="checkbox">
<div class="mrg"><input name="k9_max" type="checkbox">discard "9"<br>
<input name="k9_max_10" type="checkbox" data-group="9_10">discard "10"<br>
<input name="k10_9_pcOn" type="checkbox" data-group="9_10">discard "10" if &gt;= <input name="k10_9_pc" type="number" min="1" max="99">% of "9"</div>
<hr>
Expire cached values after <input name="purge" type="number" data-norld min="1" max="99"> hours
<hr>
<nobr><input type="button" id="rldSettings" value="Reload settings"> (if modified in another window)</nobr><br>
<input type="button" id="reset" value="Reset to default"><br>
<hr>
<span>Rating values cached on: <span id="cached"></span></span><br>
<input type="button" id="clrCache" value="Refresh cache"><br class="show"><hr class="show"><br>
<div class="show">
<input type="checkbox" name="search" data-norld>Enable on "search" (need page reload)<br>
<input type="checkbox" name="chart" data-norld>Enable on "chart" (need page reload)<br>
<input type="checkbox" name="list" data-norld>Enable on "list" (need page reload)</div>
`;
dialog.querySelector('#close').onclick=function(){dialog.remove();dialog.style='';};
dialog.querySelector('#rldSettings').onclick=function(){
  getOpts();
  upd_dialog();
  upd_ratings();
  getListRating();
  };
dialog.querySelector('#clrCache').onclick=function(){
  getRatings(id, opts.voters);
  };
dialog.querySelector('#reset').onclick=function(){
  if (!confirm("Reset? You'll lose your changes.")) return;
  GM_deleteValue('opts');
  getOpts();
  upd_dialog();
  upd_ratings();
  getListRating();
  };

var cached=dialog.querySelector('#cached');

function upd_opts(e) {
  let k=e.name;
  if (k in opts) {
    if (e.type=='checkbox') opts[k]=e.checked;
    else opts[k]=e.value;
    }
  }

dialog.addEventListener('change', function(ev){
  let t=ev.target, g;
  if (g=t.dataset.group) {
    let a=dialog.querySelectorAll('[data-group="'+g+'"]:checked');
    a.forEach(function(e){
      if (e!==t) {
        e.checked=false;
        upd_opts(e);
        }
      });
    }
  upd_opts(t)
  GM_setValue('opts', opts);
  if ('norld' in t.dataset) return;
  upd_ratings();
  getListRating();
  });

var x=0, y=0, move=dialog.querySelector('#hdr');

function moving(ev) {
  var st=dialog.style;
  var Y= (E?ev.pageY:ev.clientY) -y, X= (E?ev.pageX:ev.clientX) -x;
  if ( (Y<0) || (X<0) ) return;
  st.top=Y+'px';
  st.left=X+'px';
  st.margin='0';
  }

move.onmousedown=function(ev){
  // ignore if not left click
  if (ev.buttons != 1) return;
  ev.preventDefault();
  var cCss=window.getComputedStyle(dialog);
  x=ev.offsetX+parseInt(cCss.borderLeftWidth); y=ev.offsetY+parseInt(cCss.borderTopWidth);
  document.body.addEventListener('mousemove', moving);
  dialog.onmouseup=mouseup;
  dialog.classList.add('grabbed');
  }

function mouseup(ev){
  document.body.removeEventListener('mousemove', moving);
  dialog.onmouseup=null;
  dialog.classList.remove('grabbed');
  }

function fixed(s,n) {
  return ('000'+s).substr(- n);
}

function upd_dialog() {
  if (!dialog) return;
  for (let k in opts) {
    let e=dialog.querySelector('[name="'+k+'"]');
    if (e) {
      if (e.type=='checkbox') e.checked=opts[k];
      else e.value=opts[k];
      }
    }
  if (cached && ratings) {
    let s='', a=ratings.t || [];
    if (!Array.isArray(a)) a=[a];

    for (let t of a) {
      t=new Date(t);
      if (s) s+='<br>';
      s+=t.getFullYear()+'/'+ fixed(t.getMonth()+1,2) +'/'+ fixed(t.getDate(),2) +' '+fixed(t.getHours(),2)+':'+fixed(t.getMinutes(),2);
      }
    cached.innerHTML=s;
    }
  }
upd_dialog();


} // END display()




})();