calculate weighted average track rating based on track lengths
目前為
// ==UserScript==
// @name RYM: Weighted average track rating (updated)
// @version 2.3
// @description calculate weighted average track rating based on track lengths
// @match https://rateyourmusic.com/release/*
// @match http://rateyourmusic.com/release/*
// @copyright 2021, w_biggs (originally by thought_house)
// @namespace https://greasyfork.org/users/170755
// ==/UserScript==
window.addEventListener('load', function() {
const tracklistTracks = document.querySelectorAll('#tracks li.track');
const trackLengths = {};
let prevNum = 0;
tracklistTracks.forEach((track) => {
const numEl = track.querySelector('.tracklist_num');
// skip non track rows
if (numEl) {
const num = numEl.textContent.trim();
const nameEl = track.querySelector('.tracklist_title .rendered_text');
const name = nameEl.textContent.trim();
const durationEl = track.querySelector('span.tracklist_duration');
let duration = 0;
if (durationEl) {
duration = parseInt(durationEl.dataset.inseconds, 10);
}
// if track number is blank, add duration to last song with a track number
if (num === '') {
// exclude silence tracks
if (!(name.includes('[silence]'))) {
trackLengths[prevNum].duration += duration;
}
} else {
trackLengths[num] = {
name,
duration,
};
prevNum = num;
}
}
});
//console.log(trackLengths);
addWeightedAvg('#track_ratings', trackLengths);
addWeightedAvg('.track_rating_hide ul', trackLengths);
const catalogList = document.getElementById('catalog_list');
const catalogObserver = new MutationObserver(function(records, observer) {
records.forEach((mutation) => {
if (mutation.type === 'childList') {
addWeightedAvg('.track_rating_hide ul', trackLengths);
}
});
});
catalogObserver.observe(catalogList, {
childList: true,
attributes: false,
subtree: false
});
const ratingStarButton = document.getElementById('track_ratings_save_btn');
ratingStarButton.addEventListener('click', function() {
addWeightedAvg('#track_ratings', trackLengths);
});
});
const addWeightedAvg = function addWeightedAvg(selector, trackLengths) {
const areas = document.querySelectorAll(selector);
areas.forEach((area) => {
const weightedRow = area.querySelector('.avg-rating');
if (weightedRow) {
weightedRow.remove();
}
let rating = 0;
let rawRating = 0;
let trackCount = 0;
let rated = 0;
let allFound = true;
const tracks = area.querySelectorAll('.tracklist_line');
tracks.forEach((track) => {
const n = parseInt(track.querySelector('.tracklist_num').textContent.trim(), 10);
const name = track.querySelector('.tracklist_title .rendered_text').textContent.trim();
let starsVal = 0;
const ratingNum = track.querySelector('.rating_num');
if (ratingNum) {
starsVal = parseFloat(ratingNum.textContent.trim(), 10);
} else {
const starsImg = track.querySelector('.track_rating_disp img');
if (starsImg) {
starsVal = parseFloat(starsImg.getAttribute('title'), 10);
}
}
if (starsVal > 0) {
if (n in trackLengths && trackLengths[n].name === name) {
rating += trackLengths[n].duration * starsVal;
rated += trackLengths[n].duration * 1;
} else {
allFound = false;
}
rawRating += starsVal;
trackCount += 1;
}
});
let unweightedRating = rawRating / trackCount;
let weightedRating = 0;
if (allFound) {
weightedRating = rating / rated;
}
let avgHTML = '';
if (unweightedRating > 0) {
avgHTML += 'Average: <b>' + unweightedRating.toFixed(2) + '</b>';
}
if (weightedRating > 0) {
avgHTML += ', Weighted: <b>' + weightedRating.toFixed(2) + '</b>';
}
const row = document.createElement('li');
row.classList.add('track');
row.classList.add('avg-rating');
const text = document.createElement('span');
text.style = 'float:right;margin-right:10px;color:var(--mono-2);font-size:1.1em;margin-top:6px;margin-bottom:6px;';
text.innerHTML = avgHTML;
row.appendChild(text);
area.appendChild(row);
});
};