Greasy Fork

Greasy Fork is available in English.

Audio Tab Title

Change the window title on YouTube based on the channel name and video title, and append the website name on Spotify and SoundCloud pages.

// ==UserScript==
// @name         Audio Tab Title
// @description  Change the window title on YouTube based on the channel name and video title, and append the website name on Spotify and SoundCloud pages.
// @version      0.6.5
// @namespace    itsafeature.org
// @author       Geoffrey De Belie (Smile4ever)
// @license      Unlicense
// @match        https://www.youtube.com/watch?v=*
// @match        https://music.youtube.com/*
// @match        https://open.spotify.com/*
// @match        https://soundcloud.com/*
// @match        https://music.amazon.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Format GrupoBryndisOficial to Grupo Bryndis
    function formatChannelName(name) {
        if (!name.includes(" ")) {
            name = name.replace(/([a-z])([A-Z])/g, '$1 $2'); // Add spaces if none exist
        }
        return name.replace("Oficial", "").trim(); // Remove "Oficial" and trim spaces
    }

    // Function to update the title on YouTube
    function updateYouTubeTitle() {
        const metadataElementArtist = document.querySelector(".yt-video-attribute-view-model__metadata h4"); // Artist
        const metadataElementArtistText = metadataElementArtist?.innerText ?? "";
        const metadataElementTitle = document.querySelector(".yt-video-attribute-view-model__metadata h1"); // Title
        const metadataElementTitleText = metadataElementTitle?.innerText ?? "";

        const channelElement = document.querySelector('a.yt-simple-endpoint.style-scope.yt-formatted-string');
        const channelName = channelElement?.innerText ?? "";
        const channelNameClean = formatChannelName(channelName.split(' - ')[0].split('|')[0]);

        const videoTitleElement = document.querySelector('#above-the-fold #title');
        let videoTitle = videoTitleElement?.innerText ?? "";
        const spaceIndex = videoTitle.indexOf(' ');
        const dashIndex = videoTitle.indexOf('-');
        const spaceDashIndex = videoTitle.indexOf(' - ');
        const lastDashIndex = videoTitle.lastIndexOf('-');

        // Cleanup videoTitle
        videoTitle = videoTitle.replace(" - Video Oficial", "");
        videoTitle = videoTitle.replace(" - Video", "");

        // We need the video title element, if it's not found the page structure must have changed
        if(videoTitleElement == null) return;

        if (metadataElementArtist && metadataElementTitle && lastDashIndex != -1){
            const contentAfterDash = videoTitle.substring(lastDashIndex + 1).trim();

            if (contentAfterDash.toLowerCase().includes(metadataElementArtistText.toLowerCase())) {
                // If metadata artist appears after the dash in video title, fix the tab title
                document.title = `${metadataElementArtistText} - ${metadataElementTitleText} - YouTube`;
                return;
            }
        }

        // Fix dash, for example Marco Antonio Solís — Eran Mentiras
        if(dashIndex == -1 && videoTitle.indexOf("—") != -1){
            document.title = `${videoTitle.replace("—", "-")} - YouTube`;
            return;
        }

        // Fix comma's, for example Marco Antonio Solís, Los Bukis - Será Mejor Que Te Vayas
        // But don't break Olvídala, Binomio De Oro De América - Video Oficial
        if(spaceDashIndex != -1 && videoTitle.indexOf(", ") != -1 && metadataElementArtistText.indexOf(", ") != -1){
            document.title = `${videoTitle.split(", ")[0]} - ${videoTitle.split(" - ")[1]} - YouTube`;
            return;
        }

        // Sombras, Los Betas - Video
        if(videoTitle.indexOf("-") == -1 && videoTitle.indexOf(", ") != -1){
            document.title = videoTitle.replace(", ", " - ") + " - YouTube";
            return;
        }

        // Use metadata if available, but not if the artist and title are the same
        if (metadataElementArtist && metadataElementTitle && metadataElementArtistText != metadataElementTitleText && metadataElementArtistText.includes("|") == false) {
            // Set the window title for YouTube if needed
            document.title = `${metadataElementArtistText} - ${metadataElementTitleText} - YouTube`;
            return;
        }

        // Fall back to channel + video title approach
        if (channelElement && videoTitle.includes('-') == false) {
            // If there's no space, continue. If the first dash appears before the first space, get out (case A-ha)
            if (spaceIndex != -1 && dashIndex < spaceIndex) return;

            // Set the window title for YouTube if needed
            if(videoTitle.includes(channelNameClean) == false){
                document.title = `${channelNameClean} - ${videoTitle} - YouTube`;
                return;
            }
        }
    }

    // Function to update the title on YouTube Music
    function updateYouTubeMusicTitle() {
        const elements = document.querySelectorAll('.ytmusic-player-bar yt-formatted-string');
        if (elements.length < 2) return;

        const artistElement = elements[1];
        const audioTitleElement = elements[0];

        if (artistElement && audioTitleElement) {
            const artistName = artistElement.childNodes[0].innerText;
            const audioTitle = audioTitleElement.innerText;

            // Set the window title for YouTube Music
            document.title = `${artistName} - ${audioTitle} - YouTube Music`;
        }
    }

    // Function to update the title on Spotify
    function updateSpotifyTitle() {
        const titleElement = document.querySelector('title'); // Get the <title> element
        if (titleElement.innerText.includes(" - Spotify") == false) {
            titleElement.innerText = `${titleElement.innerText} - Spotify`; // Set the title's innerText for Spotify
        }
    }

     function updateSoundCloudTitle() {
        const titleElement = document.querySelector('title'); // Get the <title> element
        if (titleElement.innerText.includes(" - SoundCloud") == false) {
            titleElement.innerText = `${titleElement.innerText} - SoundCloud`; // Set the title's innerText for Spotify
        }
    }

    function updateAmazonMusicTitle(){
        const shadowHost = document.querySelector('music-horizontal-item');
        const shadowRoot = shadowHost.shadowRoot;
        const musicLinks = shadowRoot.querySelectorAll('music-link');

        if (musicLinks.length >= 2) {
            const songTitle = musicLinks[0].getAttribute('title');
            const artistTitle = musicLinks[1].getAttribute('title');

            document.title = `${artistTitle} - ${songTitle} - Amazon Music`;
        }
    }

    // Function to check for the current platform
    function updateTitle() {
        if (window.location.hostname == 'music.youtube.com'){
            updateYouTubeMusicTitle();
        } else if (window.location.hostname.includes('youtube.com')) {
            updateYouTubeTitle();
        } else if (window.location.hostname.includes('spotify.com')) {
            updateSpotifyTitle();
        } else if (window.location.hostname.includes('soundcloud.com')) {
            updateSoundCloudTitle();
        } else if (window.location.hostname.includes('music.amazon.com')) {
            updateAmazonMusicTitle();
        }
    }

    // Optionally, observe changes in the page if the title might update after load
    const observer = new MutationObserver(updateTitle);
    observer.observe(document.body, { childList: true, subtree: true });

    // Wait for the page content to load before running the updateTitle function
    window.addEventListener('load', updateTitle);

    // Set an interval to check the title every second on Spotify pages only
    setInterval(() => {
        updateTitle(); // Update the title every X seconds (if needed)
    }, 2000);
})();