// ==UserScript== // @name Panopto-Video-DL // @namespace https://github.com/Panopto-Video-DL // @description Download video from Panopto! // @icon https://www.panopto.com/wp-content/themes/panopto/library/images/favicons/favicon-96x96.png // @author Panopto-Video-DL // @version 3.1.0 // @copyright 2021, Panopto-Video-DL // @license MIT // @homepageURL https://github.com/Panopto-Video-DL // @match https://*.panopto.com/Panopto/Pages/Viewer.aspx?*id=* // @match https://*.panopto.eu/Panopto/Pages/Viewer.aspx?*id=* // @connect panopto.com // @connect panopto.eu // @grant GM_setClipboard // @grant GM_openInTab // @noframes // @downloadURL none // ==/UserScript== (function(panopto) { 'use strict'; const url = new URL(location.href) const lesson_id = url.searchParams.get('id'); if (!lesson_id) { alert('Failed to get Lesson ID') return; } request({ url: location.origin + '/Panopto/Pages/Viewer/DeliveryInfo.aspx', method: 'POST', headers: { 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, data: 'deliveryId=' + lesson_id + '&isEmbed=true&responseType=json', success: function(response) { const data = JSON.parse(response); let stream = undefined; try { stream = data.Delivery.PodcastStreams[0].StreamUrl; } catch (error) { console.error(error) alert('Error: StreamURL not found'); return; } const element = document.createElement('a'); element.id = 'downloadTabHeader'; element.classList = 'event-tab-header'; element.style = 'position:absolute;bottom:40px;padding:5px 10px;text-decoration:none;cursor:pointer;'; element.innerHTML = 'Download
'; element.addEventListener('click', event => { if (stream.endsWith('master.m3u8')) { if (localStorage.getItem('popup-viewed') != 'true') { const div = document.createElement('div'); div.id = 'Panopto-Video-DL'; div.innerHTML += ''; div.innerHTML += 'To download the video follow these steps:
'; document.querySelector('body').appendChild(div); } if (typeof GM_setClipboard !== 'undefined') { GM_setClipboard(stream, 'text'); alert('Link copied!') } else { navigator.clipboard.writeText(stream).then(() => { alert('Link copied!') }).catch(e => { const div = document.createElement('div'); div.innerHTML += ''; div.innerHTML += '
Copy it manually:
'; div.querySelector('input').value = stream; if (document.querySelector('#Panopto-Video-DL')) document.querySelector('#Panopto-Video-DL').append(div) else { div.id = 'Panopto-Video-DL'; div.querySelector('style').innerText += '#Panopto-Video-DL{position:fixed;top:10%;left:50%;width:80%;padding:3em 3em 1em;background-color:#2d3436;transform:translateX(-50%);z-index:999999}'; document.querySelector('body').appendChild(div); } }); } } else { if (typeof GM_openInTab !== 'undefined') { GM_openInTab(stream, false); } else { window.open(stream); } } }); document.querySelector('#eventTabControl').appendChild(element); }, error: function(response) { console.error(response) alert('Failed to get DeliveryInfo of lesson'); } }); // Functions function request(options) { const onreadystatechange = function() { if (this.readyState === 4 && (this.status >= 200 && this.status <= 299)) options.success(this.responseText); else if (this.readyState === 4) options.error(this.responseText); }; if (typeof GM_xmlhttpRequest != 'undefined') { options.onload = onreadystatechange; GM_xmlhttpRequest(options); } else { const xhttp = new XMLHttpRequest(); xhttp.open(options.method || 'GET', options.url); if (options.headers) { for (let key in options.headers) xhttp.setRequestHeader(key, options.headers[key]) } xhttp.onreadystatechange = onreadystatechange; xhttp.send(options.data); } } })(Panopto);