Greasy Fork 还支持 简体中文。

Add Spotify to YouTube

Adds a link to Spotify on music videos on YouTube

目前為 2014-08-29 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Add Spotify to YouTube
  3. // @description Adds a link to Spotify on music videos on YouTube
  4. // @include *://youtube.*/*
  5. // @include *://*.youtube.*/*
  6. // @version 0.0.1.20140829194743
  7. // @namespace https://greasyfork.org/users/3216
  8. // ==/UserScript==
  9.  
  10. var userscript = function()
  11. {
  12.  
  13. // http://stackoverflow.com/questions/2246901/how-can-i-use-jquery-in-greasemonkey-scripts-in-google-chrome
  14. function addJQuery(callback) {
  15. var script = document.createElement("script");
  16. script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js");
  17. script.addEventListener('load', function() {
  18. var script = document.createElement("script");
  19. script.textContent = "window.jQ=jQuery.noConflict(true);(" + callback.toString() + ")();";
  20. document.body.appendChild(script);
  21. }, false);
  22. document.body.appendChild(script);
  23. }
  24.  
  25. function main()
  26. {
  27.  
  28. var videoinfo = {url: top.location.href, complete: 0, text: "", timer: null, running: 0}
  29. var DEBUG = 0;
  30.  
  31. if(DEBUG) var DEBUGLOG = console;
  32. else { var TDEBUGLOG = function() { return {log: function() {}}; }; var DEBUGLOG = TDEBUGLOG(); }
  33.  
  34. function IsMusic()
  35. {
  36. if(jQ('#eow-title #watch-headline-show-title').length != 0) return 1;
  37. if(jQ('#eow-category').text().trim() == "Music") return 1;
  38. var metadata = jQ('.metadata-info-title');
  39. for(var i = 0; i < metadata.length; i++)
  40. {
  41. if(metadata[i].innerText.match(/Buy ".*?" on|Artist/) != null) return 1;
  42. }
  43.  
  44. if(jQ('#eow-title').text().split('-', 2).length == 2) return 1; // Might be dangerous!
  45. return 0;
  46. }
  47.  
  48. function GetVideoTitle()
  49. {
  50. var artistname;
  51. var trackname;
  52. var fullname;
  53. var artist = jQ('#eow-title #watch-headline-show-title');
  54. if(artist.length != 0 && !artistname)
  55. {
  56. artistname = artist.text();
  57. }
  58. var artist = jQ('.metadata-info');
  59. if(artist.length != 0 && !artistname)
  60. {
  61. for(var i = 0; i < artist.length; i++)
  62. {
  63. var tname = artist[i].innerText.match(/(Artist)[ \n\r]*(.*)/);
  64. if(tname)
  65. {
  66. if(tname[2].trim() != "Various Artists")
  67. {
  68. artistname = tname[2];
  69. break;
  70. }
  71. }
  72. }
  73. }
  74. if(!artistname)
  75. {
  76. var tname = jQ('#eow-title').text().split('-', 2);
  77. if(tname.length == 2)
  78. {
  79. artistname = tname[0].trim();
  80. }
  81. }
  82. var track = jQ('.metadata-info-title').text().match(/Buy "(.*?)" on/);
  83. if(track != null && !trackname)
  84. {
  85. trackname = track[1];
  86. }
  87. if(!trackname)
  88. {
  89. //trackname = jQ('#eow-title').text().replace(artistname, "").replace(/-/, '').trim();
  90. var tname = jQ('#eow-title').text().split(/[-]+/, 2);
  91. if(tname.length == 2)
  92. {
  93. trackname = tname[1].trim();
  94. }
  95. else
  96. {
  97. trackname = trackname = jQ('#eow-title').text().replace(/-/, '').trim();
  98. if(artistname) trackname = trackname.replace(artistname, "");
  99. }
  100. }
  101. if(!artistname && trackname)
  102. {
  103. artistname = " ";
  104. }
  105. if(artistname && trackname)
  106. {
  107. trackname = trackname.replace(/\((.*?)\)|\[(.*?)\]| (Re)?mastered| f(ea)?t(uring)?(.)? .*|\"|\'/gi, "").trim();
  108. artistname = artistname.replace(/f(ea)?t(uring)?(.)? .*/gi, "").trim(); // & .*
  109. return {artist: artistname, track: trackname};
  110. }
  111. else
  112. {
  113. if(!artistname) DEBUGLOG.log("failed to get artistname");
  114. if(!trackname) DEBUGLOG.log("failed to get trackname");
  115. }
  116. return 0;
  117. }
  118.  
  119. // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
  120. function escapeRegExp(str) {
  121. return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  122. }
  123.  
  124. // http://stackoverflow.com/a/21081760
  125. function wordInString(s, word){
  126. return new RegExp( '\\b' + word + '\\b', 'i').test(s);
  127. }
  128.  
  129. function FindOriginal(title, data)
  130. {
  131. var scores = []
  132. var highest = 0;
  133. var title_artist = title.artist.replace(/[^a-zA-Z ]/g, "").split(' ').filter(Boolean);
  134. var extra = [];
  135. if(!/remix/i.test(title.track))
  136. {
  137. extra.push("remix");
  138. }
  139.  
  140. for(var i = 0; i < Math.min(data.info.num_results, 10); i++)
  141. {
  142. var points = 0;
  143. var track = data.tracks[i];
  144. if(!new RegExp(escapeRegExp(title.track) + ' .*(radio|clean|live|remaster(ed)?|edit|' + extra.join('|') + ')', 'gi').test(track.name))
  145. {
  146. points += 1;
  147. }
  148. var artists = track.artists;
  149. for(var x = 0; x < artists.length; x++)
  150. {
  151. if(title_artist.some(function(str) { return wordInString(this, str); }, artists[x].name)) points += 1;
  152. }
  153. scores[i] = points;
  154. }
  155. for(var i = 0; i < scores.length; i++) if(scores[i] > scores[highest]) highest = i;
  156. return highest;
  157. }
  158.  
  159. function CheckAddress()
  160. {
  161. if(window.location.href.match(/^(https?\:\/\/(www\.)?youtube.com\/watch)/))
  162. {
  163. return 1;
  164. }
  165. return 0;
  166. }
  167.  
  168. function AddSpotify()
  169. {
  170. if(!CheckAddress()) return 1;
  171.  
  172. videoinfo.complete = 0;
  173. if(IsMusic())
  174. {
  175. var title = GetVideoTitle();
  176. DEBUGLOG.log("title", title);
  177. if(title != 0)
  178. {
  179. jQ.getJSON('//ws.spotify.com/search/1/track.json?q=' + encodeURIComponent(title.artist + " " + title.track), function(data)
  180. {
  181. DEBUGLOG.log("data", data);
  182. DEBUGLOG.log("fullname:", title.artist, title.track);
  183. if(data.info.num_results > 0)
  184. {
  185. var artists = [];
  186. var index = FindOriginal(title, data);
  187. DEBUGLOG.log("Index", index, "selected");
  188. var track = data.tracks[index];
  189. jQ.each(track.artists, function(key, val) { artists.push('<a href="' + val.href + '">' + val.name + '</a>'); });
  190. var artistsname = artists.join(", ");
  191. var trackname = track.name;
  192. var htmloutput = '<div class="youtubespotify" style="font-size: 70%"><a href="' + track.href + '">';
  193. htmloutput += '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAQhSURBVDhPhZVtSJ11GMZ/zznHoz56XHbsbFmtpgj5khuZWCO3hDnG+tLqy+hDRRBsxPoSFX4IIigZsQjWgogFoygI5iAsSpdrMqHhXEKzCUujhWe+TI969OiZL6frfp4jKS12w9/n5fz/131d133fj05GwW1iLn2D38eOE5/tYCZ9lZXVFMGAy6a8SkqL9lIVO0Jh7r3Z3RvjP6BLKwucvlJPfGaASC7khiAnAAEHVrVzeRXSy5C8hcCrebaml5xgfva0HxtAryfO8nV/s9hAfo7Agj5gSNdgFnRJoMsrlhwWBD6zCAe3d7K1eE8WRQSyV/5KdPJFXzPFAswTu5BAbBlwWCuknXYNWxItS5anZ9v/5eVm7/xaeExN8tEul6irQ2KYFxZTk677sMnX4VUxzJh0yV5Mw60sW1t2P5mCN5tSnhUe6KneGqZSA0TvgoICGP0TRq7B9LgAtNmkF0SgZAtsrZCX5ahw8nVOBZ0XqGxIKdndbjUv1F/BSS7GM8fOlXJ/DL7/HNpOZDXcIcoqoek52HNQKvQ8nYAJJXm9KU5w30vhd0aTF4iIyTcfQkLs8mTDw49C7ePwSIPud8ADYle4CeaTYib5iZvwazec/kRqxHbHLv99KBDGOXWxLjM+1+cVJ1KkrEsC2OZLtoIEtRzdo8pbn1gHTAmwux3OnIThAY8477WpDlGI5tfhHPvJ1TYzWC9VyckR6NGBod/k7XV5NiNwFS66GR6Un1WPwZNPw5aH/Nbq74HBfmh8xveYjIvT+iMZrx+1jOnLdX5mC0csTfKyirAgiesjdh+82AIN++TnlGzR7zYYVjTng05XqlKeVFeDMdirKqpotU8okSyxSTL5ASWdHIW+8/DzGbh0zgff3givfQSz0/5gOIjpyZ66zFiyj1wdMv+K7/F9HZb88az8gL1XovIa2FblK5iehI/f0rtaST8gA9V6xnJzkTztGmzJdP/RiivfCtUBX7XChW99Fv8XO/fD828okXw2hgsCtL61Xm2saMGZXYhn3v2ulJJCydUEJSRx4m+oVEGMdUjvzAIbgpFh+OUHaFfVLQ4dVeFkU1rzb6CT8vXt/XF/oj7trmF0dsBrKwO2tarKWhvZMk9tBe13G195365BqdkpdcX+qKZlWUxfrUO7NFEGarPf0uZSrBG1/jRmawXyelRhF8uxFiGBW7NbWxnLaSl5/4A/+7Jc2XVz+KkOJjQta5usPby17tm76tmYpSR1Sezs+abOHd7d4eFYeEy9O8XQxFlOdDUT0RDY18ljqvdrbC1st+eK/li15+Tnq02dlMX+/Z5uALUwKz47X8+1sQEKJNH7QEuPJ187V7SM3bwqXRGr5pXdd/jyr4/k4g0uDh9naLxD8q6SXkmpl11KIpWUx/bSUHZEim73Pwr+AWfotNJ4G681AAAAAElFTkSuQmCC">';
  194. htmloutput += ' ' + trackname + '</a> - ' + artistsname + '</div>';
  195. jQ('.youtubespotify').remove();
  196. jQ('#watch-headline-title').append(htmloutput);
  197. }
  198. else
  199. {
  200. jQ('.youtubespotify').remove();
  201. DEBUGLOG.log("No song found");
  202. }
  203. });
  204. } else
  205. {
  206. jQ('.youtubespotify').remove();
  207. DEBUGLOG.log("failed to get title");
  208. }
  209. }
  210. else
  211. {
  212. DEBUGLOG.log("not music!!");
  213. }
  214. videoinfo.complete = 1;
  215. videoinfo.url = top.location.href;
  216. videoinfo.text = jQ('#eow-title').text().trim();
  217. }
  218.  
  219. AddSpotify();
  220.  
  221. function timerfunction()
  222. {
  223. videoinfo.running = 1;
  224. if(videoinfo.complete && videoinfo.url != top.location.href)
  225. {
  226. if(videoinfo.text != jQ('#eow-title').text().trim())
  227. {
  228. AddSpotify();
  229. }
  230. }
  231. }
  232.  
  233. window.addEventListener('focus', function()
  234. {
  235. clearInterval(videoinfo.timer);
  236. if(!videoinfo.running) videoinfo.timer = setInterval(timerfunction, CheckAddress() ? 1000 : 2000);
  237. });
  238.  
  239. window.addEventListener('blur', function()
  240. {
  241. clearInterval(videoinfo.timer);
  242. videoinfo.running = 0;
  243. });
  244.  
  245. }
  246.  
  247. addJQuery(main);
  248.  
  249. };
  250.  
  251. // http://stackoverflow.com/questions/7971930/how-to-call-youtube-flash-api-of-existing-videos-using-greasemonkey
  252. function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
  253. var D = document;
  254. var scriptNode = D.createElement ('script');
  255. if (runOnLoad) {
  256. scriptNode.addEventListener ("load", runOnLoad, false);
  257. }
  258. scriptNode.type = "text/javascript";
  259. if (text) scriptNode.textContent = text;
  260. if (s_URL) scriptNode.src = s_URL;
  261. if (funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
  262.  
  263. var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
  264. targ.appendChild (scriptNode);
  265. }
  266.  
  267. addJS_Node(null, null, userscript);