youtube iframe lyrics

By lazyttrick Last update Dec 19, 2012 — Installed 2,301 times.

There are 24 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name           youtube iframe lyrics
// @namespace      meh
// @description    search youtube lyrics on an iframe
// @include        http://*
// @require        http://code.jquery.com/jquery-1.7.2.min.js
// @require        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js
// ==/UserScript==

if(top==self && location.href.search(/youtube.com/) < 0) { return; }
const MAX_Z = 2147483640;
var timerPlayerResize, body, imgLoading=null, observer;

if(location.href.search(/http:\/\/www.youtube.com/) == 0){

	runYoutube();
	
}else if(top!=self && location.href.search(/http:\/\/.+bing.com\/search\?q=.+\+%2Blyrics\+\-site\%3Ayoutube\.com/) > -1){

	runBing();
	
}else if(!GM_getValue('foundLyrics') && top!=self && GM_getValue('mode')=='redirectandcleanup' && location.href==GM_getValue('lyricsUrl')){	

	runLyricsSite();
	
}

function runYoutube(){
	
	loadimg();

	//append toggle button
	$('#watch7-secondary-actions').append($('<button id="buttonnn">').addClass('action-panel-trigger yt-uix-button yt-uix-button-text yt-uix-button-empty').attr({title:'Search Lyrics'}).click(toggleLyricsFrame).append('\u266B'));
	
	GM_addStyle(
		'#diviframeee { '+
			'background-color: #DCDCDC; '+//-moz-linear-gradient(center top , #E6E6E6 0pt, #DCDCDC 100%);
			'border-color: #999999 #AAAAAA #CCCCCC;'+
			'box-shadow: 0 1px 2px #AAAAAA inset;'+
			'border-radius: 3px;'+
		'}'+
		'#iframeee { '+
			'border-color: #999999 #AAAAAA #CCCCCC;'+
			'border-radius: 3px;'+
			'width: 100%;'+
			'height: 90%;'+
			'background-color: #E6E6E6;'+
			'overflow: auto;'+
		'}'
	);
	
	// http://nicolasgallagher.com/pure-css-speech-bubbles/
	GM_addStyle(
		'.baloonnn { position:relative; padding:15px; margin:1em 0 3em; color:#fff; background:#333;  border-radius: 10px; z-index:'+MAX_Z+' !important; box-shadow: 5px 5px 5px #000;}'+
		
		'.baloonnn.belowLeft, .baloonnn.belowRight {background:-moz-linear-gradient(bottom, #777, #333); background:linear-gradient(bottom, #777, #333);}'+
		'.baloonnn.aboveLeft, .baloonnn.aboveRight {background:-moz-linear-gradient(top, #777, #333); background:linear-gradient(top, #777, #333);}'+
		
		'.baloonnn.belowLeft:after { content:""; display:block; position:absolute; left: 50px; top: -15px; width:0; border-width:0 15px 15px; border-style:solid; border-color:#333 transparent; z-index:'+MAX_Z+' !important;}'+
		'.baloonnn.belowRight:after { content:""; display:block; position:absolute; right: 50px; top: -15px; width:0; border-width:0 15px 15px; border-style:solid; border-color:#333 transparent; z-index:'+MAX_Z+' !important;}'+
		
		'.baloonnn.aboveLeft:after { content:""; display:block; position:absolute; left: 50px; bottom: -15px; width:0; border-width:15px 15px 0; border-style:solid; border-color:#333 transparent; z-index:'+MAX_Z+' !important;}'+
		'.baloonnn.aboveRight:after { content:""; display:block; position:absolute; right: 50px; bottom: -15px; width:0; border-width:15px 15px 0; border-style:solid; border-color:#333 transparent; z-index:'+MAX_Z+' !important;}'		
	);	
	
}

