// ==UserScript==
// @name Ratings on Trakt
// @name:de Bewertungen auf Trakt
// @name:es Calificaciones en Trakt
// @name:fr Évaluations sur Trakt
// @name:it Valutazioni su Trakt
// @name:ru Рейтинги на Trakt
// @name:zh-CN Trakt上的评分
// @author Davide <iFelix18@protonmail.com>
// @namespace https://github.com/iFelix18
// @icon https://www.google.com/s2/favicons?sz=64&domain=https://trakt.tv
// @description Adds ratings from IMDb, Rotten Tomatoes, Metacritic and MyAnimeList to Trakt
// @description:de Fügt Bewertungen von IMDb, Rotten Tomatoes, Metacritic und MyAnimeList zu Trakt hinzu
// @description:es Agrega las calificaciones de IMDb, Rotten Tomatoes, Metacritic y MyAnimeList a Trakt
// @description:fr Ajoute des évaluations d'IMDb, Rotten Tomatoes, Metacritic et MyAnimeList à Trakt
// @description:it Aggiunge valutazioni da IMDb, Rotten Tomatoes, Metacritic e MyAnimeList a Trakt
// @description:ru Добавляет рейтинги IMDb, Rotten Tomatoes, Metacritic и MyAnimeList в Trakt
// @description:zh-CN 在Trakt中添加来自IMDb、烂番茄、Metacritic和MyAnimeList的评分。
// @copyright 2019, Davide (https://github.com/iFelix18)
// @license MIT
// @version 4.7.3
// @homepage https://github.com/iFelix18/Trakt-Userscripts#readme
// @homepageURL https://github.com/iFelix18/Trakt-Userscripts#readme
// @supportURL https://github.com/iFelix18/Trakt-Userscripts/issues
// @updateURL https://raw.githubusercontent.com/iFelix18/Trakt-Userscripts/master/userscripts/meta/ratings-on-trakt.meta.js
// @downloadURL https://raw.githubusercontent.com/iFelix18/Trakt-Userscripts/master/userscripts/ratings-on-trakt.user.js
// @require https://cdn.jsdelivr.net/gh/sizzlemctwizzle/GM_config@43fd0fe4de1166f343883511e53546e87840aeaf/gm_config.min.js
// @require https://cdn.jsdelivr.net/npm/@ifelix18/utils@5.1.1/lib/index.min.js
// @require https://cdn.jsdelivr.net/npm/@ifelix18/omdb@2.0.0/lib/index.min.js
// @require https://cdn.jsdelivr.net/npm/@ifelix18/rottentomatoes@2.0.0/lib/index.min.js
// @require https://cdn.jsdelivr.net/npm/@ifelix18/jikan@2.0.0/lib/index.min.js
// @require https://cdn.jsdelivr.net/npm/@ifelix18/ratings@4.0.0/lib/index.min.js
// @require https://cdn.jsdelivr.net/npm/node-creation-observer@1.2.0/release/node-creation-observer-latest.min.js
// @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
// @require https://cdn.jsdelivr.net/npm/handlebars@4.7.7/dist/handlebars.min.js
// @match *://trakt.tv/*
// @connect api.jikan.moe
// @connect omdbapi.com
// @connect rottentomatoes.com
// @compatible chrome
// @compatible edge
// @compatible firefox
// @compatible safari
// @grant GM_getValue
// @grant GM_setValue
// @grant GM.deleteValue
// @grant GM.getValue
// @grant GM.listValues
// @grant GM.registerMenuCommand
// @grant GM.setValue
// @grant GM.xmlHttpRequest
// @run-at document-start
// @inject-into content
// ==/UserScript==
/* global $, GM_config, Handlebars, NodeCreationObserver, Ratings, UserscriptUtils */
(() => {
//* Constants
const cachePeriod = 3_600_000
const id = GM.info.script.name.toLowerCase().replace(/\s/g, '-')
const title = `${GM.info.script.name} v${GM.info.script.version} Settings`
const fields = {
OMDbApiKey: {
label: 'API Key:',
section: ['OMDb', 'You can request a free OMDb API Key at: https://www.omdbapi.com/apikey.aspx'],
labelPos: 'left',
type: 'text',
title: 'Your OMDb API Key',
size: 70,
default: ''
},
hideDefaultRatings: {
label: 'Prefer the ratings offered by this script to those offered by Trakt:',
section: ['Features'],
labelPos: 'left',
type: 'checkbox',
default: true
},
logging: {
label: 'Logging:',
section: ['Develop'],
labelPos: 'left',
type: 'checkbox',
default: false
},
debugging: {
label: 'Debugging:',
labelPos: 'left',
type: 'checkbox',
default: false
},
clearCache: {
label: 'Clear the cache',
type: 'button',
click: async () => {
const values = await GM.listValues()
for (const value of values) {
const cache = await GM.getValue(value) // get cache
if (cache.time) { GM.deleteValue(value) } // delete cache
}
UU.log('cache cleared')
GM_config.close()
}
}
}
//* NodeCreationObserver
NodeCreationObserver.init(id)
//* GM_config
UserscriptUtils.migrateConfig('trakt-config', id) // migrate to the new GM_config ID
GM_config.init({
id,
title,
fields,
css: ':root{--font:"Montserrat",sans-serif;--background-grey:rgb(29, 29, 29);--black:rgb(0, 0, 0);--dark-grey:rgb(22, 22, 22);--grey:rgb(51, 51, 51);--light-grey:rgb(102, 102, 102);--red:rgb(237, 34, 36);--white:rgb(255, 255, 255)}#ratings-on-trakt *{color:var(--white)!important;font-family:var(--font)!important;font-size:14px!important;font-weight:400!important}#ratings-on-trakt{background:var(--background-grey)!important}#ratings-on-trakt .config_header{font-size:34px!important;line-height:1.1!important;text-shadow:0 0 20px var(--black)!important}#ratings-on-trakt .section_header_holder{background:var(--dark-grey)!important;border:1px solid var(--grey)!important;margin-bottom:1em!important}#ratings-on-trakt .section_header{background:var(--grey)!important;border:1px solid var(--grey)!important;padding:8px!important;text-align:left!important;text-transform:uppercase!important}#ratings-on-trakt .section_desc{background:var(--black)!important;border:1px solid var(--grey)!important;border-left:0!important;border-right:0!important;font-size:13px!important;margin:0!important;padding:10px 8px!important;text-align:left!important}#ratings-on-trakt .config_var{align-items:center!important;display:flex!important;margin:0!important;padding:15px!important}#ratings-on-trakt .field_label{margin-left:6px!important}#ratings-on-trakt_field_OMDbApiKey{background-color:var(--grey)!important;border:1px solid var(--light-grey)!important;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)!important;flex:1!important;padding:6px 12px!important}#ratings-on-trakt_field_OMDbApiKey:focus{box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)!important;outline:0!important}#ratings-on-trakt button,#ratings-on-trakt input[type=button]{background:var(--grey)!important;border:1px solid transparent!important;padding:10px 16px!important}#ratings-on-trakt button:hover,#ratings-on-trakt input[type=button]:hover{filter:brightness(85%)!important}#ratings-on-trakt_buttons_holder button{background-color:var(--red)!important}#ratings-on-trakt .reset{margin-right:10px!important}',
events: {
init: () => {
window.addEventListener('load', () => { // add style
$('head').append('<style>@import url(https://fonts.googleapis.com/css2?family=Montserrat&display=swap);header#top-nav .navbar-nav.navbar-user:hover #user-menu{max-height:max-content}</style>')
})
if (!GM_config.isOpen && GM_config.get('OMDbApiKey') === '') { // first configuration
window.addEventListener('load', () => GM_config.open())
}
if (GM.info.scriptHandler !== 'Userscripts') { //! Userscripts Safari: GM.registerMenuCommand is missing
GM.registerMenuCommand('Configure', () => GM_config.open())
}
},
save: () => {
if (GM_config.get('OMDbApiKey') === '') {
window.alert(`${GM.info.script.name}: check your settings and save`)
} else {
window.alert(`${GM.info.script.name}: settings saved`)
GM_config.close()
setTimeout(window.location.reload(false), 500)
}
}
}
})
//* Utils
const UU = new UserscriptUtils({
name: GM.info.script.name,
version: GM.info.script.version,
author: GM.info.script.author,
logging: GM_config.get('logging')
})
UU.init(id)
//* Ratings
const rating = new Ratings({
omdb_api_key: GM_config.get('OMDbApiKey'),
cache_period: cachePeriod,
debug: GM_config.get('debugging')
})
//* Handlebars
Handlebars.registerHelper('ifEqual', function (a, b, options) {
if (a === b) return options.fn(this)
return options.inverse(this)
})
//* Functions
/**
* Adds a link to the menu to access the script configuration
*/
const addSettingsToMenu = () => {
const menu = `<li class=${id}><a href=""onclick=return!1>${GM.info.script.name}</a>`
$('#user-menu ul li.separator').last().after(menu)
$(`.${id}`).click(() => GM_config.open())
}
/**
* Clear old data from the cache
*/
const clearOldCache = async () => {
const values = await GM.listValues()
for (const value of values) {
const cache = await GM.getValue(value) // get cache
if ((Date.now() - cache.time) > 3_600_000) { GM.deleteValue(value) } // delete old cache
}
}
/**
* Hide default ratings offered by Trakt
*/
const hideDefaultRatings = () => {
$('#summary-ratings-wrapper ul li.imdb, #summary-ratings-wrapper ul li.rt, #summary-ratings-wrapper ul li.metacritic').hide()
}
/**
* Returns IMDb ID
*
* @returns {string} IMDb ID
*/
const getID = () => {
return $('#info-wrapper .sidebar .external li a#external-link-imdb').attr('href').match(/tt\d+/)[0]
}
/**
* Add template
*
* @param {object} target Target
*/
const addTemplate = (target) => {
const template = '<ul class=external-ratings style=margin-left:30px></ul><script id=external-ratings-template type=text/x-handlebars-template>{{#each ratings}} {{#ifEqual this.rating "N/A"}} {{else}}<li class={{this.source}}-rating><a href={{this.url}} target=_blank><img alt="{{this.source}} logo" class=logo src={{this.logo}}><div class=number><div class=rating style=display:flex;align-items:center;align-content:center;justify-content:center>{{this.rating}} {{#ifEqual this.rating "N/A"}} {{else}} <span style=font-weight:400;font-size:80%;opacity:.8>{{this.symbol}} </span>{{/ifEqual}}</div>{{#ifEqual this.source "metascore"}}<div class=votes style="width:100%;color:transparent;background:linear-gradient(to top,transparent 0,transparent 25%,{{this.votes}} 25%,{{this.votes}} 75%,transparent 75%,transparent 100%)">{{this.rating}}</div>{{else}}<div class=votes><span>{{this.votes}}</span></div>{{/ifEqual}}</div></a></li>{{/ifEqual}} {{/each}}</script>'
$(template).insertAfter(target)
}
/**
* Add ratings
*/
const addRatings = async () => {
clearOldCache() // clear old cache
const target = $('#summary-ratings-wrapper .ratings') // target
if (target.length === 0) return // check if it is on the main page
const id = getID() // IMDb ID
if (!id) return // check if the ID exists
UU.log(`ID is '${id}'`)
addTemplate(target) // add template
// get ratings
const ratings = await rating.get({ id }).then().catch(error => console.error(error))
const elaboratedRatings = await rating.elaborate(ratings).then().catch(error => console.error(error))
// compile template
const template = Handlebars.compile($('#external-ratings-template').html())
const context = { ratings: elaboratedRatings }
const compile = template(context)
$('.external-ratings').html(compile)
if (GM_config.get('hideDefaultRatings')) hideDefaultRatings() // hide default ratings by Trakt
}
//* Script
$(document).ready(() => {
NodeCreationObserver.onCreation('body', () => {
addSettingsToMenu() // link settings to trakt menu
})
NodeCreationObserver.onCreation('.movies.show #summary-ratings-wrapper, .shows.show #summary-ratings-wrapper, .shows.episode #summary-ratings-wrapper', () => {
addRatings() // add ratings
})
})
})()
Donate for the site OpenUserJS
Are you sure you want to go to an external site to donate a monetary value?
WARNING: Some countries laws may supersede the payment processors policy such as the GDPR and PayPal. While it is highly appreciated to donate, please check with your countries privacy and identity laws regarding privacy of information first. Use at your utmost discretion.