Search code examples
javascripttampermonkey

How to implement google's birthday balloon using js?


I really like Google's floating birthday balloons on my avatar, so is there any way to keep the balloons floating on my avatar? Is it possible to write a Tampermonkey script to accomplish this requirement?

    let divNav = document.querySelector('div[role="navigation"]')
    let btnAccount = undefined, btnArr = divNav.getElementsByTagName("a")
    for (let objA of btnArr) {
        if (objA.getAttribute("aria-label").includes("account")) {btnAccount = objA; break;}
    }
    if (btnAccount != undefined) {
        let imgEle = document.createElement("img")
        imgEle.className = "gb_d"
        imgEle.src = "https://ssl.gstatic.com/gb/images/birthday/apd_desktop_dark_2x.gif"
        imgEle.style.zIndex = 991
        imgEle.style.position = "absolute"
        imgEle.style.top = "-4px"
        imgEle.style.bottom = "-4px"
        imgEle.style.left = "-4px"
        imgEle.style.right = "-4px"
        btnAccount.parentNode.insertBefore(imgEle, btnAccount);
    }

Solution

  • if (objA.getAttribute("aria-label").includes("account"))

    includes() is case sensitive, I think you meant to type Account instead of account.

    There is no need to loop over all the <a> tags, directly select the element you need using attribute selectors.

    Here is a revised version that should work on all google sites (and iframes) including Youtube:

    function main(){
        const images = document.querySelectorAll('a[aria-label^="Google Account:"] > img, img[alt="Profile image"], img[alt="Avatar image"]');
        if (!images.length) return;
    
        const imgEle = document.createElement("img");
        imgEle.className = "balloons"; // changed classname to avoid inherited styles
        imgEle.src = 'https://ssl.gstatic.com/gb/images/birthday/apd_desktop_dark_2x.gif';
        //imgEle.style.zIndex = 991  // causes weird behavior sometimes (used img.after instead)
        imgEle.style.position = 'absolute';
        imgEle.style.height = '100%';
        imgEle.style.width = '100%';
        imgEle.style.top = '0px';
        imgEle.style.left = '0px';
        imgEle.style.transform = 'scale(1.1)'; // not needed but looks better with
    
        images.forEach(img => {
            img.parentElement.style.position ='relative'; // fixes issue on youtube
            img.after(imgEle.cloneNode(true)); // used after instead of before (takes care of z-index)
        });
    }
    
    window.addEventListener('load', () => setTimeout(main, 1000)); // sometimes elements take some time to load (especially iframes)
    

    to match google and youtube:

    // @match        https://*.google.com/*
    // @match        https://www.youtube.com/*