function baloon(position, anchorNode, html){
	// @position: "above" or "below" anchorNode
	var left, right, anchorPos, bal;
	
	//creates baloon
	bal = $('<div>')
		.addClass('baloonnn ')
		.append(html)
		.css({
			position:'absolute',
			fontSize: 14
		})
		.appendTo(document.body);
	
	anchorPos = anchorNode.offset();
	
	//defines horizontal position
	if(anchorPos.left + (anchorNode.outerWidth()/2) >= window.innerWidth/2){ 
		//anchor baloon from the right 
		bal.addClass(position+'Right')
		bal.css({right: window.innerWidth - anchorPos.left - (anchorNode.outerWidth()/2) - 57});
	}else{ 
		//anchor baloon from the left
		bal.addClass(position+'Left')
		bal.css({left: anchorPos.left + (anchorNode.outerWidth()/2) - 57});
	}
	
	//sets baloon position
	if(position=='below'){
		bal.css({
			top: anchorNode.offset().top + 20,
		})
	}else if(position=='above'){//TODO: fix
		bal.css({
			top: anchorNode.offset().top - bal.outerHeight() - 45,
		})	
	}

	return bal;
}

function toggleHelp(){

	if($('.baloonnn').length > 0){
		$('.baloonnn').remove();
		GM_setValue('firstRun',false);
		$('#iframeee').show();
		return;
	}

	$('#iframeee').hide();
	
	// 1st baloon - input search
	baloon(
		'below', $('#inputsearchhh'), 'Make sure the search contains <b>artist</b> and <b>music</b> only.<br>'
	)
	.append(
		//next button
		$('<span>').css({cursor: 'pointer', float:'right'}).append('<br>[next]')
			.click(function(){
				
				// 2nd baloon - select mode
				$('.baloonnn').remove();
				baloon(
					'below', 
					$('#selectModeee'), 
					'Choose what to do with search results.<br>The Cleanup option works better on some sites. Favorite them. '
				)
				.append(
					$('<span>').css({cursor: 'pointer', float:'right'}).append('<br>[next]')
						.click(function(){
							
							// 3rd baloon - results navigation
							$('.baloonnn').remove();
							baloon(
								'below', 
								$('#divPagination'), 
								'Navigate through results . <br> Some lyrics may not  show up at the 1st.'
							)
							.append(
								$('<span>').css({cursor: 'pointer', float:'right'}).append('<br>[next]')
									.click(function(){
										
										// 4th baloon - favorites
										$('.baloonnn').remove();
										baloon(
											'below', 
											$('#divLyricDomainnn'), 
											'Favorite lyric sites you want to have priority.<br>Very useful for Cleanup option.'
										)
										.append(
											$('<span>').css({cursor: 'pointer', float:'right'}).append('<br>[next]')
												.click(function(){
													
													// last baloon - help
													GM_setValue('firstRun',false);
													$('.baloonnn').remove();
													baloon(
														'below', 
														$('#spanToggleHelp'), 
														'Click the \u24D8 anytime to toggle this help.<br>'
													)
													.append(
														$('<span>')
															.css({cursor: 'pointer', float:'right'})
															.append('<br>[ok]')
															.click(toggleHelp)
													)
												})
										)
									})
							)
						})
				)
			})
	)	
}

