/* Copyright (C) 2010 - 2017 Sebastian Luncan Copyright (C) 2017 Arun Isaac This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Website: http://isebaro.com/viewtube Contact: http://isebaro.com/contact */ // ==========Variables========== // (function() { // Userscript var userscript = 'ViewTube'; // Page var page = {win: window, doc: document, body: document.body, url: window.location.href, title: document.title, site: window.location.hostname.match(/([^.]+)\.[^.]+$/)[1]}; // Player var player = {}; var option = {'autoplay': false, 'definition': 'HD', 'container': 'MP4', 'dash': false, 'direct': false, 'widesize': false, 'fullsize': false}; var mimetypes = { 'MPEG': 'video/mpeg', 'MP4': 'video/mp4', 'WebM': 'video/webm', 'FLV': 'video/x-flv', 'MOV': 'video/quicktime', 'M4V': 'video/x-m4v', 'AVI': 'video/x-msvideo', '3GP': 'video/3gpp', }; var sources = {}; // Links var website = 'https://git.systemreboot.net/youtube-noscript-shim/about'; var contact = 'mailto:arunisaac@systemreboot.net'; // ==========Functions========== // function createMyElement(type, content, event, action, target) { function styleButton (button, state) { styleMyElement(player[button], state ? {color: '#008080', textShadow: '0px 1px 1px #CCCCCC'} : {color: '#CCCCCC', textShadow: '0px 0px 0px'}); } var obj = page.doc.createElement(type); if (content) { switch (type) { case 'div': obj.innerHTML = content; break; case 'img': obj.src = content; break; case 'option': obj.value = content; obj.innerHTML = content; break; case 'video': obj.src = content; obj.controls = 'controls'; obj.autoplay = 'autoplay'; obj.volume = 0.8; obj.innerHTML = '

