Large

YouTube Video Download

By rossy! Last update Oct 14, 2011 — Installed 800,015 times.

There are 73 previous versions of this script.

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

// ==UserScript==
// @name           YouTube Video Download
// @namespace      http://rossy2401.blogspot.com/
// @description    Scans the YouTube page for all formats, including 1080p on selected videos. Designed to be lightweight and unobtrusive, it runs entirely on the page without contacting any external sites.
// @version        3.1
// @author         rossy!
// @license        MIT License
// @updateURL      https://userscripts.org/scripts/source/62634.meta.js
// @include        http://userscripts.org/scripts/source/62634.meta.js
// @include        http://*.youtube.com/watch?*
// @include        https://*.youtube.com/watch?*
// ==/UserScript==

var version = "3.1";
var host = document.location.host;

function inject(func)
{
	var script = document.createElement("script");
	script.setAttribute("type", "application/javascript");
	script.appendChild(document.createTextNode("_ytd_localVersion=\"" + version + "\";(" + func + ")();"));
	document.body.appendChild(script);
}

if (host.substr(host.length - 11) == "youtube.com" && host != "m.youtube.com") inject(function() {
	var language = document.documentElement.getAttribute("lang");
	var watchFlag = document.getElementById("watch-flag");
	var currDate = new Date().getTime();
	var formats;
	var orderedFormats;
	var title;
	var channel;
	var button;
	var menu;
	var dlheader;
	var options;
	var updateMsg;
	var showUpdate;
	var sar = 16/9;
	var videoId;
	
	var translation = {
		"en": {
			errormsg: "Error: YouTube has been updated and YouTube Video Download is no longer compatible. ",
			errorlink: "Please click here to check for updates.",
			
			button: "Download",
			tip: "Save video to hard drive",
			
			low: "Low Quality",
			high: "Low Definition",
			
			lowdef: "Low Definition",
			stddef: "Standard Definition",
			highdef: "High Definition",
			fhighdef: "Full High Definition",
			
			origdef: "Original Definition",
			
			unknown: "Unknown Format",
			
			dlheader: "Choose a format to download:",
			nofmts: "Error: No download formats available.",
			update1: "A new version of YouTube Video Download is available.",
			update2: "Click here to update now.",
			
			options: "options",
			updatetoggle: " Check for updates",
			replacetoggle: " Replace video title",
			vinfotoggle: " Set visitor info cookie (advanced)",
			tformat: "Title format: ",
			apply: "apply",
			tformatinfo: "%t - video title\n%c - uploader\n%f - format number\n%v - video id\n%% - literal percent",
		},
		"cn": { // http://userscripts.org/users/349372
			errormsg: "错误:由于YouTube网站已更新,YouTube视频下载插件已与YouTube不兼容。",
			errorlink: "查看新版请点击这里。",
			
			button: "下载",
			tip: "保存到本地",
			
			low: "低品质",
			high: "低分辨率",
			
			lowdef: "低分辨率",
			stddef: "标准分辨率",
			highdef: "较高分辨率",
			fhighdef: "最高分辨率",
			
			origdef: "原始分辨率",
			
			unknown: "未知格式",
			
			dlheader: "选择下载格式:",
			nofmts: "错误:下载格式不可用。",
			update1: "已推出新版YouTube下载插件!",
			update2: "更新请点击这里。",
			
			options: "选项",
			updatetoggle: " 检查更新",
			replacetoggle: " 重命名",
			vinfotoggle: " 设置浏览者cookies信息(高级)",
			tformat: "标题格式:",
			apply: "应用",
			tformatinfo: "%t - 视频标题\n%c - 上传者\n%f - 格式代号\n%v - 视频id\n%% - 百分率",
		},
		"cs": { // http://userscripts.org/users/janwatzek
			errormsg: "Chyba: YouTube byl aktualizován a skript YouTube Video Download již není kompatibilní. ",
			errorlink: "Prosím klikněte sem pro kontrolu, zda jsou dostupné aktualizace.",
			
			button: "Stáhnout",
			tip: "Uložit video na pevný disk",
			
			low: "Nízká kvalita",
			high: "Nízké rozlišení",
			
			lowdef: "Nízké rozlišení",
			stddef: "Standardní rozlišení",
			highdef: "Vysoké rozlišení",
			fhighdef: "Plné vysoké rozlišení",
			
			origdef: "Originální rozlišení",
			
			unknown: "Neznámý formát",
			
			dlheader: "Vyberte formát ke stažení:",
			nofmts: "Chyba: Žádné formáty nejsou dostupné ke stažení.",
			update1: "Nová verze skriptu YouTube Video Download je dostupná ke stažení!",
			update2: "Klikněte sem pro aktualizaci.",
			
			options: "nastavení",
			updatetoggle: " Kontrolovat aktualizace",
			replacetoggle: " Přepsat název videa",
			vinfotoggle: " Nastavit info návštěvníka - cookie (pokročilé)",
			tformat: "Formát názvu videa: ",
			apply: "použít",
			tformatinfo: "%t - název videa\n%c - uploader\n%f - číslo formátu\n%v - id videa\n%% - doslova procento",
		},
		"de": { // http://userscripts.org/users/348658
			errormsg: "Fehler: Die Youtube Seite wurde geändert und YouTube Video Download ist nicht mehr kompatibel. ",
			errorlink: "Bitte klicken sie hier, um auf Updates zu überprüfen.",
			
			button: "Download",
			tip: "Video auf der Festplatte speichern",
			
			low: "Niedrige Qualität",
			high: "Niedrige Auflösung",
			
			lowdef: "Niedrige Auflösung",
			stddef: "Standard Auflösung",
			highdef: "HD",
			fhighdef: "Full HD",
			
			origdef: "Original Auflösung",
			
			unknown: "Unbekanntes Format",
			
			dlheader: "Download Format wählen:",
			nofmts: "Fehler: Keine Download Formate vorhenden.",
			update1: "Eine neue Version von YouTube Video Download steht zur Verfügung.",
			update2: "Hier klicken um jetzt upzudaten.",
			
			options: "Einstellungen",
			updatetoggle: " Auf neue Version überprüfen",
			replacetoggle: " Video Titel ersetzen",
			vinfotoggle: " Besucher Info Cookie setzen (erweitert)",
			tformat: "Titel Format: ",
			apply: "anwenden",
			tformatinfo: "%t - Video Titel\n%c - Hochgeladen von\n%f - Format Nummer\n%v - Video ID\n%% - Prozentzeichen",
		},
		"es": { // http://userscripts.org/users/327867
			errormsg: "Error: YouTube ha sido actualizado y YouTube Video Download ya no es compatible. ",  
			errorlink: "Clic aquí para comprobar si hay  actualizaciones.",  
			
			button: "Descargar",  
			tip: "Descarga este video",  
			
			low: "Baja Calidad",  
			high: "Baja Definición",  
			
			lowdef: "Baja Definición",  
			stddef: "Definición Estandar",  
			highdef: "Definición HD",  
			fhighdef: "Definición FullHD",  
			
			origdef: "Definición Original",  
			
			unknown: "Formato Desconocido",  
			
			dlheader: "Elija un formato para descargar:",  
			nofmts: "Error: No hay formatos de descarga  disponibles.",  
			update1: "Una nueva version de YouTube Video Download  esta disponible.",  
			update2: "Click aqui para actualizar ahora.",  
			
			options: "Opciones",  
			updatetoggle: " Buscar actualizaciones",  
			replacetoggle: " Reemplazar título del video",  
			vinfotoggle: " Enviar cookie de visita (Avanzado)",  
			tformat: "Formato del Título: ",  
			apply: "Aplicar",  
			tformatinfo: "%t - Titulo\n%c - Uploader\n%f - Formato de número\n%v - ID del Video\n%% - % Literal",  
		},
		"fr": { // http://userscripts.org/users/87056
			errormsg: "Erreur: Youtube a été mis à jour et YouTube Video Download n'est plus compatible. ",
			errorlink: "Cliquer ici pour vérifier les mises à jour.",
			
			button: "Télécharger",
			tip: "Télécharger cette vidéo",
			
			low: "Basse Qualité",
			high: "Basse Définition",
			
			lowdef: "Basse Définition",
			stddef: "Définition Standard",
			highdef: "Haute Définition",
			fhighdef: "Très Haute Définition",
			
			origdef: "Définition Originale",
			
			unknown: "Format Inconnu",
			
			dlheader: "Choisissez le format à télécharger:",
			nofmts: "Erreur: Pas de formats de téléchargement disponible.",
			update1: "Une nouvelle version de YouTube Video Download est disponible.",
			update2: "Cliquer ici pour mettre à jour maintenant.",
			
			options: "options",
			updatetoggle: " Vérifier les mises à jour",
			replacetoggle: " Modifier le nom de fichier de la vidéo",
			vinfotoggle: " Enregister le cookie d'information du visiteur (avancé)",
			tformat: "Format du nom de fichier: ",
			apply: "Appliquer",
			tformatinfo: "%t - titre de la vidéo\n%c - uploader\n%f - numéro du format\n%v - ID de la vidéo\n%% - pourcentage littéral",
		},
		"it": { // http://userscripts.org/users/kharg
			errormsg: "Errore: YouTube \u00e8 stato aggiornato e YouTube Video Download non \u00e8 pi\u00d9 compatibile. ",
			errorlink: "Clicca qui per cercare degli aggiornamenti.",
			
			button: "Scarica",
			tip: "Salva il video nell'HD",
			
			low: "Bassa Qualit\u00e0",
			high: "Alta Qualit\u00e0",
			
			lowdef: "Bassa Definizione",
			stddef: "Qualit\u00e0 Standard",
			highdef: "Alta Definizione",
			fhighdef: "Alta Definizione",
			
			origdef: "Definizione Originale",
			
			dlheader: "Scegli un formato da scaricare:",
			nofmts: "Errore: Nessun formato da scaricare disponibile.",
			
			options: "opzioni",
			updatetoggle: " Controlla la disponibilità di aggiornamenti",
			replacetoggle: " Sostituisci il titolo del video",
			vinfotoggle: " Imposta informazioni cookie visitatori (avanzate)",
			tformat: "Formato titolo: ",
			apply: "applica",
			tformatinfo: "%t – titolo video\n%c – uploader\n%f – numero formato\n%v – id video\n%% – percentuale letterale",
		},
		"ja": { // http://userscripts.org/users/184613
			errormsg: "エラー: YouTubeのシステムが更新されたのでYouTube Video Downloadの互換性がなくなりました。",
			errorlink: "ここをクリックして更新してください。",
			
			button: "ダウンロード",
			tip: "ハードディスクにビデオを保存",
			
			low: "低品質",
			high: "低画質",
			
			lowdef: "低画質",
			stddef: "普通の画質",
			highdef: "高画質",
			fhighdef: "フル高画質",
			
			origdef: "オリジナル画質",
			
			unknown: "不明な形式",
			
			dlheader: "ダウンロードする形式を選択:",
			nofmts: "エラー:ダウンロードできません",
			update1: "YouTube Video Downloadの更新があります",
			update2: "ここをクリックすると更新します",
			
			options: "オプション",
			updatetoggle: " 更新を確認",
			replacetoggle: " ビデオのタイトルを置換",
			vinfotoggle: " 訪問者情報をクッキーに保存 (高度)",
			tformat: "タイトルの形式: ",
			apply: "適用",
			tformatinfo: "%t - ビデオタイトル\n%c - 投稿者\n%f - 型式番号\n%v - ビデオID\n%% - パーセント",
		},
		"pl": { // http://userscripts.org/users/123591
			errormsg: "Błąd: YouTube został zaktualizowany i YouTube Video Download przestał być zgodny. ",
			errorlink: "Kliknij tutaj, aby sprawdzić dostępność aktualizacji.",
			
			button: "Pobierz",
			tip: "Zapisz film na twardym dysku",
			
			low: "Niska jakość",
			high: "Niska rozdzielczość",
			
			lowdef: "Niska rozdzielczość",
			stddef: "Standardowa rozdzielczość",
			highdef: "Wysoka rozdzielczość",
			fhighdef: "Pełna wysoka rozdzielczość",
			
			origdef: "Oryginalna rozdzielczość",
			
			unknown: "Nieznany Format",
			
			dlheader: "Wybierz format do pobrania:",
			nofmts: "Błąd: Nie dostępne formaty.",
			update1: "Nowa wersja YouTube Video Download jest dostępna.",
			update2: "Kliknij tutaj, aby zaktualizować.",
			
			options: "opcje",
			updatetoggle: " Sprawdzaj aktualizacje",
			replacetoggle: " Zastąp tytuł filmu",
			vinfotoggle: " Set visitor info cookie (zaawansowane)",
			tformat: "Format Tytułu: ",
			apply: "zastosuj",
			tformatinfo: "%t - tytuł filmu\n%c - nazwa przesyłającego\n%f - numer formatu\n%v - id filmu\n%% - dosłownie procent",
		},
		"pt": { // http://userscripts.org/users/73303 (Brazilian Portuguese)
			errormsg: "Erro: Youtube foi modificado e o Youtube Video Download não é mais compatível. ",
			errorlink: "Por favor clique aqui para procurar atualizações.",
			
			button: "Baixar",
			tip: "Salvar vídeo para o disco",
			
			low: "Qualidade Baixa",
			high: "Definição Baixa",
			
			lowdef: "Definição Baixa",
			stddef: "Definição Padrão",
			highdef: "Definição Alta",
			fhighdef: "Definição Máxima",
			
			origdef: "Definição Original",
			
			unknown: "Formato Desconhecido",
			
			dlheader: "Escolha um formato para baixar:",
			nofmts: "Erro: Nenhum formato disponível para baixar.",
			update1: "Uma nova versão do Youtube Video Download está disponível.",
			update2: "Clique aqui para atualizar agora.",
			
			options: "opções",
			updatetoggle: " Procurar por atualizações",
			replacetoggle: " Substituir título do vídeo",
			vinfotoggle: " Usar cookie diferente para baixar (avançado)",
			tformat: "Formato do título: ",
			apply: "aplicar",
			tformatinfo: "%t - título do vídeo\n%c - autor do vídeo\n%f - número do formato\n%v - id do vídeo\n%% - % literal",
		},
		"ru": { // http://userscripts.org/users/121962
			errormsg: "Ошибка: YouTube был обновлен, поэтому YouTube Video Download больше не совместим. ",
			errorlink: "Нажмите тут для обновления.",
			
			button: "Скачать",
			tip: "Сохранить на жесткий диск",
			
			low: "Низкое Качество",
			high: "Низкое Разрешение",
			
			lowdef: "Низкое Разрешение",
			stddef: "Стандартное Разрешение",
			highdef: "Высокое Разрешение",
			fhighdef: "Самое высокое Разрешение",
			
			origdef: "Оригинальное Разрешение",
			
			unknown: "Неизвестный формат",
			
			dlheader: "Выберите формат для загрузки:",
			nofmts: "Ошибка: Нет загружаемых допустимых форматов.",
			update1: "Доступна новая версия YouTube Video Download.",
			update2: "Нажмите тут для обновления.",
			
			options: "настройки",
			updatetoggle: " Проверить обновления",
			replacetoggle: " Переместить видео",
			vinfotoggle: " Выставить куки посещения (доп)",
			tformat: "Формат заголовка: ",
			apply: "принять",
			tformatinfo: "%t - заголовок видео файла\n%c - имя загрузчика/автора\n%f - число файла\n%v - ид номер видео файла\n%% - буквальный процент",
		},
		"sr": { // http://userscripts.org/users/26334
			errormsg: "Грешка: YouTube је ажуриран и YouTube Видео Преузимач више није компатибилан. ",
			errorlink: "Кликните овде да проверите има ли надоградњи.",
			
			button: "Преузми",
			tip: "Сачувај видео на диск",
			
			low: "Низак квалитет",
			high: "Мала резолуција",
			
			lowdef: "Мала резолуција",
			stddef: "Стандардна резолуција",
			highdef: "Висока резолуција",
			fhighdef: "Full HD резолуција",
			
			origdef: "Оригинална резолуција",
			
			unknown: "Непознат формат",
			
			dlheader: "Изаберите формат видеа за преузимање:",
			nofmts: "Грешка: нема доступних формата.",
			update1: "Ново издање YouTube Видео Преузимача је доступно.",
			update2: "Кликните овде да ажурирате сада.",
			
			options: "опције",
			updatetoggle: " Провери надоградње",
			replacetoggle: " Замени назив видеа",
			vinfotoggle: " Постави колачић информације о посети (напредно)",
			tformat: "Формат наслова: ",
			apply: "примени",
			tformatinfo: "%t - наслов видеа\n%c - аутор\n%f - број формата\n%v - ИД видеа\n%% - постотак дословности",
		},
		"tr": { // http://userscripts.org/users/Kenterte
			errormsg: "Hata: YouTube sistemi güncellendi ve artık YouTube Video Downloader'la uyumlu değil.. ",
			errorlink: "Güncelleştirmeler için lütfen tıklayınız.",
			
			button: "İndir",
			tip: "Videoyu Farklı Kaydet",
			
			low: "Düşük Kalite",
			high: "Düşük Çözünürlük",
			
			lowdef: "Düşük Çözünürlük",
			stddef: "Standart Çözünürlük",
			highdef: "Yüksek Çözünürlük",
			fhighdef: "Çok Yüksek Çözünürlük",
			
			origdef: "Orijinal Çözünürlük",
			
			unknown: "Bilinmeyen Format",
			
			dlheader: "Bir İndirme Formatı Seçin:",
			nofmts: "Hata: Format Bulunamadı.",
			update1: "YouTube Video Downloader'ın yeni bir versiyonu var..",
			update2: "Güncelleştirmek için tıklayınız.",
			
			options: "Ayarlar",
			updatetoggle: " Güncelleştirmeleri Kontrol Et",
			replacetoggle: " Video Başlığını Değiştir",
			vinfotoggle: " Cookie bilgisini ziyaret et (Gelişmiş)",
			tformat: "Başlık Türü: ",
			apply: "Onayla",
			tformatinfo: "%t - video başlığı\n%c - yükleyen\n%f - tür numarası\n%v - video id'i\n%% - değişmez yüzde",
		},
		"zh-tw": { // http://userscripts.org/users/381783
			errormsg: "錯誤: YouTube已更新,YouTube Video Download現已無效",
			errorlink: "請點選此處更新YouTube Video Download",
			
			button: "下載",
			tip: "儲存到硬碟",
			
			low: "低品質",
			high: "低畫質",
			
			lowdef: "低畫質",
			stddef: "標準畫質",
			highdef: "HD",
			fhighdef: "Full HD",
			
			origdef: "原始畫質",
			
			unknown: "不明的格式",
			
			dlheader: "選擇要下載的格式:",
			nofmts: "錯誤:沒有可用的下載格式.",
			update1: "有新的YouTube Video Download可供更新.",
			update2: "請點選此處更新.",
			
			options: "選項",
			updatetoggle: " 檢查更新",
			replacetoggle: " 重命名",
			vinfotoggle: " 設定瀏覽者cookies (進階)",
			tformat: "標題格式: ",
			apply: "套用",
			tformatinfo: "%t - 影片標題\n%c - 上傳者\n%f - 格式\n%v - 影片id\n%% - 百分比",
		},
	};
	
	function getTrans(str)
	{
		var ret;
		if (translation[language] && (ret = translation[language][str]))
			return ret;
		else if (ret = translation["en"][str])
			return ret;
		else
			return "";
	}
	
	function createElem(tagName, template)
	{
		var ret = document.createElement(tagName);
		for (var attribute in template)
			if (attribute == "style")
				for (var property in template["style"])
					ret.style[property] = template["style"][property];
			else if (attribute == "className")
				ret.className = template["className"];
			else if (attribute == "checked")
				ret.checked = template["checked"];
			else if (attribute == "disabled")
				ret.disabled = template["disabled"];
			else if (attribute == "children")
				for (var i = 0; i < template["children"].length; i ++)
					ret.appendChild(template["children"][i]);
			else if (attribute == "actions")
				for (var action in template["actions"])
					ret.addEventListener(action, template["actions"][action], false);
			else
				ret.setAttribute(attribute, template[attribute]);
		return ret;
	}
	
	function createCookie(name, value, days)
	{
		if (days)
		{
			var date = new Date();
			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
			var expires = "; expires=" + date.toGMTString();
		}
		else
			var expires = "";
		document.cookie = name + "=" + value + expires + "; path=/; domain=.youtube.com";
	}

	function readCookie(name)
	{
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for (var i = 0; i < ca.length; i++)
		{
			var c = ca[i];
			while (c.charAt(0) == ' ')
				c = c.substring(1, c.length);
			if (c.indexOf(nameEQ) == 0)
				return c.substring(nameEQ.length, c.length);
		}
		return null;
	}

	function eraseCookie(name)
	{
		createCookie(name, "", -1);
	}
	
	function checkForUpdates()
	{
		window.addEventListener("message", function(event) {
			remoteVersion = /^\/\/ @version\s+(.+)$/m.exec(event.data)[1];
			
			if (remoteVersion)
			{
				localStorage["_ytd_lastUpdateCheck"] = currDate;
				localStorage["_ytd_remoteVersion"] = remoteVersion;
				
				if (remoteVersion != _ytd_localVersion)
					showUpdate();
			}
		}, false);
		
		document.body.appendChild(createElem("iframe", {
			src: "http://userscripts.org/scripts/source/62634.meta.js",
			style: {
				position: "absolute",
				width: "1px",
				height: "1px",
				left: "-1px",
				top: "-1px",
			},
		}));
	}
	
	function initFormats()
	{
		formats = {
			5:  { itag: 5 , quality:  1, description: getTrans("low")     , format: "FLV" , mres: { width:  400, height:  240 }, acodec: "MP3"   , vcodec: "SVQ"                          , arate: 22050, abr:  64000, vbr:  250000 },
			18: { itag: 18, quality:  5, description: getTrans("high")    , format: "MP4" , mres: { width:  480, height:  360 }, acodec: "AAC"   , vcodec: "H.264" , vpro: "Baseline@L3.0", arate: 44100, abr:  96000, vbr:  500000 },
			22: { itag: 22, quality:  8, description: getTrans("highdef") , format: "MP4" , mres: { width: 1280, height:  720 }, acodec: "AAC"   , vcodec: "H.264" , vpro: "High@L3.1"    , arate: 44100, abr: 152000, vbr: 2000000 },
			34: { itag: 34, quality:  3, description: getTrans("lowdef")  , format: "FLV" , mres: { width:  640, height:  360 }, acodec: "AAC"   , vcodec: "H.264" , vpro: "Main@L3.0"    , arate: 44100, abr: 128000, vbr:  500000 },
			35: { itag: 35, quality:  6, description: getTrans("stddef")  , format: "FLV" , mres: { width:  854, height:  480 }, acodec: "AAC"   , vcodec: "H.264" , vpro: "Main@L3.0"    , arate: 44100, abr: 128000, vbr:  800000 },
			37: { itag: 37, quality:  9, description: getTrans("fhighdef"), format: "MP4" , mres: { width: 1920, height: 1080 }, acodec: "AAC"   , vcodec: "H.264" , vpro: "High@L4.0"    , arate: 44100, abr: 152000, vbr: 3500000 },
			38: { itag: 38, quality: 10, description: getTrans("origdef") , format: "MP4" , mres: { width: 4096, height: 3072 }, acodec: "AAC"   , vcodec: "H.264" },
			43: { itag: 43, quality:  2, description: getTrans("lowdef")  , format: "WebM", mres: { width:  640, height:  360 }, acodec: "Vorbis", vcodec: "VP8"                          , arate: 44100, abr: 128000, vbr:  500000 },
			44: { itag: 44, quality:  4, description: getTrans("stddef")  , format: "WebM", mres: { width:  854, height:  480 }, acodec: "Vorbis", vcodec: "VP8"                          , arate: 44100, abr: 128000, vbr: 1000000 }, 
			45: { itag: 45, quality:  7, description: getTrans("highdef") , format: "WebM", mres: { width: 1280, height:  720 }, acodec: "Vorbis", vcodec: "VP8"                          , arate: 44100, abr: 192000, vbr: 2000000 },
		};
		orderedFormats = new Array();
	}
	
	var createMenu = function() {
		var ret;
		button = createElem("button", {
			className: "yt-uix-button" + (watchFlag.disabled ? "" : " yt-uix-tooltip") + " yt-uix-tooltip-reverse",
			title: (watchFlag.disabled ? "" : getTrans("tip")),
			type: "button",
			role: "button",
			"aria-pressed": "false",
			onclick: "; return false;",
			disabled: watchFlag.disabled,
			children: [
				createElem("span", {
					className: "yt-uix-button-content",
					children: [
						document.createTextNode(getTrans("button")),
					],
				}),
				document.createTextNode(" "),
				createElem("img", {
					className: "yt-uix-button-arrow",
					src: "//s.ytimg.com/yt/img/pixel-vfl73.gif",
					alt: "",
				}),
				ret = createElem("div", {
					className: "yt-uix-button-menu",
					style: {
						display: "none",
						backgroundColor: "#eaeaea",
					},
					children: [
						dlheader = createElem("div", {
							className: "yt-uix-button-menu-item",
							style: {
								fontSize: "smaller",
								fontWeight: "bold",
								backgroundColor: "#eaeaea",
								cursor: "default",
							},
							children: [
								document.createTextNode(getTrans("nofmts")),
							],
						}),
						updateMsg = createElem("a", {}),
					],
				}),
			],
		});
		return ret;
	};
	
	var appendedMenu = false;
	var appendMenu = function() {
		watchFlag.parentNode.insertBefore(button, watchFlag);
		watchFlag.parentNode.insertBefore(document.createTextNode(" "), watchFlag);
		appendedMenu = true;
	};
	
	function createHeader()
	{
		dlheader.style.borderBottom = "1px solid #999999";
		dlheader.removeChild(dlheader.firstChild);
		dlheader.appendChild(createElem("a", {
			style: {
				cssFloat: "right",
				color: "#4272db",
				fontWeight: "normal",
				cursor: "pointer",
			},
			children: [
				document.createTextNode(getTrans("options")),
			],
			actions: {
				click: function() {
					options.style.display = options.style.display == "none" ? "" : "none";
				},
			},
		}));
		dlheader.appendChild(document.createTextNode(getTrans("dlheader")));
		var tformat;
		dlheader.appendChild(options = createElem("div", {
			style: {
				display: "none",
				fontWeight: "normal",
				fontSize: "12px",
				paddingTop: "6px",
			},
			children: [
				createElem("input", {
					type: "checkbox",
					id: "-ytd-update",
					checked: localStorage["_ytd_checkForUpdates"] == "yes",
					actions: {
						change: function() {
							localStorage["_ytd_checkForUpdates"] = this.checked ? "yes" : "no";
						},
					},
				}),
				createElem("label", {
					"for": "-ytd-update",
					children: [
						document.createTextNode(getTrans("updatetoggle")),
					],
				}),
				createElem("br", {}),
				createElem("input", {
					type: "checkbox",
					id: "-ytd-setvinfo",
					checked: readCookie("VISITOR_INFO1_LIVE") == "AAAAAAAAAAA",
					actions: {
						change: function() {
							if (this.checked)
								createCookie("VISITOR_INFO1_LIVE", "AAAAAAAAAAA", 9999);
							else
								eraseCookie("VISITOR_INFO1_LIVE");
						},
					},
				}),
				createElem("label", {
					"for": "-ytd-setvinfo",
					children: [
						document.createTextNode(getTrans("vinfotoggle")),
					],
				}),
				createElem("br", {}),
				createElem("input", {
					type: "checkbox",
					id: "-ytd-replace",
					checked: localStorage["_ytd_replaceTitle"] == "yes",
					actions: {
						change: function() {
							if (this.checked)
							{
								localStorage["_ytd_replaceTitle"] = "yes";
								tformat.disabled = false;
							}
							else
							{
								localStorage["_ytd_replaceTitle"] = "no";
								localStorage["_ytd_titleFormat"] = "video";
								tformat.value = "video";
								tformat.disabled = true;
							}
							getStreamMap();
							getHTML5Map();
						},
					},
				}),
				createElem("label", {
					"for": "-ytd-replace",
					children: [
						document.createTextNode(getTrans("replacetoggle")),
					],
				}),
				createElem("br", {}),
				document.createTextNode(getTrans("tformat")),
				tformat = createElem("input", {
					type: "text",
					disabled: localStorage["_ytd_replaceTitle"] != "yes",
					value: localStorage["_ytd_titleFormat"],
					actions: {
						input: function() {
							localStorage["_ytd_titleFormat"] = this.value;
						},
					},
				}),
				document.createTextNode(" "),
				createElem("a", {
					style: {
						color: "#4272db",
						cursor: "pointer",
					},
					children: [
						document.createTextNode(getTrans("apply")),
					],
					actions: {
						click: function() {
							getStreamMap();
							getHTML5Map();
						},
					},
				}),
				createElem("br", {}),
				createElem("span", {
					style: {
						fontSize: "smaller",
						whiteSpace: "pre",
					},
					children: [
						document.createTextNode(getTrans("tformatinfo")),
					],
				}),
			],
		}));
	}
	
	var addMenu = function(format) {
		var width;
		var height;
		
		if (format.fres)
		{
			width = format.fres.width;
			height = format.fres.height;
		}
		else if (format.mres)
			if (Math.abs(format.mres.width / format.mres.height - 1.7) < 0.1 && Math.abs(sar - 1.7) < 0.1)
			{
				width = format.mres.width;
				height = format.mres.height;
			}
			else if (format.mres.height * sar > format.mres.width)
			{
				width = format.mres.width;
				height = format.mres.width / sar;
			}
			else
			{
				width = format.mres.height * sar;
				height = format.mres.height;
			}
		
		var elem = createElem("a", {
			href: format.url,
			className: "yt-uix-button-menu-item",
			style: {
				position: "relative",
				paddingRight: "7em",
			},
			children: [
				document.createTextNode(format.description ? format.description + (format.mres && Math.abs(format.mres.width / format.mres.height - 1.7) < 0.1 ? ", " + format.mres.height + "p" : "") + " " + format.format + " " : getTrans("unknown") + " " + format.itag),
				createElem("span", {
					style: {
						position: "absolute",
						right: "0.6666em",
						opacity: 0.6,
						cssFloat: "right",
					},
					children: [
						document.createTextNode(format.vcodec ? format.vcodec + (format.acodec ? "/" + format.acodec: "") : format.html5hint ? format.html5hint.type.substring(0, format.html5hint.type.indexOf(";")) : "itag=" + format.itag),
					],
				}),
			],
		});
		if (!orderedFormats.length)
			createHeader();
		
		var i;
		for (i = 0; i < orderedFormats.length; i ++)
			if (orderedFormats[i].quality < format.quality)
				break;
		
		if (orderedFormats[i])
			menu.insertBefore(elem, orderedFormats[i].elem);
		else
			menu.insertBefore(elem, updateMsg);
		orderedFormats.splice(i, 0, format);
		
		if (format.elem)
			menu.removeChild(format.elem);
		format.elem = elem;
	}
	
	var updateShown = false;
	showUpdate = function() {
		var link;
		
		if (updateShown)
			return;
		else
			updateShown = true;
		
		updateMsg.setAttribute("href", "http://userscripts.org/scripts/source/62634.user.js");
		
		updateMsg.className = "yt-uix-button-menu-item";
		updateMsg.style.fontSize = "smaller";
		updateMsg.style.fontWeight = "bold";
		updateMsg.style.backgroundColor = "#eaeaea";
		updateMsg.style.borderTop = "1px solid #999999";
		
		updateMsg.appendChild(document.createTextNode(getTrans("update1")));
		updateMsg.appendChild(createElem("br", {}));
		updateMsg.appendChild(link = createElem("span", {
			style: {
				fontWeight: "normal",
				color: "#4272db",
			},
			children: [
				document.createTextNode(getTrans("update2")),
			],
		}));
		
		updateMsg.addEventListener("mouseover", function() {
			link.style.textDecoration = "underline";
		}, false);
		updateMsg.addEventListener("mouseout", function() {
			link.style.textDecoration = "";
		}, false);
	};
	
	function addUrl(itag, url)
	{
		if (localStorage["_ytd_replaceTitle"])
		{
			var titleChangable = true;
			var tformatted = localStorage["_ytd_titleFormat"].replace(/%./g, function(str, offset, s) {
				if (str == "%t")
					return title;
				else if (str == "%c")
					return channel;
				else if (str == "%f")
					return itag;
				else if (str == "%v")
					return videoId;
				else if (str == "%%")
					return "%";
				return str;
			});
			var escapedTitle = tformatted.replace(/"/g, "-").replace(/%/g, "%25").replace(/=/g, "%3D").replace(/,/g, "%2C").replace(/&/g, "%26").replace(/#/g, "%23").replace(/\?/g, "%3F").replace(/\//g, "_").replace(/\\/g, "_").replace(/ /g, "+");
			var queryLoc = url.indexOf("?");
			var location = url.substr(0, queryLoc);
			var query = url.substr(queryLoc + 1).split("&");
			var name;
			var splitLoc;
			for (var i = 0; i < query.length; i ++)
			{
				name = query[i].substr(0, splitLoc = query[i].indexOf("="));
				if (name == "sparams")
				{
					var sparams = unescape(query[i].substr(splitLoc + 1)).split(",");
					for (var j = 0; j < sparams.length; j ++)
						if (sparams[j] == "title")
							titleChangable = false;
				}
				else if (name == "title" && titleChangable)
				{
					query[i] = "title=" + escapedTitle;
					titleChangable = false;
					url = location + "?" + query.join("&");
				}
			}
			if (titleChangable)
				url = url + "&title=" + escapedTitle;
		}
		
		if (formats[itag])
			formats[itag].url = url;
		else
			formats[itag] = { itag: itag, url: url };
		
		addMenu(formats[itag]);
	}
	
	function getStreamMap()
	{
		var streamMap;
		try
		{
			if (!(streamMap = yt.getConfig("PLAYER_CONFIG").args["url_encoded_fmt_stream_map"]))
				throw "";
		}
		catch (e)
		{
			try
			{
				var flashVars = document.getElementById("movie_player").getAttribute("flashvars").split("&");
				var splitLoc;
				var name;
				for (var i = 0; i < flashVars.length; i ++)
				{
					name = flashVars[i].substr(0, splitLoc = flashVars[i].indexOf("="));
					if (name == "url_encoded_fmt_stream_map")
						streamMap = unescape(flashVars[i].substr(splitLoc + 1));
				}
				if (!streamMap)
					throw "";
			}
			catch (e)
			{
				try
				{
					var swfConfigTxt = document.getElementById("postpage").getElementsByTagName("script")[3].textContent;
					if (swfConfigTxt.substring(0, 18) == "\n    (function() {")
					{
						eval(swfConfigTxt.substring(18, swfConfigTxt.length - 8))
						streamMap = swfConfig.args.url_encoded_fmt_stream_map;
					}
				}
				catch (e)
				{
					return false;
				}
			}
		}
		
		if (streamMap)
		{
			streamMap = streamMap.split(",");
			var split;
			var url;
			var itag;
			var name;
			for (var i = 0; i < streamMap.length; i ++)
			{
				split = streamMap[i].split("&");
				for (var j = 0; j < split.length; j ++)
				{
					name = split[j].substring(0, split[j].indexOf("="));
					if (name == "url")
						url = unescape(split[j].substring(split[j].indexOf("=") + 1));
					else if (name == "itag")
						itag = parseInt(split[j].substring(split[j].indexOf("=") + 1));
				}
				addUrl(itag, url);
			}
			return true;
		}
		else
			return false;
	}
	
	function getHTML5Map()
	{
		try
		{
			var hFormatMap = yt.getConfig("PLAYER_CONFIG").args["html5_fmt_map"];
			if (hFormatMap)
				for (var i = 0; i < hFormatMap.length; i ++)
				{
					if (formats[hFormatMap[i].itag])
						formats[hFormatMap[i].itag].html5hint = hFormatMap[i];
					else
						formats[hFormatMap[i].itag] = { itag: hFormatMap[i].itag, html5hint: hFormatMap[i] };
					addUrl(hFormatMap[i].itag, hFormatMap[i].url);
				}
			else
				return false;
		}
		catch (e)
		{
			return false;
		}
		return true;
	}
	
	function getTitle()
	{
		var title = document.getElementById("eow-title");
		if (title)
			return title.getAttribute("title").replace(/^\s+/, "").replace(/\s+$/, "");
		else
			return document.title.substr(10);
	}
	
	function getChannel()
	{
		try
		{
			return yt.getConfig("VIDEO_USERNAME");
		}
		catch (e)
		{
			try
			{
				return document.getElementById("watch-uploader-info").getElementsByClassName("author")[0].textContent;
			}
			catch (e)
			{
				return "unknown";
			}
		}
	}
	
	function getSAR()
	{
		try
		{
			return yt.getConfig("IS_WIDESCREEN") ? 16/9 : 4/3;
		}
		catch (e)
		{
			return 16/9;
		}
	}
	
	function getVideoId()
	{
		try
		{
			return yt.getConfig("VIDEO_ID");
		}
		catch (e)
		{
			return "";
		}
	}
	
	var vo;
	if (vo = document.getElementById("vo"))
	{
		var ret;
		
		createMenu = function() {
			vo.insertBefore(createElem("button", {
				className: "b",
				children: [
					document.createTextNode("Download"),
				],
				actions: {
					click: function() {
						featherMenu.style.display = featherMenu.style.display == "none" ? "" : "none";
					},
				},
			}), vo.lastChild);
			
			vo.parentNode.insertBefore(ret = createElem("div", {
				style: {
					marginTop: "10px",
					lineHeight: "14px",
					padding: "5px",
					border: "1px solid #eaeaea",
					borderRadius: "5px",
					display: "none",
				},
			}), vo.nextSibling);
			
			return ret;
		};
		
		addMenu = function(format) {
			var elem = createElem("a", {
				href: format.url,
				children: [
					document.createTextNode(format.description ? format.description + (format.mres && Math.abs(format.mres.width / format.mres.height - 1.7) < 0.1 ? ", " + format.mres.height + "p" : "") + " " + format.format + " " : getTrans("unknown")),
				],
				style: {
					display: "block",
				},
			});
			var i;
			
			for (i = 0; i < orderedFormats.length; i ++)
				if (orderedFormats[i].quality < format.quality)
					break;
			
			if (orderedFormats[i])
				menu.insertBefore(elem, orderedFormats[i].elem);
			else
				menu.appendChild(elem);
			orderedFormats.splice(i, 0, format);
			
			if (format.elem)
				menu.removeChild(format.elem);
			format.elem = elem;
		};
		
		showUpdate = function() {};
		appendMenu = function() {};
	}
	
	try
	{
		if (!localStorage["_ytd_checkForUpdates"])
			localStorage["_ytd_checkForUpdates"] = ((window.chrome || window.globalStorage) && _ytd_localVersion != "git" ? "yes" : "no");
		if (!localStorage["_ytd_replaceTitle"])
			localStorage["_ytd_replaceTitle"] = "yes";
		if (!localStorage["_ytd_titleFormat"])
			localStorage["_ytd_titleFormat"] = "%t";
		
		title = getTitle();
		channel = getChannel();
		sar = getSAR();
		videoId = getVideoId();
		
		menu = createMenu();
		if (watchFlag.disabled)
		{
			appendMenu();
			return;
		}
		initFormats();
		getStreamMap();
		getHTML5Map();
		appendMenu();
		
		if (localStorage["_ytd_localVersion"] != _ytd_localVersion)
		{
			localStorage["_ytd_remoteVersion"] = _ytd_localVersion;
			localStorage["_ytd_localVersion"] = _ytd_localVersion;
		}
		
		if (localStorage["_ytd_checkForUpdates"] == "yes")
		{
			if (!localStorage["_ytd_remoteVersion"] || !localStorage["_ytd_lastUpdateCheck"] || currDate - parseInt(localStorage["_ytd_lastUpdateCheck"]) > 1000 * 60 * 60 * 24 * 2)
				checkForUpdates();
			
			if (localStorage["_ytd_remoteVersion"] && localStorage["_ytd_remoteVersion"] != _ytd_localVersion)
				showUpdate();
		}
	}
	catch (e)
	{
		var firstChild = document.body.firstChild;
		document.body.insertBefore(document.createTextNode(getTrans("errormsg")), firstChild);
		document.body.insertBefore(createElem("a", {
			href: "http://userscripts.org/scripts/show/62634",
			target: "_blank",
			children: [
				document.createTextNode(getTrans("errorlink")),
			],
		}), firstChild);
		document.body.insertBefore(createElem("br"), firstChild);
		document.body.insertBefore(document.createTextNode("Error: " + (e.lineNumber ? e.lineNumber+ ": " : "") + (e.name ? e.name + ": ": "") + (e.message ? e.message : e.description ? e.description : "")), firstChild);
		
		if (button && !appendedMenu)
			appendMenu();
		
		throw e;
	}
});
else if (document.location.href == "http://userscripts.org/scripts/source/62634.meta.js") inject(function() {
	window.parent.postMessage(document.documentElement.textContent, "*");
});