function runBing(){
	
	//scroll to bing results
	var divResults = $('#results');
	var pos = divResults.offset();
	window.scrollTo(pos.left-20, pos.top-10);
	
	//redirect
	if(GM_getValue('mode').search(/redirect/) > -1){
	
		$('#divStatusss').append('<br>Redirecting to Lyrics site...')
	
		//store results for navigation
		GM_setValue('results', escape($('#results h3 a').toArray().join()));
		GM_setValue('currentResult',0)
	
		//redirect to one of the Bing results
		try{
			var lyricsUrl, favs, results, orderedResults, j;
			favs = GM_getValue('favoriteDomains');
			if(favs==undefined || favs==''){
				//no favorites, picks first result
				lyricsUrl = $('#results h3 a:first').attr('href');
			}else{
				//order results by favorites first
				orderedResults = [];
				results = unescape(GM_getValue('results')).split(',');
				favs = favs.split(',');
				for(var i=0; i<results.length; i++){
					for(j=0; j<favs.length; j++){
						if( favs[j] == getDomain(results[i]) ) {
							orderedResults.splice(0, 0, results[i]);//insert fav at beggining
							break;
						}
					}
					if(j >= favs.length){
						orderedResults.push(results[i]);//insert non-fav at the end
					}
				}
				lyricsUrl = orderedResults[0];
				GM_setValue('results', escape(orderedResults.join()) );
			}
			GM_setValue('lyricsUrl',lyricsUrl);
			location.href = lyricsUrl;
		}catch(e){
			GM_log('Bing changed? '+e)
			GM_deleteValue('lyricsUrl');
		}
	}
}

function runLyricsSite(){

	body = $(document.body);

	//get lyrics
	var node = detectLyrics(body).clone();
	
	if(node!=null){
		//cleanup lyrics
		$('head').html('');
		$('script,noscript,iframe,style,link,javascript,a,img,ol,ul,embed,object').remove();
			
		body.removeAttr('class style background');
		body.css({
				overflow:'auto',
				backgroundColor:'#E6E6E6',
				color:'black',
				fontFamily:'Arial',
				fontSize:'14px',
				fontWeight:'normal'
			})
			.html(node.html());
	
	}else{
		GM_log('failed to detect lyrics');
	}
}

function getDomain(url){
	try{
		return url.match(/^http?:\/\/(www\.)?([^\/]+)/)[2];
	}catch(e){
		//GM_log('getDomain: '+e)
		return null;
	}
}

function getWords(node){
	try{
		return node.text().replace(/<\!--[\s\S]+-->/,'').match(/\w/g).length;
	}catch(e){
		return 0;
	}
}

function getLinks(node){
	try{
		return node.find('a').length;
	}catch(e){
		return 0;
	}
}

function detectLyrics(node){
	var divs = $('*[id*=lyric],*[class*=lyric]');
	if(divs.length==0){
		GM_log('first try failed')
		divs = $('*[id^=ly],*[class^=ly]');
	}
	if(divs.length==0){
		GM_log('second try failed')
		if(GM_getValue('mode')!='redirectandcleanup'){
			return null;
		}
		var brs = document.body.innerHTML.match(/([^><]+<br\/?>)+/g);
		var best = 0;
		for(var i=1; i<brs.length; i++){
			if(brs[i].length > brs[best].length)
				best = i;
		}
		return $('<div>').html(brs[best]);
	}
	GM_setValue('foundLyrics',true);//avoid multiple searches
	GM_log('found '+divs.length+' divs')
	var bestdiv = divs.eq(0);
	for(var i=1; i<divs.length; i++){
		if(divs.eq(i).text().length > bestdiv.text().length){
			bestdiv = divs.eq(i)
		}
	}
	return bestdiv;
}


function nextResult(){
	var results = unescape(GM_getValue('results')).split(',');
	var i = GM_getValue('currentResult');
	if(i < results.length){
		i++;
		GM_setValue('lyricsUrl',results[i]);
		GM_setValue('currentResult',i);
		GM_setValue('foundLyrics',false);
		$('#iframeee').hide().attr('src',results[i]);
		$('#imgsearchhh').show();
		updateDivDomainFav();
		updateResultsPagination();
	}
}

function prevResult(){
	var i = parseInt(GM_getValue('currentResult'));
	if(i > 0){
		var results = unescape(GM_getValue('results')).split(',');
		i--;
		GM_setValue('lyricsUrl',results[i]);
		GM_setValue('currentResult',i);
		GM_setValue('foundLyrics',false);
		$('#iframeee').hide().attr('src',results[i]);
		$('#imgsearchhh').show();
		updateDivDomainFav();
		updateResultsPagination();
	}	
}