The video should be loading. If it doesn\'t load, make sure your browser supports HTML5\'s Video and this video codec. If you think it\'s a script issue, please report it here.'; break; } } if (type == 'video') { obj.type = mimetypes[player['videoPlay'].replace(/.*\s/, '')]; obj.id = 'vtVideo'; } if (event == 'change') { if (target == 'video') { obj.addEventListener('change', function() { player['videoPlay'] = this.value; if (player['isPlaying']) playMyVideo(option['autoplay']); }, false); } } else if (event == 'click') { obj.addEventListener('click', function() { switch (action) { case 'close': page.body.removeChild(target); break; case 'play': playMyVideo(!player['isPlaying']); break; case 'autoplay': option['autoplay'] = !option['autoplay']; styleButton('buttonAutoplay', option['autoplay']); playMyVideo(option['autoplay'] && (!player['isPlaying'])); break; case 'dash': option['dash'] = !option['dash']; styleButton('buttonDASH', option['dash']) setMyOptions('dash', option['dash']); break; case 'widesize': option['widesize'] = !option['widesize']; setMyOptions('widesize', option['widesize']); resizeMyPlayer('widesize'); break; case 'fullsize': option['fullsize'] = !option['fullsize']; setMyOptions('fullsize', option['fullsize']); resizeMyPlayer('fullsize'); break; } }, false); } return obj; } function getMyElement(obj, type, from, value, child, content) { var getObj, chObj, coObj; var pObj = (!obj) ? page.doc : obj; if (type == 'body') getObj = pObj.body; else { if (from == 'id') getObj = pObj.getElementById(value); else if (from == 'class') getObj = pObj.getElementsByClassName(value); else if (from == 'tag') getObj = pObj.getElementsByTagName(type); else if (from == 'ns') getObj = pObj.getElementsByTagNameNS(value, type); } chObj = (child >= 0) ? getObj[child] : getObj; if (content && chObj) { if (type == 'html' || type == 'body' || type == 'div' || type == 'option') coObj = chObj.innerHTML; else if (type == 'object') coObj = chObj.data; else if (type == 'img' || type == 'video' || type == 'embed') coObj = chObj.src; else coObj = chObj.textContent; return coObj; } else { return chObj; } } function modifyMyElement(obj, type, content, clear, hide) { if (content) { if (type == 'div') obj.innerHTML = content; else if (type == 'option') { obj.value = content; obj.innerHTML = content; } else if (type == 'object') obj.data = content; else if (type == 'img' || type == 'video' || type == 'embed') obj.src = content; } if (clear) { if (obj.hasChildNodes()) { while (obj.childNodes.length >= 1) { obj.removeChild(obj.firstChild); } } } if (hide) { for (var i = 0; i < obj.children.length; i++) { styleMyElement(obj.children[i], {display: 'none'}); } } } function styleMyElement(obj, styles) { for (var property in styles) { if (styles.hasOwnProperty(property)) obj.style[property] = styles[property]; } } function createMyPlayer() { /* Get My Options */ function onGot(item) { Object.assign(option, item); /* Player Settings */ player['panelHeight'] = 18; player['panelPadding'] = 2; /* The Panel */ var panelWidth = player['playerWidth'] - player['panelPadding'] * 2; player['playerPanel'] = createMyElement('div', '', '', '', ''); styleMyElement(player['playerPanel'], {width: panelWidth + 'px', height: player['panelHeight'] + 'px', padding: player['panelPadding'] + 'px', backgroundColor: 'inherit', textAlign: 'center'}); player['playerWindow'].appendChild(player['playerPanel']); /* Panel Items */ var panelItemBorder = 1; var panelItemHeight = player['panelHeight'] - panelItemBorder * 2; /* Panel Video Menu */ player['videoMenu'] = createMyElement('select', '', 'change', '', 'video'); player['videoMenu'].title = '{Videos: select the video format for playback}'; styleMyElement(player['videoMenu'], {width: '200px', height: panelItemHeight + 'px', border: '1px solid transparent', padding: '0px', display: 'inline', backgroundColor: 'inherit', color: '#336699', fontSize: '12px', textShadow: '0px 1px 1px #CCCCCC', verticalAlign: 'baseline', cursor: 'pointer'}); player['playerPanel'].appendChild(player['videoMenu']); for (var videoCode in player['videoList']) { player['videoItem'] = createMyElement('option', videoCode, '', '', ''); styleMyElement(player['videoItem'], {padding: '0px', display: 'block', color: '#336699', fontSize: '12px', textShadow: '0px 1px 1px #CCCCCC', cursor: 'pointer'}); if (videoCode.indexOf('Video') != -1 || videoCode.indexOf('Audio') != -1) styleMyElement(player['videoItem'], {color: '#8F6B32'}); if (player['videoList'][videoCode] == 'DASH') styleMyElement(player['videoItem'], {color: '#CF4913'}); if (player['videoList'][videoCode] != 'DASH' || option['dash']) player['videoMenu'].appendChild(player['videoItem']); else delete player['videoList'][videoCode]; if (videoCode == 'Direct Video Link') styleMyElement(player['videoItem'], {color: '#00C0C0'}); } /* Panel Autoplay Button */ player['buttonAutoplay'] = createMyElement('div', 'AP', 'click', 'autoplay', ''); player['buttonAutoplay'].title = '{Autoplay: click to enable/disable auto playback on page load}'; styleMyElement(player['buttonAutoplay'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#CCCCCC', fontSize: '12px', cursor: 'pointer'}); if (option['autoplay']) styleMyElement(player['buttonAutoplay'], {color: '#008080', textShadow: '0px 1px 1px #CCCCCC'}); player['playerPanel'].appendChild(player['buttonAutoplay']); /* Panel DASH Button */ player['buttonDASH'] = createMyElement('div', 'MD', 'click', 'dash', ''); player['buttonDASH'].title = '{MPEG-DASH: click to enable/disable DASH playback using the HTML5 video player (experimental)}'; styleMyElement(player['buttonDASH'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#CCCCCC', fontSize: '12px', cursor: 'pointer'}); if (option['dash']) styleMyElement(player['buttonDASH'], {color: '#008080', textShadow: '0px 1px 1px #CCCCCC'}); player['playerPanel'].appendChild(player['buttonDASH']); /* Panel Widesize Button */ player['buttonWidesize'] = createMyElement('div', option['widesize'] ? '<' : '>', 'click', 'widesize', ''); player['buttonWidesize'].title = '{Widesize: click to enter player widesize or return to normal size}'; styleMyElement(player['buttonWidesize'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#C05800', fontSize: '12px', textShadow: '1px 1px 2px #CCCCCC', cursor: 'pointer'}); player['playerPanel'].appendChild(player['buttonWidesize']); /* Panel Fullsize Button */ player['buttonFullsize'] = createMyElement('div', option['fullsize'] ? '-' : '+', 'click', 'fullsize', ''); player['buttonFullsize'].title = '{Fullsize: click to enter player fullsize or return to normal size}'; styleMyElement(player['buttonFullsize'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#C05800', fontSize: '12px', textShadow: '1px 1px 2px #CCCCCC', cursor: 'pointer'}); player['playerPanel'].appendChild(player['buttonFullsize']); /* The Content */ player['contentWidth'] = player['playerWidth']; player['contentHeight'] = player['playerHeight'] - player['panelHeight'] - player['panelPadding'] * 2; player['playerContent'] = createMyElement('div', '', '', '', ''); styleMyElement(player['playerContent'], {width: player['contentWidth'] + 'px', height: player['contentHeight'] + 'px', position: 'relative', color: '#AD0000', backgroundColor: '#000000', fontSize: '14px', fontWeight: 'bold', textAlign: 'center'}); player['playerWindow'].appendChild(player['playerContent']); /* The Video Thumbnail */ if (player['videoThumb']) { player['contentImage'] = createMyElement('img', player['videoThumb'], 'click', 'play', ''); player['contentImage'].title = '{Click to start video playback}'; styleMyElement(player['contentImage'], {maxWidth: '100%', maxHeight: '100%', position: 'absolute', top: '0px', left: '0px', right: '0px', bottom: '0px', margin: 'auto', border: '0px', cursor: 'pointer'}); player['contentImage'].addEventListener('load', function() { if (this.width/this.height >= player['contentWidth']/player['contentHeight']) { this.style.width = '100%'; } else { this.style.height = '100%'; } }); } /* Resize My Player */ if (option['widesize']) resizeMyPlayer('widesize'); if (option['fullsize']) resizeMyPlayer('fullsize'); /* Play My Video */ playMyVideo(option['autoplay']); } promise = browser.storage.local.get(Object.keys(option)); promise.then(onGot, onGot); } function playDASHwithHTML5() { console.log(player['videoList']); if (player['videoPlay'].indexOf('MP4') != -1) { player['contentVideo'] = createMyElement('video', player['videoList'][player['videoPlay'].replace(/MP4/, 'Video MP4')], '', '', ''); if (player['videoList']['High Bitrate Audio Opus']) { player['contentAudio'] = createMyElement('video', player['videoList']['High Bitrate Audio Opus'], '', '', ''); } else if (player['videoList']['Medium Bitrate Audio Opus']) { player['contentAudio'] = createMyElement('video', player['videoList']['Medium Bitrate Audio Opus'], '', '', ''); } else { player['contentAudio'] = createMyElement('video', player['videoList']['Medium Bitrate Audio MP4'], '', '', ''); } } else { player['contentVideo'] = createMyElement('video', player['videoList'][player['videoPlay'].replace(/WebM/, 'Video WebM')], '', '', ''); if (player['videoList']['High Bitrate Audio Opus']) { player['contentAudio'] = createMyElement('video', player['videoList']['High Bitrate Audio Opus'], '', '', ''); } else if (player['videoList']['Medium Bitrate Audio Opus']) { player['contentAudio'] = createMyElement('video', player['videoList']['Medium Bitrate Audio Opus'], '', '', ''); } else { player['contentAudio'] = createMyElement('video', player['videoList']['Medium Bitrate Audio WebM'], '', '', ''); } } player['contentAudio'].pause(); player['contentVideo'].addEventListener('play', function() { player['contentAudio'].play(); }, false); player['contentVideo'].addEventListener('pause', function() { player['contentAudio'].pause(); }, false); player['contentVideo'].addEventListener('ended', function() { player['contentVideo'].pause(); player['contentAudio'].pause(); }, false); player['contentVideo'].addEventListener('timeupdate', function() { if (player['contentAudio'].paused && !player['contentVideo'].paused) { player['contentAudio'].play(); } if (Math.abs(player['contentVideo'].currentTime - player['contentAudio'].currentTime) >= 0.30) { player['contentAudio'].currentTime = player['contentVideo'].currentTime; } }, false); styleMyElement(player['contentAudio'], {display: 'none'}); player['contentVideo'].appendChild(player['contentAudio']); } function playMyVideo(play) { player['isPlaying'] = play; modifyMyElement(player['playerContent'], 'div', '', true); if (play) { if (player['videoList'][player['videoPlay']] == 'DASH') playDASHwithHTML5(); else player['contentVideo'] = createMyElement('video', player['videoList'][player['videoPlay']], '', '', ''); player['contentVideo'].width = player['contentWidth']; player['contentVideo'].height = player['contentHeight']; player['contentVideo'].poster = player['videoThumb']; styleMyElement(player['contentVideo'], {position: 'relative', width: player['contentWidth'] + 'px', height: player['contentHeight'] + 'px'}); player['playerContent'].appendChild(player['contentVideo']); } else { if (player['contentImage']) player['playerContent'].appendChild(player['contentImage']); else showMyMessage('!thumb'); } } function resizeMyPlayer(size) { switch (size) { case 'widesize': if (option['widesize']) { if (player['buttonWidesize']) modifyMyElement(player['buttonWidesize'], 'div', '<', false); var playerWidth = player['playerWideWidth']; var playerHeight= player['playerWideHeight']; var sidebarMargin = player['sidebarMarginWide']; } else { if (player['buttonWidesize']) modifyMyElement(player['buttonWidesize'], 'div', '>', false); var playerWidth = player['playerWidth']; var playerHeight= player['playerHeight']; var sidebarMargin = player['sidebarMarginNormal']; } break; case 'fullsize': if (option['fullsize']) { var playerPosition = 'fixed'; var playerWidth = page.win.innerWidth || page.doc.documentElement.clientWidth; var playerHeight = page.win.innerHeight || page.doc.documentElement.clientHeight; var playerIndex = '9999999999'; if (!player['isFullsize']) { styleMyElement(player['buttonWidesize'], {display: 'none'}); modifyMyElement(player['buttonFullsize'], 'div', '-', false); page.body.appendChild(player['playerWindow']); styleMyElement(page.body, {overflow: 'hidden'}); styleMyElement(page.body.parentNode, {overflow: 'hidden'}); if (!player['resizeListener']) player['resizeListener'] = function() {resizeMyPlayer('fullsize')}; page.win.addEventListener('resize', player['resizeListener'], false); player['isFullsize'] = true; if (player['isPlaying']) { if (player['contentVideo'] && player['contentVideo'].paused) player['contentVideo'].play(); } } } else { var playerPosition = 'relative'; var playerWidth = (option['widesize']) ? player['playerWideWidth'] : player['playerWidth']; var playerHeight = (option['widesize']) ? player['playerWideHeight'] : player['playerHeight']; var playerIndex = 'auto'; styleMyElement(player['buttonWidesize'], {display: 'inline'}); modifyMyElement(player['buttonFullsize'], 'div', '+', false); player['playerSocket'].appendChild(player['playerWindow']); styleMyElement(page.body, {overflow: 'auto'}); styleMyElement(page.body.parentNode, {overflow: 'auto'}); page.win.removeEventListener('resize', player['resizeListener'], false); player['isFullsize'] = false; if (player['isPlaying']) { if (player['contentVideo'] && player['contentVideo'].paused) player['contentVideo'].play(); } } break; } /* Resize The Player */ if (size == 'widesize') { if (player['sidebarWindow']) styleMyElement(player['sidebarWindow'], {marginTop: sidebarMargin + 'px'}); styleMyElement(player['playerWindow'], {width: playerWidth + 'px', height: playerHeight + 'px'}); } else styleMyElement(player['playerWindow'], {position: playerPosition, top: '0px', left: '0px', width: playerWidth + 'px', height: playerHeight + 'px', zIndex: playerIndex}); /* Resize The Panel */ var panelWidth = playerWidth - player['panelPadding'] * 2; styleMyElement(player['playerPanel'], {width: panelWidth + 'px'}); /* Resize The Content */ player['contentWidth'] = playerWidth; player['contentHeight'] = playerHeight - player['panelHeight'] - player['panelPadding'] * 2; styleMyElement(player['playerContent'], {width: player['contentWidth'] + 'px', height: player['contentHeight'] + 'px'}); if (player['isPlaying']) { player['contentVideo'].width = player['contentWidth']; player['contentVideo'].height = player['contentHeight']; styleMyElement(player['contentVideo'], {width: player['contentWidth'] + 'px', height: player['contentHeight'] + 'px'}); } } function cleanMyContent(content, unesc) { var myNewContent = content; if (unesc) myNewContent = unescape(myNewContent); myNewContent = myNewContent.replace(/\\u0025/g,'%'); myNewContent = myNewContent.replace(/\\u0026/g,'&'); myNewContent = myNewContent.replace(/\\/g,''); myNewContent = myNewContent.replace(/\n/g,''); return myNewContent; } function getMyContent(url, pattern, clean) { var myPageContent, myVideosParse, myVideosContent; var getMethod = (url != page.url) ? 'XHR' : 'DOM'; if (!sources[url]) sources[url] = {}; if (getMethod == 'DOM') { if (!sources[url]['DOM']) { sources[url]['DOM'] = getMyElement('', 'html', 'tag', '', 0, true); if (!sources[url]['DOM']) sources[url]['DOM'] = getMyElement('', 'body', '', '', -1, true); } myPageContent = sources[url]['DOM']; if (clean) myPageContent = cleanMyContent(myPageContent, true); myVideosParse = myPageContent.match(pattern); myVideosContent = (myVideosParse) ? myVideosParse[1] : null; if (myVideosContent) return myVideosContent; else getMethod = 'XHR'; } if (getMethod == 'XHR') { if (!sources[url]['XHR']) sources[url]['XHR'] = {}; if ((pattern == 'XML' && !sources[url]['XHR']['XML']) || (pattern != 'XML' && !sources[url]['XHR']['TEXT'])) { var xmlHTTP = new XMLHttpRequest(); xmlHTTP.open('GET', url, false); xmlHTTP.send(); if (pattern == 'XML') sources[url]['XHR']['XML'] = xmlHTTP.responseXML; else sources[url]['XHR']['TEXT'] = xmlHTTP.responseText; } if (pattern == 'XML') { myVideosContent = sources[url]['XHR']['XML']; } else if (pattern == 'TEXT') { myVideosContent = sources[url]['XHR']['TEXT']; } else { myPageContent = sources[url]['XHR']['TEXT']; if (clean) myPageContent = cleanMyContent(myPageContent, true); myVideosParse = myPageContent.match(pattern); myVideosContent = (myVideosParse) ? myVideosParse[1] : null; } return myVideosContent; } } function setMyOptions(key, value) { var pair = {}; pair[key] = value; browser.storage.local.set(pair); } function showMyMessage(cause, content) { var myScriptLogo = createMyElement('div', userscript, '', '', ''); styleMyElement(myScriptLogo, {margin: '0px auto', padding: '10px', color: '#666666', fontSize: '24px', textAlign: 'center', textShadow: '#FFFFFF -1px -1px 2px'}); var myScriptMess = createMyElement('div', '', '', '', ''); styleMyElement(myScriptMess, {border: '1px solid #F4F4F4', margin: '5px auto 5px auto', padding: '10px', backgroundColor: '#FFFFFF', color: '#AD0000', textAlign: 'center'}); if (cause == '!player') { var myScriptAlert = createMyElement('div', '', '', '', ''); styleMyElement(myScriptAlert, {position: 'absolute', top: '30%', left: '35%', border: '1px solid #F4F4F4', borderRadius: '3px', padding: '10px', backgroundColor: '#FFFFFF', fontSize: '14px', textAlign: 'center', zIndex: '99999'}); myScriptAlert.appendChild(myScriptLogo); var myNoPlayerMess = 'Couldn\'t get the player element. Please report it here.'; modifyMyElement(myScriptMess, 'div', myNoPlayerMess, false); myScriptAlert.appendChild(myScriptMess); var myScriptAlertButton = createMyElement('div', 'OK', 'click', 'close', myScriptAlert); styleMyElement(myScriptAlertButton, {width: '100px', border: '3px solid #EEEEEE', borderRadius: '5px', margin: '0px auto', backgroundColor: '#EEEEEE', color: '#666666', fontSize: '18px', textAlign: 'center', textShadow: '#FFFFFF -1px -1px 2px', cursor: 'pointer'}); myScriptAlert.appendChild(myScriptAlertButton); page.body.appendChild(myScriptAlert); } else if (cause == '!thumb') { var myNoThumbMess = '

Couldn\'t get the thumbnail for this video. Please report it here.'; modifyMyElement(player['playerContent'], 'div', myNoThumbMess, false); } else { myPlayerWindow.appendChild(myScriptLogo); if (cause == '!content') { var myNoContentMess = 'Couldn\'t get the videos content. Please report it here.'; modifyMyElement(myScriptMess, 'div', myNoContentMess, false); } else if (cause == '!videos') { var myNoVideosMess = 'Couldn\'t get any video. Please report it here.'; modifyMyElement(myScriptMess, 'div', myNoVideosMess, false); } else if (cause == '!support') { var myNoSupportMess = 'This video uses the RTMP protocol and is not supported.'; modifyMyElement(myScriptMess, 'div', myNoSupportMess, false); } else if (cause == 'embed') { var myEmbedMess = 'This is an embedded video. You can watch it here.'; modifyMyElement(myScriptMess, 'div', myEmbedMess, false); } else if (cause == 'other') { modifyMyElement(myScriptMess, 'div', content, false); } myPlayerWindow.appendChild(myScriptMess); } } // =====YouTube===== // /* Redirect Categories */ if (page.url.indexOf('gaming.youtube.com') != -1) { page.win.location.href = page.url.replace('gaming', 'www'); } /* Video Availability */ var ytVideoUnavailable = getMyElement('', 'div', 'id', 'player-unavailable', -1, false); if (ytVideoUnavailable) { if (ytVideoUnavailable.className.indexOf('hid') == -1) { var ytAgeGateContent = getMyElement('', 'div', 'id', 'watch7-player-age-gate-content', -1, true); if (!ytAgeGateContent) return; else { if(ytAgeGateContent.indexOf('feature=private_video') != -1) return; } } } /* Decrypt Signature */ var ytScriptSrc; function ytDecryptSignature(s) {return null;} function ytDecryptFunction() { var ytSignFuncName, ytSignFuncBody, ytSwapFuncName, ytSwapFuncBody, ytFuncMatch; ytScriptSrc = ytScriptSrc.replace(/(\r\n|\n|\r)/gm, ''); ytSignFuncName = ytScriptSrc.match(/"signature"\s*,\s*([^\)]*?)\(/); ytSignFuncName = (ytSignFuncName) ? ytSignFuncName[1] : null; if (ytSignFuncName) { ytFuncMatch = ytSignFuncName.replace(/\$/, '\\$') + '\\s*=\\s*function\\s*' + '\\s*\\(\\w+\\)\\s*\\{(.*?)\\}'; ytSignFuncBody = ytScriptSrc.match(ytFuncMatch); ytSignFuncBody = (ytSignFuncBody) ? ytSignFuncBody[1] : null; if (ytSignFuncBody) { ytSwapFuncName = ytSignFuncBody.match(/((\$|_|\w)+)\.(\$|_|\w)+\(\w,[0-9]+\)/); ytSwapFuncName = (ytSwapFuncName) ? ytSwapFuncName[1] : null; if (ytSwapFuncName) { ytFuncMatch = 'var\\s+' + ytSwapFuncName.replace(/\$/, '\\$') + '=\\s*\\{(.*?)\\};'; ytSwapFuncBody = ytScriptSrc.match(ytFuncMatch); ytSwapFuncBody = (ytSwapFuncBody) ? ytSwapFuncBody[1] : null; } if (ytSwapFuncBody) ytSignFuncBody = 'var ' + ytSwapFuncName + '={' + ytSwapFuncBody + '};' + ytSignFuncBody; ytSignFuncBody = 'try {' + ytSignFuncBody + '} catch(e) {return null}'; ytDecryptSignature = new Function('a', ytSignFuncBody); } } } /* Player Size */ var ytSidebarMarginNormal = 382; var ytSidebarWindow = getMyElement('', 'div', 'id', 'watch7-sidebar', -1, false); if (ytSidebarWindow) { var ytSidebarWindowStyle = ytSidebarWindow.currentStyle || window.getComputedStyle(ytSidebarWindow); if (ytSidebarWindowStyle) ytSidebarMarginNormal = -12 + parseInt(ytSidebarWindowStyle.marginTop.replace('px', '')); styleMyElement(ytSidebarWindow, {marginTop: ytSidebarMarginNormal + 'px'}); } var ytPlayerWidth, ytPlayerHeight; var ytPlayerWideWidth, ytPlayerWideHeight; var ytSidebarMarginWide; var ytScreenWidth, ytScreenHeight; function ytSizes() { ytScreenWidth = page.win.innerWidth || page.doc.documentElement.clientWidth; ytScreenHeight = page.win.innerHeight || page.doc.documentElement.clientHeight; if (ytScreenWidth >= 1720 && ytScreenHeight >= 980) { ytPlayerWidth = 1280; ytPlayerHeight = 742; ytPlayerWideWidth = 1706; ytPlayerWideHeight = 982; } else if (ytScreenWidth >= 1294 && ytScreenHeight >= 630) { ytPlayerWidth = 854; ytPlayerHeight = 502; ytPlayerWideWidth = 1280; ytPlayerWideHeight = 742; } else { ytPlayerWidth = 640; ytPlayerHeight = 382; ytPlayerWideWidth = 1066; ytPlayerWideHeight = 622; } ytSidebarMarginWide = ytPlayerHeight + ytSidebarMarginNormal; } /* Get Player Window */ var ytPlayerWindow = document.querySelector("#player"); if (!ytPlayerWindow) { showMyMessage('!player'); } else { /* Get Video Thumbnail */ var ytVideoThumb = getMyContent(page.url, 'link\\s+itemprop="thumbnailUrl"\\s+href="(.*?)"', false); if (!ytVideoThumb) ytVideoThumb = getMyContent(page.url, 'meta\\s+property="og:image"\\s+content="(.*?)"', false); if (!ytVideoThumb) { var ytVideoID = page.url.match(/(\?|&)v=(.*?)(&|$)/); if (ytVideoID) ytVideoThumb = 'https://img.youtube.com/vi/' + ytVideoID[2] + '/0.jpg'; } /* Get Video Title */ var ytVideoTitle = getMyContent(page.url, 'meta\\s+itemprop="name"\\s+content="(.*?)"', false); if (!ytVideoTitle) ytVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false); if (!ytVideoTitle) ytVideoTitle = page.doc.title; if (ytVideoTitle) { ytVideoTitle = ytVideoTitle.replace(/"/g, '\'').replace(/"/g, '\'').replace(/"/g, '\''); ytVideoTitle = ytVideoTitle.replace(/'/g, '\'').replace(/'/g, '\''); ytVideoTitle = ytVideoTitle.replace(/&/g, 'and').replace(/&/g, 'and'); ytVideoTitle = ytVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-'); ytVideoTitle = ytVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, ''); ytVideoTitle = ytVideoTitle.replace(/^YouTube\s-\s/, ''); } /* Get Videos Content */ var ytVideosEncodedFmts, ytVideosAdaptiveFmts, ytVideosContent, ytHLSVideos, ytHLSContent; ytVideosEncodedFmts = getMyContent(page.url, '"url_encoded_fmt_stream_map":\\s*"(.*?)"', false); if (!ytVideosEncodedFmts) ytVideosEncodedFmts = getMyContent(page.url, '\\\\"url_encoded_fmt_stream_map\\\\":\\s*\\\\"(.*?)\\\\"', false); ytVideosAdaptiveFmts = getMyContent(page.url, '"adaptive_fmts":\\s*"(.*?)"', false); if (!ytVideosAdaptiveFmts) ytVideosAdaptiveFmts = getMyContent(page.url, '\\\\"adaptive_fmts\\\\":\\s*\\\\"(.*?)\\\\"', false); if (ytVideosEncodedFmts) { ytVideosContent = ytVideosEncodedFmts; } else { ytHLSVideos = getMyContent(page.url, '"hlsvp":\\s*"(.*?)"', false); if (!ytHLSVideos) ytHLSVideos = getMyContent(page.url, '\\\\"hlsvp\\\\":\\s*\\\\"(.*?)\\\\"', false); if (ytHLSVideos) { ytHLSVideos = cleanMyContent(ytHLSVideos, false); if (ytHLSVideos.indexOf('keepalive/yes/') != -1) ytHLSVideos = ytHLSVideos.replace('keepalive/yes/', ''); } else { var ytVideoID = page.url.match(/(\?|&)v=(.*?)(&|$)/); ytVideoID = (ytVideoID) ? ytVideoID[2] : null; if (ytVideoID) { var ytVideoSts = getMyContent(page.url.replace(/watch.*?v=/, 'embed/').replace(/&.*$/, ''), '"sts"\\s*:\\s*(\\d+)', false); var ytVideosInfoURL = page.win.location.protocol + '//' + page.win.location.hostname + '/get_video_info?video_id=' + ytVideoID + '&eurl=https://youtube.googleapis.com/v/' + ytVideoID + '&sts=' + ytVideoSts; var ytVideosInfo = getMyContent(ytVideosInfoURL, 'TEXT', false); if (ytVideosInfo) { ytVideosEncodedFmts = ytVideosInfo.match(/url_encoded_fmt_stream_map=(.*?)&/); ytVideosEncodedFmts = (ytVideosEncodedFmts) ? ytVideosEncodedFmts[1] : null; if (ytVideosEncodedFmts) { ytVideosEncodedFmts = cleanMyContent(ytVideosEncodedFmts, true); ytVideosContent = ytVideosEncodedFmts; } if (!ytVideosAdaptiveFmts) { ytVideosAdaptiveFmts = ytVideosInfo.match(/adaptive_fmts=(.*?)&/); ytVideosAdaptiveFmts = (ytVideosAdaptiveFmts) ? ytVideosAdaptiveFmts[1] : null; if (ytVideosAdaptiveFmts) ytVideosAdaptiveFmts = cleanMyContent(ytVideosAdaptiveFmts, true); } } } } } if (ytVideosAdaptiveFmts && !ytHLSVideos) { if (ytVideosContent) ytVideosContent += ',' + ytVideosAdaptiveFmts; else ytVideosContent = ytVideosAdaptiveFmts; } /* Get Sizes */ ytSizes(); function removeElements (selector) { document.querySelectorAll(selector).forEach(function (element) { element.remove(); }); } /* Remove Player Window */ removeElements("#placeholder-player"); /* Remove Sidebar Ads */ removeElements("#watch7-sidebar-ads"); /* Playlist */ var ytPlaylist = document.querySelector("#player-playlist"); if (ytPlaylist) { styleMyElement(ytPlaylist, {marginLeft: '-' + ytPlayerWidth + 'px'}); var ytPlaceholderPlaylist = document.querySelector("#placeholder-playlist"); if (ytPlaceholderPlaylist) ytPlaceholderPlaylist.appendChild(ytPlaylist); } /* My Player Window */ var myPlayerWindow = createMyElement('div', '', '', '', ''); styleMyElement(myPlayerWindow, {position: 'relative', width: ytPlayerWidth + 'px', height: ytPlayerHeight + 'px', backgroundColor: '#FFFFFF'}); modifyMyElement(ytPlayerWindow, 'div', '', false, true); ytPlayerWindow.appendChild(myPlayerWindow); /* Update Sizes */ page.win.addEventListener('resize', function() { ytSizes(); player['playerWidth'] = ytPlayerWidth; player['playerHeight'] = ytPlayerHeight; player['playerWideWidth'] = ytPlayerWideWidth; player['playerWideHeight'] = ytPlayerWideHeight; player['sidebarMarginWide'] = ytSidebarMarginWide; resizeMyPlayer('widesize'); if (ytPlaylist) styleMyElement(ytPlaylist, {marginLeft: '-' + ytPlayerWidth + 'px'}); }, false); /* Create Player */ var ytDefaultVideo = 'Low Definition MP4'; function ytPlayer() { player = { 'playerSocket': ytPlayerWindow, 'playerWindow': myPlayerWindow, 'videoList': ytVideoList, 'videoPlay': ytDefaultVideo, 'videoThumb': ytVideoThumb, 'videoTitle': ytVideoTitle, 'playerWidth': ytPlayerWidth, 'playerHeight': ytPlayerHeight, 'playerWideWidth': ytPlayerWideWidth, 'playerWideHeight': ytPlayerWideHeight, 'sidebarWindow': ytSidebarWindow, 'sidebarMarginNormal': ytSidebarMarginNormal, 'sidebarMarginWide': ytSidebarMarginWide }; option['definitions'] = ['Ultra High Definition', 'Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition']; option['containers'] = ['MP4', 'WebM', 'FLV', '3GP', 'Any']; createMyPlayer(); } /* Parse Videos */ function ytVideos() { var ytVideoFormats = { '5': 'Very Low Definition FLV', '17': 'Very Low Definition 3GP', '18': 'Low Definition MP4', '22': 'High Definition MP4', '34': 'Low Definition FLV', '35': 'Standard Definition FLV', '36': 'Low Definition 3GP', '37': 'Full High Definition MP4', '38': 'Ultra High Definition MP4', '43': 'Low Definition WebM', '44': 'Standard Definition WebM', '45': 'High Definition WebM', '46': 'Full High Definition WebM', '82': 'Low Definition 3D MP4', '83': 'Standard Definition 3D MP4', '84': 'High Definition 3D MP4', '85': 'Full High Definition 3D MP4', '100': 'Low Definition 3D WebM', '101': 'Standard Definition 3D WebM', '102': 'High Definition 3D WebM', '135': 'Standard Definition Video MP4', '136': 'High Definition Video MP4', '137': 'Full High Definition Video MP4', '138': 'Ultra High Definition Video MP4', '139': 'Low Bitrate Audio MP4', '140': 'Medium Bitrate Audio MP4', '141': 'High Bitrate Audio MP4', '171': 'Medium Bitrate Audio WebM', '172': 'High Bitrate Audio WebM', '244': 'Standard Definition Video WebM', '247': 'High Definition Video WebM', '248': 'Full High Definition Video WebM', '249': 'Low Bitrate Audio Opus', '250': 'Medium Bitrate Audio Opus', '251': 'High Bitrate Audio Opus', '266': 'Ultra High Definition Video MP4', '272': 'Ultra High Definition Video WebM', '298': 'High Definition Video MP4', '299': 'Full High Definition Video MP4', '302': 'High Definition Video WebM', '303': 'Full High Definition Video WebM', '313': 'Ultra High Definition Video WebM' }; var ytVideoFound = false; var ytVideos = ytVideosContent.split(','); var ytVideoParse, ytVideoCodeParse, ytVideoCode, myVideoCode, ytVideo; for (var i = 0; i < ytVideos.length; i++) { if (!ytVideos[i].match(/^url/)) { ytVideoParse = ytVideos[i].match(/(.*)(url=.*$)/); if (ytVideoParse) ytVideos[i] = ytVideoParse[2] + '&' + ytVideoParse[1]; } ytVideoCodeParse = ytVideos[i].match(/itag=(\d{1,3})/); ytVideoCode = (ytVideoCodeParse) ? ytVideoCodeParse[1] : null; if (ytVideoCode) { myVideoCode = ytVideoFormats[ytVideoCode]; if (myVideoCode) { ytVideo = cleanMyContent(ytVideos[i], true); ytVideo = ytVideo.replace(/url=/, '').replace(/&$/, ''); if (ytVideo.match(/itag=/) && ytVideo.match(/itag=/g).length > 1) { if (ytVideo.match(/itag=\d{1,3}&/)) ytVideo = ytVideo.replace(/itag=\d{1,3}&/, ''); else if (ytVideo.match(/&itag=\d{1,3}/)) ytVideo = ytVideo.replace(/&itag=\d{1,3}/, ''); } if (ytVideo.match(/clen=/) && ytVideo.match(/clen=/g).length > 1) { if (ytVideo.match(/clen=\d+&/)) ytVideo = ytVideo.replace(/clen=\d+&/, ''); else if (ytVideo.match(/&clen=\d+/)) ytVideo = ytVideo.replace(/&clen=\d+/, ''); } if (ytVideo.match(/lmt=/) && ytVideo.match(/lmt=/g).length > 1) { if (ytVideo.match(/lmt=\d+&/)) ytVideo = ytVideo.replace(/lmt=\d+&/, ''); else if (ytVideo.match(/&lmt=\d+/)) ytVideo = ytVideo.replace(/&lmt=\d+/, ''); } if (ytVideo.match(/type=(video|audio).*?&/)) ytVideo = ytVideo.replace(/type=(video|audio).*?&/, ''); else ytVideo = ytVideo.replace(/&type=(video|audio).*$/, ''); if (ytVideo.match(/xtags=[^%=]*&/)) ytVideo = ytVideo.replace(/xtags=[^%=]*?&/, ''); else if (ytVideo.match(/&xtags=[^%=]*$/)) ytVideo = ytVideo.replace(/&xtags=[^%=]*$/, ''); if (ytVideo.match(/&sig=/)) ytVideo = ytVideo.replace(/&sig=/, '&signature='); else if (ytVideo.match(/&s=/)) { var ytSig = ytVideo.match(/&s=(.*?)(&|$)/); if (ytSig) { var s = ytSig[1]; s = ytDecryptSignature(s); if (s) ytVideo = ytVideo.replace(/&s=.*?(&|$)/, '&signature=' + s + '$1'); else ytVideo = ''; } else ytVideo = ''; } ytVideo = cleanMyContent(ytVideo, true); if (ytVideo.indexOf('ratebypass') == -1) ytVideo += '&ratebypass=yes'; if (ytVideo && ytVideo.indexOf('http') == 0) { if (!ytVideoFound) ytVideoFound = true; ytVideoList[myVideoCode] = ytVideo; } } } } if (ytVideoFound) { /* DASH */ if (!ytVideoList['Standard Definition MP4'] && ytVideoList['Standard Definition Video MP4']) ytVideoList['Standard Definition MP4'] = 'DASH'; if (!ytVideoList['High Definition MP4'] && ytVideoList['High Definition Video MP4']) ytVideoList['High Definition MP4'] = 'DASH'; if (!ytVideoList['Full High Definition MP4'] && ytVideoList['Full High Definition Video MP4']) ytVideoList['Full High Definition MP4'] = 'DASH'; if (!ytVideoList['Ultra High Definition MP4'] && ytVideoList['Ultra High Definition Video MP4']) ytVideoList['Ultra High Definition MP4'] = 'DASH'; if (!ytVideoList['Standard Definition WebM'] && ytVideoList['Standard Definition Video WebM']) ytVideoList['Standard Definition WebM'] = 'DASH'; if (!ytVideoList['High Definition WebM'] && ytVideoList['High Definition Video WebM']) ytVideoList['High Definition WebM'] = 'DASH'; if (!ytVideoList['Full High Definition WebM'] && ytVideoList['Full High Definition Video WebM']) ytVideoList['Full High Definition WebM'] = 'DASH'; if (!ytVideoList['Ultra High Definition WebM'] && ytVideoList['Ultra High Definition Video WebM']) ytVideoList['Ultra High Definition WebM'] = 'DASH'; /* DVL */ ytVideoList['Direct Video Link'] = page.url; ytPlayer(); } else { if (ytVideosContent.indexOf('conn=rtmp') != -1) showMyMessage('!support'); else showMyMessage('!videos'); } } /* Parse HLS */ function ytHLS() { var ytHLSFormats = { '92': 'Very Low Definition MP4', '93': 'Low Definition MP4', '94': 'Standard Definition MP4', '95': 'High Definition MP4', '96': 'Full High Definition MP4' }; ytVideoList["Any Definition MP4"] = ytHLSVideos; if (ytHLSContent) { var ytHLSVideo, ytVideoCodeParse, ytVideoCode, myVideoCode; var ytHLSMatcher = new RegExp('(http.*?m3u8)', 'g'); ytHLSVideos = ytHLSContent.match(ytHLSMatcher); if (ytHLSVideos) { for (var i = 0; i < ytHLSVideos.length; i++) { ytHLSVideo = ytHLSVideos[i]; ytVideoCodeParse = ytHLSVideo.match(/\/itag\/(\d{1,3})\//); ytVideoCode = (ytVideoCodeParse) ? ytVideoCodeParse[1] : null; if (ytVideoCode) { myVideoCode = ytHLSFormats[ytVideoCode]; if (myVideoCode && ytHLSVideo) { ytVideoList[myVideoCode] = ytHLSVideo; } } } } } /* DVL */ ytVideoList['Direct Video Link'] = page.url; ytVideoTitle = null; ytDefaultVideo = 'Any Definition MP4'; ytPlayer(); } /* Get Videos */ var ytVideoList = {}; if (ytVideosContent) { if (ytVideosContent.match(/&s=/) || ytVideosContent.match(/,s=/) || ytVideosContent.match(/u0026s=/)) { var ytScriptURL = getMyContent(page.url, '"js":\\s*"(.*?)"', true); if (!ytScriptURL) ytScriptURL = getMyContent(page.url.replace(/watch.*?v=/, 'embed/').replace(/&.*$/, ''), '"js":\\s*"(.*?)"', true); if (ytScriptURL) { ytScriptURL = page.win.location.protocol + ytScriptURL; try { ytScriptSrc = getMyContent(ytScriptURL, 'TEXT', false); if (ytScriptSrc) ytDecryptFunction(); ytVideos(); } catch(e) { try { var oReq = new XMLHttpRequest(); oReq.open("GET", ytScriptURL); oReq.onload = function(response) { if (response.readyState === 4 && response.status === 200 && response.responseText) { ytScriptSrc = response.responseText; ytDecryptFunction(); ytVideos(); } else { showMyMessage('other', 'Couldn\'t get the signature content. Please report it here.'); } }; oReq.onerror = function() { showMyMessage('other', 'Couldn\'t make the request. Make sure your browser user scripts extension supports cross-domain requests.'); }; oReq.send(); } catch(e) { showMyMessage('other', 'Couldn\'t make the request. Make sure your browser user scripts extension supports cross-domain requests.'); } } } else { showMyMessage('other', 'Couldn\'t get the signature link. Please report it here.'); } } else { ytVideos(); } } else { if (ytHLSVideos) { try { ytHLSContent = getMyContent(ytHLSVideos, 'TEXT', false); ytHLS(); } catch(e) { try { var oReq = new XMLHttpRequest(); oReq.open("GET", ytHLSVideos); oReq.onload = function(response) { if (response.readyState === 4 && response.status === 200 && response.responseText) { ytHLSContent = response.responseText; } ytHLS(); }; oReq.onerror = function() { ytHLS(); }; oReq.send(); } catch(e) { ytHLS(); } } } else { showMyMessage('!content'); } } } })();