// ==UserScript== // @name Trakt.tv | Custom Profile Image // @description A custom profile image for free users. Like the vip feature, except this one only works locally. Uses the native set/reset buttons and changes the dashboard + settings background as well. // @version 1.1.0 // @namespace https://github.com/Fenn3c401 // @author Fenn3c401 // @license GPL-3.0-or-later // @homepageURL https://github.com/Fenn3c401/Trakt.tv-Userscript-Collection#readme // @supportURL https://github.com/Fenn3c401/Trakt.tv-Userscript-Collection/issues // @updateURL https://raw.githubusercontent.com/Fenn3c401/Trakt.tv-Userscript-Collection/main/userscripts/meta/2dz6ub1t.meta.js // @downloadURL https://raw.githubusercontent.com/Fenn3c401/Trakt.tv-Userscript-Collection/main/userscripts/dist/2dz6ub1t.user.js // @icon https://trakt.tv/assets/logos/logomark.square.gradient-b644b16c38ff775861b4b1f58c1230f6a097a2466ab33ae00445a505c33fcb91.svg // @match https://trakt.tv/* // @match https://classic.trakt.tv/* // @run-at document-start // @grant unsafeWindow // @grant GM_info // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // ==/UserScript== 'use strict'; let $, toastr; const Logger = Object.freeze({ _DEFAULT_PREFIX: GM_info.script.name.replace('Trakt.tv', 'Userscript') + ': ', _DEFAULT_TOAST: true, _printMsg(fnConsole, fnToastr, msg, { data, prefix = Logger._DEFAULT_PREFIX, toast = Logger._DEFAULT_TOAST } = {}) { msg = prefix + msg; console[fnConsole](msg, (data ? data : '')); if (toast) toastr[fnToastr](msg + (data ? ' See console for details.' : '')); }, info: (msg, opt) => Logger._printMsg('info', 'info', msg, opt), success: (msg, opt) => Logger._printMsg('info', 'success', msg, opt), warning: (msg, opt) => Logger._printMsg('warn', 'warning', msg, opt), error: (msg, opt) => Logger._printMsg('error', 'error', msg, opt), }); const gmStorage = { ...(GM_getValue('customProfileImage')) }; GM_setValue('customProfileImage', gmStorage); let styles = addStyles(); window.addEventListener('turbo:load', () => { if (!/^\/(shows|movies|users|dashboard|settings|oauth\/(authorized_)?applications)/.test(location.pathname)) return; $ ??= unsafeWindow.jQuery; toastr ??= unsafeWindow.toastr; if (!$ || !toastr) return; const $coverWrapper = $('body.is-self #cover-wrapper'), $btnSetProfileImage = $('body.is-self #btn-set-profile-image'), $fullScreenshot = $('body:is(.shows, .movies) #summary-wrapper > .full-screenshot'); if (gmStorage.imgUrl && $coverWrapper.length && $btnSetProfileImage.length) addUserPageElems($coverWrapper, $btnSetProfileImage); if ($fullScreenshot.length) { if ($fullScreenshot.attr('style')) addTitlePageElems($fullScreenshot); else { new MutationObserver((_muts, mutObs) => { mutObs.disconnect(); addTitlePageElems($fullScreenshot); }).observe($fullScreenshot[0], { attributeFilter: ['style'] }); // native logic for selection of bg img (fanart vs screenshot) is quite complex } } }); function addUserPageElems($coverWrapper, $btnSetProfileImage) { if ($coverWrapper.has('a.selected:contains("Profile")').length) { $coverWrapper.removeClass('slim') .find('> .poster-bg-wrapper').removeClass('poster-bg-wrapper').addClass('shade'); if (!$coverWrapper.find('> #watching-now-wrapper').length) { $coverWrapper.find('> .container').before( `
` ); } } else { $coverWrapper.find('> .poster-bg-wrapper').removeClass('poster-bg-wrapper').addClass('shadow-full-width'); } $btnSetProfileImage.popover('destroy').popover({ trigger: 'manual', container: 'body', placement: 'bottom', html: true, template: `