function checkPlayerResize(evt){
	if(evt.type=='resize' || evt.attrName=='class'){
		clearTimeout(timerPlayerResize);
		$('#diviframeee').hide();
		timerPlayerResize = setTimeout(adjustIframe, 777)	
	}
}

function adjustIframe(evt){
	
	var pos = $('#movie_player').offset();			
	
	//scroll vid to top
	try{
		window.scrollTo( 0, $('#movie_player').offset().top - 3 );
	}catch(e){
		window.scrollTo( 0, $('#movie_player-html5').offset().top - 3 );
	}
	
	//position iframe
	$('#diviframeee').css({
		top: pos.top + $('#movie_player').outerHeight(), 
		left: pos.left, 
		width: 854,
		height: window.innerHeight - $('#movie_player').outerHeight() - 20
	})
	
	$('#diviframeee').show();
}

function toggleLyricsFrame(){
	
	if($('#diviframeee').length > 0){
		close();
		return;
	}
	
	if(GM_getValue('favoriteDomains')==undefined){
		GM_setValue('favoriteDomains','leoslyrics.com,lyrics.wikia.com,lyricsbox.com,lyrics007.com,lyricsmode.com,kovideo.net,macphisto.net,elyrics.net');
		GM_setValue('mode', 'redirectandcleanup');
	}
	
	//flag used to avoid multiple searches
	GM_setValue('foundLyrics',false);
	
	//delete old results
	GM_deleteValue('results');
	GM_deleteValue('currentResult');
	
	//scroll vid to top
	try{
		window.scrollTo( 0, $('#movie_player').offset().top - 3 );
	}catch(e){
		window.scrollTo( 0, $('#movie_player-html5').offset().top - 3 );
	}
	
	//get video's title
	var title = document.getElementsByTagName('title')[0].textContent.replace(/\s+/g,' ').replace(/\s*YouTube\s*/g,'').replace(/\s*$/,'').replace(/^\s*/,'');
	title = title.replace(/\s*\-\s*/g,' '); // replaces - 
	title = title.replace(/\s*\:\s*/g,' '); // replaces : 
	title = title.replace(/\([^\)]+\)/g,''); // replaces (*)
	title = title.replace(/\[[^\]]+\]/g,''); // replaces [*]
	title = title.replace(/\{[^\}]+\}/g,''); // replaces {*}
	
	//create div container
	var pos = $('#movie_player').offset();
	$('<div id="diviframeee">')
		.css({
			position: 'absolute', 
			top: pos.top + $('#movie_player').outerHeight(), 
			left: pos.left, 
			width: 854, 
			height: window.innerHeight - $('#movie_player').outerHeight() - 20,
			zIndex:MAX_Z,
			padding:7
		})
		.append(
			$('<table id="tableee">')
				.append('<tr><td id="tdtoppp"></td></tr><tr><td id="tdbottt"></td></tr>')
				.css({width:'100%', height:'100%'})
		)
		.draggable({
			handle:'#tdtoppp', 
			start:function(){
				$('#iframeee').hide();
			},
			stop:function(){
				$('#iframeee').show();
			}
		})
		.appendTo(document.body);
	
	// create top bar
	$('#tdtoppp')
		.css({paddingBottom:3, fontSize:10})
		.append(
			//help button
			$('<span id="spanToggleHelp">')
				.css({
					//float:'right',
					cursor:'pointer',
					fontSize:14,
					fontWeight:'bold',
					marginRight:7,
					color:'#888'
				})
				.attr({title:'help'})
				.append('\u24D8')
				.click(function(){
					toggleHelp();
				})
		)	
		.append('Search: ')
		.append(
			$('<input id="inputsearchhh" type="text">')
				.attr({size:'25'})
				.css({fontSize:11})
				.keyup(function(evt){
					if(evt.keyCode==13){
						changeQuery();
					}
				})
				.val(title)
				.attr({title:'search query (keep it artist and music only)'})
		)
		.append(
			$('<input type="button">').css({marginRight:13}).val('ok').click(changeQuery)
		)
		.append('Results: ')
		.append(
			$('<select id="selectModeee">')
				.css({fontSize:11})
				.append('<option value="manual">do nothing</option>')
				.append('<option value="redirect">redirect</option>')
				.append('<option value="redirectandcleanup">redirect & cleanup</option>')
				.change(function(evt){
					GM_setValue('mode',evt.target.value)
					changeQuery();
				})
				.attr({title:'what to do with search results'})
		)
		.append(
			//results pagination
			$('<div id="divPagination">')
				.attr({title: 'paginate search results'})
				.css({
					marginLeft:13, 
					display:'none'
				})
				.append(
					$('<span>').html('\u21FD').css({cursor:'pointer',fontSize:16}).click(prevResult)
				)
				.append(
					$('<span id="spanResultsPagination">').css({fontSize:12,margin:'0 2px', cursor:'default'})
				)
				.append(
					$('<span>').html('\u21FE').css({cursor:'pointer',fontSize:16}).click(nextResult)
				)
		)
		.append(
			//lyrics domain
			$('<div id="divLyricDomainnn">')
				.css({
					fontSize: 11,
					display: 'inline',
					marginLeft:13
				})
				.append(
					$('<span id="spanLyricDomainnn">')
						.attr({title:'open lyrics in new window'})
				)
				.append(
					$('<span id="spanStarDomainnn">')
						.html('\u2605')
						.css({color:'#888', cursor:'pointer', fontSize:14, marginLeft:3})
						.attr({title:'favorite lyrics site'})
						.click(toggleFavoriteDomain)
				)
				.hide()
		)		
		.append(
			//close button
			$('<span>')
				.css({
					float:'right',
					cursor:'pointer',
					fontSize:14,
					fontWeight:'bold',
					color:'#888'
				})
				.attr({title:'close'})
				.append('\u24E7')
				.click(close)
		)

	//create iframe
	$('#tdbottt')
		.css({height:'99%'})
		.append(
			$('<iframe id="iframeee">')
				.attr({src:'http://www.bing.com/search?q='+escape(title.replace(/\s+/g,'+'))+'+%2Blyrics+-site%3Ayoutube.com'})
				.load(function(evt){
					iframeLoadEvent();
				})
				.css({
					zIndex:MAX_Z+2,
					//visibility: (GM_getValue('mode')=='manual'?'visible':'hidden'),
					width:'100%',
					height:'100%'
				})
				.hide()
		);
		
	//image "searching"
	$('#tdbottt')
		.append(
			$('<center id="imgsearchhh">')
				.append($('<img>').attr('src',imgLoading))
		)

	//options state
	if(GM_getValue('mode') && GM_getValue('mode').search(/redirect/) > -1){
		$('#selectModeee').val(GM_getValue('mode'));//set mode 
	}
	
	//resize events
	document.getElementById('watch7-video').addEventListener('DOMCharacterDataModified',checkPlayerResize, false);
	window.addEventListener('resize',checkPlayerResize, false);
	
	
	if(GM_getValue('firstRun')==undefined)
		toggleHelp();
}

