chuni-net - display overpower

Display song overpower and rating on chunithm-net

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name        chuni-net - display overpower
// @namespace   esterTion
// @license     MIT
// @match       https://chunithm-net-eng.com/mobile/record/music*
// @match       https://chunithm.wahlap.com/mobile/record/music*
// @match       https://new.chunithm-net.com/chuni-mobile/html/mobile/record/music*
// @match       https://chunithm-net-eng.com/mobile/home/playerData/rating*
// @match       https://chunithm.wahlap.com/mobile/home/playerData/rating*
// @match       https://new.chunithm-net.com/chuni-mobile/html/mobile/home/playerData/rating*
// @version     1.1.6
// @author      esterTion
// @description Display song overpower and rating on chunithm-net
// @run-at      document-end
// ==/UserScript==

(async function () {

const host = location.hostname
const server = host === 'new.chunithm-net.com' ? 'jp' : host === 'chunithm-net-eng.com' ? 'ex' : host === 'chunithm.wahlap.com' ? 'cn' : ''
if (!server) throw new Error('unknown server')
const imageBase = server === 'jp' ? '/chuni-mobile/html/mobile/images' : '/mobile/images'

const disabledSongs = {
  ex: [],
  cn: [],
  jp: []
}
const PAGE_TEXT = {
  ONLY_HIGHEST: {
    ex: 'Count highest difficulty only',
    cn: '仅统计最高难度',
    jp: '最高難易度のみ集計する',
  },
  SORT_INITIAL: {
    ex: 'Initial',
    cn: '初始顺序',
    jp: '初期順',
  },
  SORT_DIFFICULTY: {
    ex: 'Difficulty',
    cn: '难度',
    jp: '難易度',
  },
  SORT_SCORE: {
    ex: 'Score',
    cn: '分数',
    jp: 'スコア',
  },
  SORT_OP_REMAIN: {
    ex: 'op remaining',
    cn: 'op 剩余',
    jp: 'op 残り',
  },
  TOTAL_SONG_COUNT: {
    ex: 'Total {} songs',
    cn: '共计 {} 曲目',
    jp: '全 {} 曲',
  },
  AVERAGE_PLAYED: {
    ex: 'Average of played songs: ',
    cn: '已游玩平均:',
    jp: 'プレイ済み平均:',
  },
  RATING_AVERAGE: {
    ex: 'Average: ',
    cn: '平均:',
    jp: '平均:',
  },
  RATING_TOTAL: {
    ex: 'Total: ',
    cn: '总计:',
    jp: '合計:',
  },
}

// createElement
function _(e,t,i){var a=null;if("text"===e)return document.createTextNode(t);a=document.createElement(e);for(var n in t)if("style"===n)for(var o in t.style)a.style[o]=t.style[o];else if("className"===n)a.className=t[n];else if("event"===n)for(var o in t.event)a.addEventListener(o,t.event[o]);else a.setAttribute(n,t[n]);if(i)if("string"==typeof i)a.innerHTML=i;else if(Array.isArray(i))for(var l=0;l<i.length;l++)null!=i[l]&&a.appendChild(i[l]);return a}

const localStorageTimeKey = 'CNDL_music_level_info_time'
const localStorageDataKey = 'CNDL_music_level_info'
const localStoragePrefHighestOnlyKey = 'CNDL_music_level_info_highest_only'
let musicLevelInfo = {}
function loadLocalInfo() {
  if (!localStorage[localStorageDataKey]) return
  musicLevelInfo = JSON.parse(localStorage[localStorageDataKey])
}
let resultCount = {
  sssp: 0,
  sss: 0,
  ssp: 0,
  ss: 0,
  sp: 0,
  s: 0,
  other: 0,

  max: 0,
  aj: 0,
  fc: 0,
  nonfc: 0,
}
const diffToggles = {
  bas: true,
  adv: true,
  exp: true,
  mas: true,
  ult: true,
  other: true,
}
const diffTogglesDisplay = {
  bas: false,
  adv: false,
  exp: false,
  mas: false,
  ult: false,
  other: false,
}
let musicOnPage
let sortForm
let countHightestOnly = localStorage[localStoragePrefHighestOnlyKey] === '1'
function initPageOverPower() {
  musicOnPage = [...document.querySelectorAll('.musiclist_box .music_title')].map(addOverPowerToList)
  musicOnPage.forEach(i => {
    if (diffTogglesDisplay[i.dif] !== undefined) {
      diffTogglesDisplay[i.dif] = true
    } else {
      diffTogglesDisplay.other = true
    }
  })
  const scoreList = document.querySelector('#scoreList_result')
  if (!scoreList) return
  scoreList.appendChild(_('div', {className: 'box01 w420 CNDO-sort-box'}, [
    _('div', {}, [ sortForm = _('form', { event: { change: applySort }}, [
      _('select', { style: { width: '160px', margin: '10px' }, name: 'key' }, [
        _('option', {value: 'initial'}, [_('text', PAGE_TEXT.SORT_INITIAL[server])]),
        _('option', {value: 'level'}, [_('text', PAGE_TEXT.SORT_DIFFICULTY[server])]),
        _('option', {value: 'score'}, [_('text', PAGE_TEXT.SORT_SCORE[server])]),
        _('option', {value: 'aj'}, [_('text', 'FC/AJ')]),
        _('option', {value: 'op_percent'}, [_('text', 'op %')]),
        _('option', {value: 'op_remain'}, [_('text', PAGE_TEXT.SORT_OP_REMAIN[server])]),
      ]),
      _('select', { style: { width: '96px', margin: '10px' }, name: 'desc' }, [
        _('option', {value: 0}, [_('text', '↑')]),
        _('option', {value: 1}, [_('text', '↓')]),
      ]),
    ])]),
  ]))
  addOverPowerToPage()
}
function addOverPowerToPage() {
  const musics = musicOnPage.filter(i => {
    if (i.disabled) return false
    let on = diffToggles[i.dif]
    on ??= diffToggles.other
    return on
  })
  const countedSize = musics.length
  const filteredSize = musics.filter(i => !countHightestOnly || !i.notHighestLevel).length
  document.querySelector('.CNDO-info-box')?.remove()
  let resultCount = {
    sssp: 0,
    sss: 0,
    ssp: 0,
    ss: 0,
    sp: 0,
    s: 0,
    other: countedSize,

    max: 0,
    aj: 0,
    fc: 0,
    nonfc: countedSize,
  }
  const total = musics.reduce((a, i) => {
    const obj = i.parsed
    if (obj.scoreRank >=8) { resultCount.other--; }
    if (obj.scoreRank >=8) { resultCount.s++; }
    if (obj.scoreRank >=9) { resultCount.sp++; }
    if (obj.scoreRank >=10) { resultCount.ss++; }
    if (obj.scoreRank >=11) { resultCount.ssp++; }
    if (obj.scoreRank >=12) { resultCount.sss++; }
    if (obj.scoreRank >=13) { resultCount.sssp++; }
    if (obj.theoryCount) { resultCount.max++; }

    if (obj.isAllJustice) { resultCount.aj++; }
    if (obj.isFullCombo) { resultCount.fc++; resultCount.nonfc--; }

    if (countHightestOnly && i.notHighestLevel) {
      return a;
    }
    return {rate: a.rate+(i.rate), max: a.max+i.max, playedmax: a.playedmax+(i.rate>0?i.max:0)}
  }, {rate: 0, max: 0, playedmax: 0})
  total.rate /= 100
  total.max /= 100
  total.playedmax /= 100
  // console.log(total, total.rate/total.max*100)

  const scoreList = document.querySelector('#scoreList_result')
  if (!scoreList) return
  let diffToggleForm
  scoreList.appendChild(_('div', {className: 'box01 w420 CNDO-info-box'}, [
    _('style', {}, `

.overpower-graph-base {
  position:relative;
  width:100%;
  height:22px;
  background:#6e6e6e;
  outline:#dddddd 1px solid
}
.overpower-graph-base .bg-gold,
.overpower-graph-base .bg-platinum,
.overpower-graph-base .bg-silver,
.overpower-graph-base .bg-white {
  position:absolute;
  left:0;
  top:0;
  bottom:0
}
.overpower-graph-base .bg-white {
  z-index:12;
  background:linear-gradient(180deg,#fff,#fff 50%,#d0d6da 50%,#e4edf3 75%,#fff)!important
}
.overpower-graph-base .bg-platinum {
  z-index:10;
  background:linear-gradient(180deg,#fff1ba,#ffeb9c 50%,#fc0 50%,#ffeca4 75%,#fff)!important
}
.overpower-graph-base .bg-gold {
  z-index:8;
  background:linear-gradient(180deg,#ffe4a3,#efae10 50%,#ff8300 50%,#ffc947 75%,#fff)!important
}
.overpower-graph-base .bg-silver {
  z-index:6;
  background:linear-gradient(180deg,#c8e7ff,#8fceff 50%,#6eb5ff 50%,#b7ddff 75%,#fff)!important
}
.CNDO-version-box.hide :not(.CNDO-version-title) {
  display:none;
}
.CNDO-version-box.hide .CNDO-version-title::before {
  content: '▶';
}
.CNDO-version-box .CNDO-version-title::before {
  content: '▼';
}

    `),
    _('div', {className: 'narrow_block clearfix', style: {whiteSpace:'pre-wrap'}}, [
      diffToggleForm = _('form', { event: { change: e => {
        diffToggles[e.target.name] = e.target.checked
        musicOnPage.forEach(i => {
          if (i.dif !== e.target.name) return
          i.box.style.display = e.target.checked ? '' : 'none'
        })
        addOverPowerToPage()
      } } }, [
        !diffTogglesDisplay.bas ? new Comment('bas toggle') : _('label', {}, [
          _('input', {type: 'checkbox', name: 'bas', [diffToggles.bas ? 'checked' : 'checked_']: '1' }),
          _('text', 'BAS'),
        ]),
        !diffTogglesDisplay.adv ? new Comment('adv toggle') : _('label', {}, [
          _('input', {type: 'checkbox', name: 'adv', [diffToggles.adv ? 'checked' : 'checked_']: '1' }),
          _('text', 'ADV'),
        ]),
        !diffTogglesDisplay.exp ? new Comment('exp toggle') : _('label', {}, [
          _('input', {type: 'checkbox', name: 'exp', [diffToggles.exp ? 'checked' : 'checked_']: '1' }),
          _('text', 'EXP'),
        ]),
        !diffTogglesDisplay.mas ? new Comment('mas toggle') : _('label', {}, [
          _('input', {type: 'checkbox', name: 'mas', [diffToggles.mas ? 'checked' : 'checked_']: '1' }),
          _('text', 'MAS'),
        ]),
        !diffTogglesDisplay.ult ? new Comment('ult toggle') : _('label', {}, [
          _('input', {type: 'checkbox', name: 'ult', [diffToggles.ult ? 'checked' : 'checked_']: '1' }),
          _('text', 'ULT'),
        ]),
        !diffTogglesDisplay.other ? new Comment('other toggle') : _('label', {}, [
          _('input', {type: 'checkbox', name: 'other', [diffToggles.other ? 'checked' : 'checked_']: '1' }),
          _('text', 'OTHER'),
        ]),
      ]),
      _('label', {}, [
        _('input', {type: 'checkbox', [countHightestOnly ? 'checked' : 'checked_']: '1', event: { change: e => {
          countHightestOnly = e.target.checked
          localStorage[localStoragePrefHighestOnlyKey] = countHightestOnly ? '1' : '0'
          addOverPowerToPage()
        } } }),
        _('text', PAGE_TEXT.ONLY_HIGHEST[server]),
      ]), _('br'),
      _('text', [
        PAGE_TEXT.TOTAL_SONG_COUNT[server].replace('{}', filteredSize),
        `${total.rate} / ${total.max}`,
        (total.rate/Math.max(total.max, 1)*100).toFixed(4)+'%',
        '',
        PAGE_TEXT.AVERAGE_PLAYED[server],
        //`${total.rate} / ${total.playedmax}`,
        (total.rate/Math.max(total.playedmax, 1)*100).toFixed(4)+'%',
        '','',
      ].join('\n')),
      _('table', { style: {width: '100%', fontSize: '16px'} }, [
        _('tr', {}, [
          _('td', {}, [_('text', 'SSS+')]),
          _('td', {}, [_('text', 'SSS')]),
          _('td', {}, [_('text', 'SS+')]),
          _('td', {}, [_('text', 'SS')]),
          _('td', {}, [_('text', 'S+')]),
          _('td', {}, [_('text', 'S')]),
          _('td', {}, [_('text', 'OTHER')]),
        ]),
        _('tr', {}, [
          _('td', {}, [_('text', resultCount.sssp)]),
          _('td', {}, [_('text', resultCount.sss - resultCount.sssp)]),
          _('td', {}, [_('text', resultCount.ssp - resultCount.sss)]),
          _('td', {}, [_('text', resultCount.ss - resultCount.ssp)]),
          _('td', {}, [_('text', resultCount.sp - resultCount.ss)]),
          _('td', {}, [_('text', resultCount.s - resultCount.sp)]),
          _('td', {}, [_('text', resultCount.other)]),
        ]),
      ]),
      _('div', {className: 'overpower-graph-base'}, [
        _('div', {className: 'bg-platinum', style: {width: `${resultCount.sss/countedSize*100}%`}}),
        _('div', {className: 'bg-gold', style: {width: `${resultCount.ss/countedSize*100}%`}}),
        _('div', {className: 'bg-silver', style: {width: `${resultCount.s/countedSize*100}%`}}),
      ]),
      _('table', { style: {width: '100%', fontSize: '16px'} }, [
        _('tr', {}, [
          _('td', {}, [_('text', 'MAX')]),
          _('td', {}, [_('text', 'AJ')]),
          _('td', {}, [_('text', 'FC')]),
          _('td', {}, [_('text', 'OTHER')]),
        ]),
        _('tr', {}, [
          _('td', {}, [_('text', resultCount.max)]),
          _('td', {}, [_('text', resultCount.aj - resultCount.max)]),
          _('td', {}, [_('text', resultCount.fc - resultCount.aj)]),
          _('td', {}, [_('text', resultCount.nonfc)]),
        ]),
      ]),
      _('div', {className: 'overpower-graph-base'}, [
        _('div', {className: 'bg-white', style: {width: `${resultCount.max/countedSize*100}%`}}),
        _('div', {className: 'bg-platinum', style: {width: `${resultCount.aj/countedSize*100}%`}}),
        _('div', {className: 'bg-gold', style: {width: `${resultCount.fc/countedSize*100}%`}}),
      ]),
    ]),
  ]))

  if (diffToggleForm.children.length === 1) {
    diffToggleForm.remove()
  }
  applySort.call(sortForm)
}
function addOverPowerToList(titleDiv, idx) {
  const dif = getDifFromClass(titleDiv.parentNode)
  if (!dif) return null
  const box = titleDiv.parentNode
  const titleText = titleDiv.lastChild.textContent.trim()
  const level = getLevelByTitleAndDif(titleText, dif) * 1
  const returnData = {
    box,
    idx,
    dif,
    level,
    rate: 0,
    disabled: disabledSongs[server].includes(titleText),
    notHighestLevel: true,
    parsed: {},
    max: (level+3) * 500
  }
  const scoreBox = box.querySelector('.play_musicdata_highscore .text_b')
  if (!scoreBox) return returnData
  if (returnData.disabled) {
    return returnData
  }
  const obj = {
    scoreMax:      scoreBox.textContent.replace(/,/g, '')*1,
    maxComboCount: 0,
    isFullCombo:   false,
    isAllJustice:  false,
    isSuccess:     0,
    fullChain:     0,
    maxChain:      0,
    scoreRank:     0,
    isLock:        false,
    theoryCount:   0,
  }
  if (obj.scoreMax === 1010000) { obj.theoryCount = 1; }
  [...box.querySelectorAll('.play_musicdata_icon img')].forEach(i => {
    const icon = i.src.replace(/.+\//, '').replace(/icon_(.+)\.png/, '$1')
    switch (icon) {
      case 'clear': { obj.isSuccess = 1; break }
      case 'hard': { obj.isSuccess = 2; break }
      case 'absolute': { obj.isSuccess = 3; break }
      case 'brave': { obj.isSuccess = 3; break }
      case 'absolutep': { obj.isSuccess = 4; break }
      case 'absolutepp': { obj.isSuccess = 5; break }
      case 'catastrophy': { obj.isSuccess = 6; break }
      
      case 'rank_1': { obj.scoreRank = 1; break }
      case 'rank_2': { obj.scoreRank = 2; break }
      case 'rank_3': { obj.scoreRank = 3; break }
      case 'rank_4': { obj.scoreRank = 4; break }
      case 'rank_5': { obj.scoreRank = 5; break }
      case 'rank_6': { obj.scoreRank = 6; break }
      case 'rank_7': { obj.scoreRank = 7; break }
      case 'rank_8': { obj.scoreRank = 8; break }
      case 'rank_9': { obj.scoreRank = 9; break }
      case 'rank_10': { obj.scoreRank = 10; break }
      case 'rank_11': { obj.scoreRank = 11; break }
      case 'rank_12': { obj.scoreRank = 12; break }
      case 'rank_13': { obj.scoreRank = 13; break }
      
      case 'alljusticecritical':
      case 'alljustice': { obj.isAllJustice = true }
      case 'fullcombo': { obj.isFullCombo = true; obj.missCount = 0; break }
      
      case 'fullchain2': { obj.fullChain = 1; break }
      case 'fullchain': { obj.fullChain = 2; break }
    }
  })
  returnData.parsed = obj

  // lmn+逻辑
  // 存在更高等级的ult,mas不计op
  if (dif === 'mas') {
    const ultLevel = getLevelByTitleAndDif(titleText, 'ult') * 1
    if (level >= ultLevel) {
      returnData.notHighestLevel = false
    }
  } else if (dif === 'ult') {
    const masLevel = getLevelByTitleAndDif(titleText, 'mas') * 1
    if (level > masLevel) {
      returnData.notHighestLevel = false
    }
  }

  returnData.rating = getRatingFromConstantAndScore(level, obj.scoreMax)
  const comboRate = obj.theoryCount ? 125 :
                    obj.isAllJustice ? 100 :
                    obj.isFullCombo ? 50 : 0
  if (obj.scoreMax <= 1007500) {
    // 低于sss
    returnData.rate = Math.floor(returnData.rating*500 * 2) / 2 + comboRate
    addOverPowerAfterScore(scoreBox, returnData)
    return returnData
  }
  const sssRate = Math.floor((obj.scoreMax - 1007500) * 0.15 * 2) / 2
  returnData.rate = (level + 2) * 500 + comboRate + sssRate
  addOverPowerAfterScore(scoreBox, returnData)
  return returnData
}
function addOverPowerAfterScore(scoreBox, returnData) {
  scoreBox.parentNode.appendChild(_('span', {style: {marginLeft: '2em', fontFamily: 'Arial'}}, [
    _('text', (Math.floor(returnData.rate)/100).toFixed(2) + ' / ' + (returnData.max/100).toFixed(2) + ' ' + (returnData.rate/returnData.max*100).toFixed(2)+'%'),
  ]))
}
function getDifFromClass(div) {
	const divClass = [...div.classList].filter(i => i.startsWith('bg_') || i.startsWith('title_'))
	if (!divClass.length) return '?'
	switch (divClass[0]) {
		case 'bg_basic': { return 'bas' }
		case 'bg_advanced': { return 'adv' }
		case 'bg_expert': { return 'exp' }
		case 'bg_master': { return 'mas' }
		case 'bg_ultima': { return 'ult' }

		case 'title_basic': { return 'bas' }
		case 'title_advanced': { return 'adv' }
		case 'title_expert': { return 'exp' }
		case 'title_master': { return 'mas' }
		case 'title_ultima': { return 'ult' }
	}
	return '?'
}
function getLevelByTitleAndDif(title, dif) {
  if (!musicLevelInfo[title]) return 0
  if (!musicLevelInfo[title][dif]) return 0
  return musicLevelInfo[title][dif].replace('+', '.5')
}
var ratingBorder = [
  [1009000, +2.15, 1],
  [1007500, +2.0, 1],
  [1005000, +1.5, 1],
  [1000000, +1.0, 1],
  [975000, +0.0, 1],
  [925000, -3.0, 1],
  [900000, -5.0, 1],
  [800000, -5.0, 2],
  [500000, 0, 1]
];
function getRatingFromConstantAndScore(constant, score) {
  if (constant == 0) return 0;
  if (score >= ratingBorder[0][0]) return constant + ratingBorder[0][1];
  for (var i = 0; i < ratingBorder.length - 1; i++) {
    if (score >= ratingBorder[i + 1][0]) {
      return (constant + ratingBorder[i + 1][1]) / ratingBorder[i + 1][2]
      + (score - ratingBorder[i + 1][0]) / (ratingBorder[i][0] - ratingBorder[i + 1][0])
      * (
      (constant + ratingBorder[i][1]) / ratingBorder[i][2] -
      (constant + ratingBorder[i + 1][1]) / ratingBorder[i + 1][2]
      )
    }
  }
  return 0;
}
function applySort() {
  const form = this
  const key = form.key.value
  const desc = form.desc.value === '1'
  musicOnPage.sort((a, b) => (desc ? -1 : 1) * (a.idx - b.idx))
  if (key !== 'initial') {
    musicOnPage.sort((a, b) => {
      let result = 0
      switch (key) {
        case 'level': { result = a.level - b.level; break }
        case 'score': { result = (a.parsed.scoreMax || 0) - (b.parsed.scoreMax || 0); break }
        case 'aj': { result = toAjScore(a) - toAjScore(b); break }
        case 'op_percent': { result = a.rate/a.max - b.rate/b.max; break }
        case 'op_remain': { result = (a.max - a.rate) - (b.max - b.rate); break }
      }
      return desc ? -result : result
    })
  }
  musicOnPage.forEach((i, idx) => {
    i.box.parentNode.parentNode.appendChild(i.box.parentNode)
  })
}
function toAjScore(i) {
  return i.parsed.theoryCount ? 3 : (
    i.parsed.isAllJustice ? 2 : (
      i.parsed.isFullCombo ? 1 : 0
    )
  )
}

const statisticJudge = [
  ["clear"              , i => i.parsed.isSuccess >= 1 ],
  ["hard"               , i => i.parsed.isSuccess >= 2 ],
  ["absolute"           , i => i.parsed.isSuccess >= 3 ],
  ["absolutep"          , i => i.parsed.isSuccess >= 4 ],
  ["catastrophy"        , i => i.parsed.isSuccess >= 6 ],
  ["rank_8"             , i => i.parsed.scoreRank >= 8 ],
  ["rank_9"             , i => i.parsed.scoreRank >= 9 ],
  ["rank_10"            , i => i.parsed.scoreRank >= 10 ],
  ["rank_11"            , i => i.parsed.scoreRank >= 11 ],
  ["rank_12"            , i => i.parsed.scoreRank >= 12 ],
  ["rank_13"            , i => i.parsed.scoreRank >= 13 ],
  ["fullcombo"          , i => i.parsed.isFullCombo ],
  ["alljustice"         , i => i.parsed.isAllJustice ],
  ["alljusticecritical" , i => i.parsed.theoryCount > 0 ],
  ["fullchain2"         , i => i.parsed.fullChain >= 1 ],
  ["fullchain"          , i => i.parsed.fullChain >= 2 ],
]
const VERSION_MUSIC_LIST = [["CHUNITHM",[3,6,18,21,23,27,33,38,41,45,46,47,48,49,50,51,53,59,63,64,65,67,68,69,70,71,74,75,76,79,80,81,82,83,88,89,91,92,94,95,96,97,98,99,100,101,103,104,105,107,108,113,114,115,117,118,120,128,132,133,134,135,136,138,140,141,142,143,144,145,146,147,148,149,150,151,152,157,158,159,160,161,163,165,166,167,168,169,170,178,179,180,181,203,204]],["CHUNITHM PLUS",[19,35,52,61,62,72,73,90,93,106,121,122,123,131,171,173,177,196,197,199,200,201,202,205,208,210,211,212,213,216,217,220,222,223,224,225,226,227,228,232,233,240,244,245,246,251,252]],["CHUNITHM AIR",[7,37,66,77,102,119,137,186,187,189,190,218,219,229,230,248,250,254,257,259,260,261,262,263,264,267,270,271,272,273,275,276,278,279,280,281,282,283,284,286,287,288,289,290,291,292,293,294,297,298,300,301,302,303,304,305,306,307,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,336]],["CHUNITHM AIR PLUS",[20,191,192,193,194,195,234,249,253,256,258,265,266,268,274,277,295,310,334,335,337,338,339,340,341,342,354,362,363,365,367,368,369,370,371,372,373,374,375,376,377,379,380,381,382,383,384,385,386,388,389,390,393,394,395,396,397,398,399,402,403,404,405,407,409,411,414,416]],["CHUNITHM STAR",[406,421,426,427,430,431,432,433,434,435,436,437,438,439,440,441,442,444,445,446,447,448,449,455,456,457,458,459,463,464,466,467,468,469,470,471,472,475,476,477,478,479,481,482,483,485,486,487,488,489,490,492,493,494,496,497,498,499,500,502,503,504,505,506,512,513,514,516,524,525,528,532,533,535,538,540]],["CHUNITHM STAR PLUS",[24,198,391,413,460,462,465,491,515,534,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,564,565,566,567,568,569,570,572,574,575,577,578,583,585,586,587,588,589,590,592,593,594,595,597,599,600,601,605,606,607,614,615,616,617,618,625,626,627,628,629,631,632,633,635,636,637,638]],["CHUNITHM AMAZON",[517,573,619,653,654,655,656,657,659,662,663,664,665,666,667,668,669,670,671,676,677,678,679,681,683,684,685,686,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,710,711,712,713,715,716,717,720,721,722]],["CHUNITHM AMAZON PLUS",[285,598,604,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,749,750,751,752,753,754,755,756,757,760,761,762,763,764,765,766,768,771,772,773,774,775,776,777,780,781,782,783,784,785,786,787,788,791,792,793,795,796,797,798,799,802,803,804,806,807]],["CHUNITHM CRYSTAL",[429,810,815,816,817,818,819,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,848,849,850,851,852,853,854,856,858,859,860,863,865,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,885,886,887,888,889,891,893,894,895,896,897,900,901]],["CHUNITHM CRYSTAL PLUS",[333,899,909,910,911,912,913,914,915,916,917,918,921,922,923,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,953,954,955,958,959,960,961,962,966,967,969,970,971,972,973,974,975,976,978,979,980,981,982,983,984,987]],["CHUNITHM PARADISE",[968,988,989,990,991,992,993,994,997,998,999,1002,1004,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1019,1020,1021,1022,1023,1025,1026,1027,1028,1029,1030,1031,1032,1033,1035,1037,1040,1041,1042,1043,1044,1091,1092,1098,1099]],["CHUNITHM PARADISE LOST",[1005,1048,1055,1056,1057,1059,1060,1061,1062,1063,1064,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1096,1100,1101,1102,1103,1104,1105,1106,2001,2002,2048,2070,2071,2072,2073,2074,2077,2079,2080,2081,2082,2083,2084,2085,2086,2087,2089,2101,2102,2103,2106]],["CHUNITHM NEW",[511,1038,1058,1065,1094,2010,2017,2018,2019,2022,2023,2024,2025,2026,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2040,2042,2043,2044,2045,2046,2047,2049,2050,2052,2053,2054,2055,2056,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2090,2091,2092,2093,2094,2096,2097,2098,2099,2105,2108,2109,2110,2111,2114,2115,2116,2117,2118,2119,2120,2121,2122,2124,2125,2126,2127,2134,2135,2137,2138,2140,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2160,2161,2162,2163,2164,2166,2167,2168,2169,2170]],["CHUNITHM NEW PLUS",[1039,1107,2041,2057,2128,2129,2130,2131,2132,2133,2165,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252]],["CHUNITHM SUN",[428,2253,2254,2255,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2302,2303,2304,2305,2306,2307,2308,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2326,2327,2328,2329,2330,2331,2332,2333,2334,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2353,2354,2355,2356,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2381,2382,2383,2384,2385]],["CHUNITHM SUN PLUS",[2297,2298,2299,2300,2301,2309,2352,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2397,2398,2399,2400,2401,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2420,2421,2422,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2463,2464,2465,2466,2467,2468,2469,2475,2476,2477,2478,2479,2480,2481,2482,2483,2485,2486,2487,2488,2489]],["CHUNITHM LUMINOUS",[2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2542,2543,2544,2545,2546,2547,2548,2549,2550,2552,2553,2554,2555,2556,2557,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,2579,2580,2581,2582,2583]],["CHUNITHM LUMINOUS PLUS",[2584,2585,2586,2587,2589,2591,2592,2593,2594,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2610,2611,2612,2613,2614,2615,2616,2618,2619,2620,2621,2622,2623,2624,2625,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,2639,2641,2642,2643,2644,2645,2646,2647,2648,2650,2651,2652,2653,2654,2657,2658,2659,2660,2661,2663,2665,2670,2671,2673,2674,2675,2676,2677,2679,2680,2681]],["CHUNITHM VERSE",[]]]
function reorderPageIntoVersion() {
  const tempKeyedMusicList = {}
  musicOnPage.forEach(i => tempKeyedMusicList[i.box.querySelector('[name=idx]').value]=i)
  const currentBoxes = [...document.querySelectorAll('.box05')]
  if (currentBoxes.length === 0) return
  const container = currentBoxes[0].parentNode
  VERSION_MUSIC_LIST.forEach(([version, list]) => {
    const statisticCount = statisticJudge.reduce((acc, [key]) => { acc[key] = 0; return acc }, {})
    const statisticBox = _('div', {className: 'box01 w420 font_0 text_black', style: {transform:'scale(0.93)',transformOrigin:'left center'}})
    const versionBox = _('div', {className: 'box05 w400 CNDO-version-box'}, [
      _('div', {className: 'genre scroll_point text_white CNDO-version-title', event: {click: e => versionBox.classList.toggle('hide')}}, [_('text', version)]),
      statisticBox,
    ])
    let versionMusicCount = 0
    list.forEach(id => {
      if (!tempKeyedMusicList[id]) return
      versionBox.appendChild(tempKeyedMusicList[id].box.parentNode)
      versionMusicCount++
      statisticJudge.forEach(([key, judge]) => {
        if (judge(tempKeyedMusicList[id])) {
          statisticCount[key]++
        }
      })
    })
    if (versionBox.children.length === 2) return
    const statisticList = statisticJudge.map(([key]) => _('div', { className: 'score_list'}, [
      _('div', {className: 'score_list_top'}, [
        _('img', {src: `${imageBase}/icon_${key}.png`})
      ]),
      _('div', {className: 'score_list_bottom'}, [
        _('div', {className: 'score_num_text'}, [_('text', statisticCount[key])]),
        _('div', {className: 'score_all_text font_small'}, [_('text', `/${versionMusicCount}`)]),
      ]),
    ]))
    statisticList.splice(11, 0, _('br'))
    statisticList.splice(5, 0, _('br'))
    statisticBox.appendChild(_('div', {className: 'score_list_block'}, statisticList))
    container.appendChild(versionBox)
  })
  currentBoxes.forEach(i => i.remove())
  setTimeout(() => applySort.call(sortForm), 50)
}

let totalRating = 0
function addRatingToPage() {
  const musics = [...document.querySelectorAll('.musiclist_box .music_title')].map(addRatingToList)
  if (!musics.length) return

  const boxInfoText = document.querySelector('.box01 .font_x-small')
  if (!boxInfoText) return
	boxInfoText.appendChild(_('br'))
  boxInfoText.appendChild(_('span', {}, [_('text', `${PAGE_TEXT.RATING_AVERAGE[server]}${(totalRating / musics.length).toFixed(3)} (${musics.length}) ${PAGE_TEXT.RATING_TOTAL[server]}${totalRating.toFixed(2)}`)]))
}
function addRatingToList(titleDiv) {
  const dif = getDifFromClass(titleDiv.parentNode)
  if (!dif) return null
  const box = titleDiv.parentNode
  const titleText = titleDiv.lastChild.textContent.trim()
  const level = getLevelByTitleAndDif(titleText, dif) * 1
  const returnData = {
    rating: 0,
    disabled: disabledSongs[server].includes(titleText),
    ratingMax: level + 2.15,
  }
  const scoreBox = box.querySelector('.play_musicdata_highscore .text_b')
  if (!scoreBox) return returnData
  const scoreMax = scoreBox.textContent.replace(/,/g, '')*1

  returnData.rating = getRatingFromConstantAndScore(level, scoreMax)
  addRatingAfterScore(scoreBox, returnData)
	totalRating += Math.floor(returnData.rating *100) /100
  return returnData
}
function addRatingAfterScore(scoreBox, returnData) {
  scoreBox.parentNode.appendChild(_('span', {style: {marginRight: '.5em', fontFamily: 'Arial', float: 'right'}}, [
    _('text', (returnData.rating === returnData.ratingMax ? returnData.rating.toFixed(2) : returnData.rating.toFixed(3)) + ' / ' + returnData.ratingMax.toFixed(2)),
  ]))
}

loadLocalInfo()
if (location.href.indexOf('home/playerData/rating') !== -1) {
  addRatingToPage()
} else {
  initPageOverPower()
  if (document.querySelector('.btn_version') === null && document.querySelector('select[name=genre] *[value="99"][selected]') !== null) {
    reorderPageIntoVersion()
  }
}

})()