ビデオを直接ダウンロードするためのリンクを追加するスクリプト

  • YoutubeDownloader_Tak.user2.zip
    • 2012/12/08 デザイン変更に追従(左のガイドの下にリンクが出るようにした)。
    • 2012/09/21 signatureを追加するように変更。
    • 2012/01/30 flashvarsを読み取るように変更。
    • 2011/08/13 ytオブジェクトを使用するように変更。
    • 2011/08/07 url_encoded_fmt_stream_map を元にリンクを作成するようにした。
    • 2011/07/01 エラーの場合に理由を表示するようにした。
    • 2011/01/01 fmt_url_map を参照するように変更。フォーマットの表示形式を変更。タイトル対応。
    • 2010/11/06 YouTubeの仕様変更に対応。
    • 2010/04/01 YouTubeの体裁変更に対応。
    • 2009年4月頭に仕様が変わったようでこれまでのスクリプトが使えなくなったんで書き直し。
      そのフォーマットが存在するかどうかは fmt_map 見て判断するようにしたけど、実際に存在してても fmt_map に含まれてないのはどうしたもんかな。(--;)
      // ==UserScript==
      // @name		YoutubeDownloader_Tak
      // @namespace	http://www.TakeAsh.net/
      // @description	Add downloadable links in Youtube Page
      // @ujs:modified 2012-12-08 15:30
      // @include		http://*.youtube.com/watch*
      // @include		https://*.youtube.com/watch*
      // ==/UserScript==
      (function () {
      	var fmt_list = {};
      	var fmt_stream_map = [];
      	var flashvars = '';
      	var elmEmbeds = document.getElementsByTagName('embed');
      	for (var i = 0; i < elmEmbeds.length; ++i) {
      		if (flashvars = elmEmbeds[i].getAttribute('flashvars')) {
      			break;
      		}
      	}
      	if (flashvars) {
      		flashvars = getMap(flashvars, '&', /^([^=]+)=(.*)$/);
      		fmt_list = getMap(flashvars.fmt_list, ',', /^(\d+)\/(\d+x\d+)/i);
      		fmt_stream_map = getIndexedMap(flashvars.url_encoded_fmt_stream_map, 'itag');
      	}
      	var title = '';
      	var elmMetas = document.getElementsByTagName('meta');
      	for (var i = 0; i < elmMetas.length; ++i) {
      		if (elmMetas[i].name == 'title') {
      			title = encodeURIComponent(
      				elmMetas[i].content.replace(/([\\\/\:\*\?\"\|<>])/g, '_')
      			);
      			break;
      		}
      	}
      	//alert(_dump(fmt_stream_map));
      	for (var p in fmt_list) {
      		fmt_stream_map[p]['size'] = fmt_list[p];
      		fmt_stream_map[p]['width'] = parseInt(fmt_list[p]);
      		fmt_stream_map[p]['type'].match(/^\w+\/(?:x-)?([^;]+)/);
      		fmt_stream_map[p]['ext'] = RegExp.$1;
      	}
      	fmt_stream_map.sort(function (a, b) {
      		return (b['width'] - a['width'] != 0) 
      			? b['width'] - a['width'] 
      			: ((a['ext'] > b['ext']) ? 1 : -1);
      	});
      	document.getElementById('guide-main').innerHTML
      		+= '<div id="DL-YT-video" align="right"></div>';
      	/* Firefoxバグ?対策 */
      	document.getElementById('DL-YT-video').innerHTML 
      		+= '<div id="DL-YT-video-formats-dummy">&nbsp;</div>';
      	for (var i = 0; i < fmt_stream_map.length; ++i) {
      		var fmt = fmt_stream_map[i];
      		if (fmt) {
      			var params = [];
      			for (var p in fmt) {
      				params.push(p + ': ' + escapeHTML(fmt[p]));
      			}
      			document.getElementById('DL-YT-video').innerHTML 
      				+= '<div id="DL-YT-video-formats-' + fmt['itag'] + '">' 
      				+ '<a href="' + fmt['url'] + '&signature=' + fmt['sig'] 
      				+ '&title=' + title + '" title="' + params.sort().join('\n') + '">' 
      				+ fmt['ext'] + ' / ' + fmt['size'] + '</a></div>';
      		} else {
      			// ソートしたときに undefined が入った要素ができる
      			break;
      		}
      	}
      
      	function getMap(param, separater, regex) {
      		var map = {};
      		var tmp = param.split(separater);
      		for (var i = 0; i < tmp.length; ++i) {
      			tmp[i].match(regex);
      			map[RegExp.$1] = decodeURIComponent(RegExp.$2);
      		}
      		return map;
      	}
      
      	function getIndexedMap(param, primary) {
      		var map = [];
      		var tmp1 = param.split(',');
      		for (var i = 0; i < tmp1.length; ++i) {
      			var tmp2 = getMap(tmp1[i], '&', /^([^=]+)=(.*)$/);
      			map[tmp2[primary]] = tmp2;
      		}
      		return map;
      	}
      
      	function escapeHTML(str) {
      		var mapEscape = {
      			'&': 'amp', '<': 'lt', '>': 'gt', '"': 'quot', 
      		};
      		var classEscape = '';
      		for (p in mapEscape) {
      			classEscape += p;
      		}
      		var reg = new RegExp(
      			'([' + classEscape.replace(/([^0-9A-Za-z_])/g, '\\$1') + '])', 
      			'g'
      		);
      		return ('' + str).replace(reg, function (whole, p1) {
      			return '&' + mapEscape[p1] + ';';
      		});
      	}
      
      	function _dump(obj) {
      		var ret = '';
      		for (var p in obj) {
      			if (typeof (obj[p]) == 'object') {
      				ret += '\n' + p + ':\n';
      				ret += _dump(obj[p]);
      			} else {
      				ret += p + ': ' + obj[p] + '\n';
      			}
      		}
      		return ret;
      	}
      })();

リンク

YouTubeのビデオIDを抽出

  • 今見ているYouTubeのビデオIDを抽出
    javascript:void(function(){
    var url=location.href;
    prompt( 'YouTube Video ID', (url.match(/v=([^&\s]+)/))[1] );
    })()

YouTubeのタイトルとビデオIDを抽出(PukiWiki用)

javascript:void(function(){
var elm = document.getElementsByTagName( 'meta' );
var title = '';
for(var i=0; i<elm.length; ++i){
	if( elm[i].name == 'title' ){
		title = elm[i].content;
		break;
	}
}
prompt(
	'YouTube Video ID', 
	'[[' + title + '>YouTube:' + (location.href.match(/v=([^&\s]+)/))[1] + ']]'
);
})()

YouTube の URL を短縮

javascript: location = 'http://www.youtube.com/watch?hd=1&v=' + (location.href.match(/v=([^&]+)/))[1];

YouTubeをHDで見る

  • 480x360, 480x270 (fmt=18)
    javascript:location=location.href.replace(/&fmt=\d+/g,'')+'&fmt=18'
  • 1280x720 (fmt=22)
    javascript:location=location.href.replace(/&fmt=\d+/g,'')+'&fmt=22'