function toggleFavoriteDomain(evt){
	var dom = $('#spanLyricDomainnn').text();
	var favs = GM_getValue('favoriteDomains');
	var i;
	
	if(favs==undefined || favs==''){
	
		GM_setValue('favoriteDomains',dom);
		$('#spanStarDomainnn').css({color:'orange'}).attr({title:'un-favorite lyrics site'})
	
	}else {
		favs = favs.split(',');
		i = favs.indexOf(dom);
		if( i < 0 ){
			// favorite domain
			favs.push(dom);
			GM_setValue( 'favoriteDomains', favs.join() );
			$('#spanStarDomainnn').css({color:'orange'}).attr({title:'un-favorite lyrics site'})
		}else{
			// un-favorite domain
			favs.splice(i,1)
			GM_setValue('favoriteDomains', favs.join())
			$('#spanStarDomainnn').css({color:'#888'}).attr({title:'favorite lyrics site'})
		}
	}
}

function iframeLoadEvent(){
	$('#imgsearchhh').hide();
	$('#iframeee').show();
	updateResultsPagination();
	updateDivDomainFav();
}

function updateResultsPagination(){
	if(GM_getValue('mode')=='manual'){
		$('#divPagination').hide();
		return;
	}
	var results = unescape(GM_getValue('results')).split(',');
	$('#spanResultsPagination').html( (GM_getValue('currentResult')+1) + '/' + results.length)
	$('#divPagination').css({display:'inline'});
}


