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.

  1. // ==UserScript==
  2. // @name Audio Tab Title
  3. // @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.
  4. // @version 0.6.5
  5. // @namespace itsafeature.org
  6. // @author Geoffrey De Belie (Smile4ever)
  7. // @license Unlicense
  8. // @match https://www.youtube.com/watch?v=*
  9. // @match https://music.youtube.com/*
  10. // @match https://open.spotify.com/*
  11. // @match https://soundcloud.com/*
  12. // @match https://music.amazon.com/*
  13. // @grant none
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // Format GrupoBryndisOficial to Grupo Bryndis
  20. function formatChannelName(name) {
  21. if (!name.includes(" ")) {
  22. name = name.replace(/([a-z])([A-Z])/g, '$1 $2'); // Add spaces if none exist
  23. }
  24. return name.replace("Oficial", "").trim(); // Remove "Oficial" and trim spaces
  25. }
  26.  
  27. // Function to update the title on YouTube
  28. function updateYouTubeTitle() {
  29. const metadataElementArtist = document.querySelector(".yt-video-attribute-view-model__metadata h4"); // Artist
  30. const metadataElementArtistText = metadataElementArtist?.innerText ?? "";
  31. const metadataElementTitle = document.querySelector(".yt-video-attribute-view-model__metadata h1"); // Title
  32. const metadataElementTitleText = metadataElementTitle?.innerText ?? "";
  33.  
  34. const channelElement = document.querySelector('a.yt-simple-endpoint.style-scope.yt-formatted-string');
  35. const channelName = channelElement?.innerText ?? "";
  36. const channelNameClean = formatChannelName(channelName.split(' - ')[0].split('|')[0]);
  37.  
  38. const videoTitleElement = document.querySelector('#above-the-fold #title');
  39. let videoTitle = videoTitleElement?.innerText ?? "";
  40. const spaceIndex = videoTitle.indexOf(' ');
  41. const dashIndex = videoTitle.indexOf('-');
  42. const spaceDashIndex = videoTitle.indexOf(' - ');
  43. const lastDashIndex = videoTitle.lastIndexOf('-');
  44.  
  45. // Cleanup videoTitle
  46. videoTitle = videoTitle.replace(" - Video Oficial", "");
  47. videoTitle = videoTitle.replace(" - Video", "");
  48.  
  49. // We need the video title element, if it's not found the page structure must have changed
  50. if(videoTitleElement == null) return;
  51.  
  52. if (metadataElementArtist && metadataElementTitle && lastDashIndex != -1){
  53. const contentAfterDash = videoTitle.substring(lastDashIndex + 1).trim();
  54.  
  55. if (contentAfterDash.toLowerCase().includes(metadataElementArtistText.toLowerCase())) {
  56. // If metadata artist appears after the dash in video title, fix the tab title
  57. document.title = `${metadataElementArtistText} - ${metadataElementTitleText} - YouTube`;
  58. return;
  59. }
  60. }
  61.  
  62. // Fix dash, for example Marco Antonio Solís — Eran Mentiras
  63. if(dashIndex == -1 && videoTitle.indexOf("—") != -1){
  64. document.title = `${videoTitle.replace("—", "-")} - YouTube`;
  65. return;
  66. }
  67.  
  68. // Fix comma's, for example Marco Antonio Solís, Los Bukis - Será Mejor Que Te Vayas
  69. // But don't break Olvídala, Binomio De Oro De América - Video Oficial
  70. if(spaceDashIndex != -1 && videoTitle.indexOf(", ") != -1 && metadataElementArtistText.indexOf(", ") != -1){
  71. document.title = `${videoTitle.split(", ")[0]} - ${videoTitle.split(" - ")[1]} - YouTube`;
  72. return;
  73. }
  74.  
  75. // Sombras, Los Betas - Video
  76. if(videoTitle.indexOf("-") == -1 && videoTitle.indexOf(", ") != -1){
  77. document.title = videoTitle.replace(", ", " - ") + " - YouTube";
  78. return;
  79. }
  80.  
  81. // Use metadata if available, but not if the artist and title are the same
  82. if (metadataElementArtist && metadataElementTitle && metadataElementArtistText != metadataElementTitleText && metadataElementArtistText.includes("|") == false) {
  83. // Set the window title for YouTube if needed
  84. document.title = `${metadataElementArtistText} - ${metadataElementTitleText} - YouTube`;
  85. return;
  86. }
  87.  
  88. // Fall back to channel + video title approach
  89. if (channelElement && videoTitle.includes('-') == false) {
  90. // If there's no space, continue. If the first dash appears before the first space, get out (case A-ha)
  91. if (spaceIndex != -1 && dashIndex < spaceIndex) return;
  92.  
  93. // Set the window title for YouTube if needed
  94. if(videoTitle.includes(channelNameClean) == false){
  95. document.title = `${channelNameClean} - ${videoTitle} - YouTube`;
  96. return;
  97. }
  98. }
  99. }
  100.  
  101. // Function to update the title on YouTube Music
  102. function updateYouTubeMusicTitle() {
  103. const elements = document.querySelectorAll('.ytmusic-player-bar yt-formatted-string');
  104. if (elements.length < 2) return;
  105.  
  106. const artistElement = elements[1];
  107. const audioTitleElement = elements[0];
  108.  
  109. if (artistElement && audioTitleElement) {
  110. const artistName = artistElement.childNodes[0].innerText;
  111. const audioTitle = audioTitleElement.innerText;
  112.  
  113. // Set the window title for YouTube Music
  114. document.title = `${artistName} - ${audioTitle} - YouTube Music`;
  115. }
  116. }
  117.  
  118. // Function to update the title on Spotify
  119. function updateSpotifyTitle() {
  120. const titleElement = document.querySelector('title'); // Get the <title> element
  121. if (titleElement.innerText.includes(" - Spotify") == false) {
  122. titleElement.innerText = `${titleElement.innerText} - Spotify`; // Set the title's innerText for Spotify
  123. }
  124. }
  125.  
  126. function updateSoundCloudTitle() {
  127. const titleElement = document.querySelector('title'); // Get the <title> element
  128. if (titleElement.innerText.includes(" - SoundCloud") == false) {
  129. titleElement.innerText = `${titleElement.innerText} - SoundCloud`; // Set the title's innerText for Spotify
  130. }
  131. }
  132.  
  133. function updateAmazonMusicTitle(){
  134. const shadowHost = document.querySelector('music-horizontal-item');
  135. const shadowRoot = shadowHost.shadowRoot;
  136. const musicLinks = shadowRoot.querySelectorAll('music-link');
  137.  
  138. if (musicLinks.length >= 2) {
  139. const songTitle = musicLinks[0].getAttribute('title');
  140. const artistTitle = musicLinks[1].getAttribute('title');
  141.  
  142. document.title = `${artistTitle} - ${songTitle} - Amazon Music`;
  143. }
  144. }
  145.  
  146. // Function to check for the current platform
  147. function updateTitle() {
  148. if (window.location.hostname == 'music.youtube.com'){
  149. updateYouTubeMusicTitle();
  150. } else if (window.location.hostname.includes('youtube.com')) {
  151. updateYouTubeTitle();
  152. } else if (window.location.hostname.includes('spotify.com')) {
  153. updateSpotifyTitle();
  154. } else if (window.location.hostname.includes('soundcloud.com')) {
  155. updateSoundCloudTitle();
  156. } else if (window.location.hostname.includes('music.amazon.com')) {
  157. updateAmazonMusicTitle();
  158. }
  159. }
  160.  
  161. // Optionally, observe changes in the page if the title might update after load
  162. const observer = new MutationObserver(updateTitle);
  163. observer.observe(document.body, { childList: true, subtree: true });
  164.  
  165. // Wait for the page content to load before running the updateTitle function
  166. window.addEventListener('load', updateTitle);
  167.  
  168. // Set an interval to check the title every second on Spotify pages only
  169. setInterval(() => {
  170. updateTitle(); // Update the title every X seconds (if needed)
  171. }, 2000);
  172. })();