function updateDivDomainFav(){
	
	var dom, favs, shortdom, j;

	if(GM_getValue('mode')=='manual'){
		$('#divLyricDomainnn').hide();
		return;
	}		
	
	//set domain link
	dom = getDomain(GM_getValue('lyricsUrl'));
	shortdom = (dom.length>17 ? ('..'+dom.match(/\S{17}$/)[0]) : null);
	favs = GM_getValue('favoriteDomains');
	$('#spanLyricDomainnn').html('<a href="'+GM_getValue('lyricsUrl')+'" target="_blank" '+(shortdom?('title="'+dom+'"'):'')+'>'+(shortdom?shortdom:dom)+'</a>');

	//set fav star color
	$('#spanStarDomainnn').css({color:'#888'}).attr({title:'favorite lyrics site'});//default to grey
	if(favs!=undefined && favs!=''){
		favs = favs.split(',');
		j = favs.indexOf(dom);
		if(j > -1){
			//domain is a favorite
			$('#spanStarDomainnn').css({color:'orange'}).attr({title:'un-favorite lyrics site'})		
		}
	}
	
	$('#divLyricDomainnn').css({display:'inline'});
}

function close(){
	try{ window.removeEventListener('resize',checkPlayerResize, false); }catch(e){}
	try{ document.getElementById('watch7-video').removeEventListener('DOMAttrModified',checkPlayerResize, false); }catch(e){}
	$('#diviframeee').remove();
	$('.balonnn').remove();
	GM_setValue('firstRun',false);
}

function changeQuery(){
	
	GM_setValue('foundLyrics',false);
	
	try{ observer.disconnect(); }catch(e){ }
	
	//$('#divPagination').hide();
	//$('#divLyricDomainnn').hide();
	updateDivDomainFav();
	
	$('#iframeee')
		.hide()
		.attr({src:'http://www.bing.com/?q='+escape($('#inputsearchhh').val().replace(/\s+/g,'+'))+'+%2Blyrics+-site%3Ayoutube.com'})
		
	$('#imgsearchhh').show();
}


function debug(str){	
	var d = document.getElementById('debugg');
	if(!d){
		var div = document.createElement('div');
		div.setAttribute('id','divdebug');
		div.setAttribute('style', 'background-color:#000000; position:fixed; bottom:3px; left:3px; width:50%; z-index:999999999;');
		
		var closeButton = document.createElement('input');
		closeButton.setAttribute('id','closedebug');
		closeButton.setAttribute('type', 'button');
		closeButton.setAttribute('value', 'close');
		closeButton.setAttribute('onClick', 'this.parentNode.parentNode.removeChild(this.parentNode);');
		
		d = document.createElement('textarea');
		d.setAttribute('id','debugg');
		d.setAttribute('style',"height:150px; width:99%; margin:2px;");
		
		div.appendChild(d);
		div.appendChild(document.createElement('br'));
		div.appendChild(closeButton);
		document.body.appendChild(div);
	}
	d.innerHTML += '\n'+str;
	d.scrollTop = d.scrollHeight;
}

function loadimg(){
	imgLoading = "data:image/gif;base64,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%3D%3D";
}