NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name DailyMotion Download // @id DailyMotionDownload // @version 1.4 // @description Adds download link for DailyMotion Videos // @namespace https://openuserjs.org/users/volkan-k/scripts // @match *://www.dailymotion.com/* // @grant unsafeWindow // @grant GM_download // @grant GM_openInTab // @grant GM_xmlhttpRequest // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/filesize/3.6.1/filesize.min.js // @require-test https://paste.ee/r/XNUsq/0 // @connect cloudflare.com // @connect dailymotion.com // @license MIT // ==/UserScript== var usw = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window; // Firefox, Opera<15 var RANDOM = Math.floor(Math.random() * 1234567890); var DIALOG_ID = 'dmotion_download' + RANDOM; var dl_handle, download_div, progressbar, progressLabel; var is_downloading = false; var timer1, timer2, timer3; if (typeof GM_openInTab === "undefined") { GM_openInTab = window.open; } if (typeof GM_info.downloadMode === "undefined") { GM_info.downloadMode = "browser"; } function find(selector) { return document.querySelector(selector); } function debugLog(message) { console.log("USER-SCRIPT DAILYMOTION-DOWNLOAD : " + message); } function convert_relative_urls(css, base) { return css.replace(/url\s*\(\s*['"]{1}([^'"]+)['"]{1}\s*\)/ig, function(match, capture) { if (/^(https?|file|ftps?|mailto|javascript|data:image\/[^;]{2,9};):/i.test(capture)) { return match; // url is already absolute } return "url('" + new URL(capture, base).href + "')"; }); } function addStyle_external(css_link, once, xhr) { id = btoa(css_link).replace(/[+\/=]+/ig, ""); if (typeof xhr === "boolean" && xhr === true) { // xhr it GM_xmlhttpRequest({ method: "GET", url: css_link, onerror: function(oEvent) { alert("Error " + oEvent.target.status + " occurred while receiving the document."); }, onload: function(response) { if (response.readyState !== 4 || response.status !== 200) return; addGlobalStyle(convert_relative_urls(response.responseText, css_link), once, id) } }); return; } var head, style; head = document.getElementsByTagName('head')[0]; if (!head) { return; } if (once && $("link[href='" + css_link + "']").length > 0) { return; } style = document.createElement('link'); style.setAttribute("rel", "stylesheet"); style.setAttribute("type", "text/css"); style.setAttribute("id", id); style.setAttribute("href", css_link); head.appendChild(style); } function addGlobalStyle(css, once, id) { var head, style; head = document.getElementsByTagName('head')[0]; if (!head) { return; } if (once && document.getElementById(id)) { return; } style = document.createElement('style'); style.setAttribute("type", "text/css"); if (typeof id === "string") { style.setAttribute("id", id); } style.innerHTML = css; head.appendChild(style); } function downloadVideoNatively(e) { if ($.inArray(GM_info.downloadMode, ["native", "browser"]) === -1) { return; } var elem = e.currentTarget; e.returnValue = false; if (e.preventDefault) { e.preventDefault(); } var link = $(elem).find('a').attr('href'); var name = $(elem).find('a').attr('title') + '.mp4'; name = name.replace(/[\\<>:"\/|?*]*/g, ""); if (link && name) { if (typeof GM_download !== 'undefined') { if (GM_info.downloadMode === "native") { open_download_dialog(); if (is_downloading === false) { dl_handle = GM_download({ url: link, name: name, onerror: gm_dl_error, onload: gm_dl_load, onprogress: gm_dl_progress, ontimeout: gm_dl_timeout }); dl_handle.my_filename = name; is_downloading = true; } } else { GM_download(link, name); // browser handles } debugLog("Downloading should start now.. File Name = " + name + " ; File URL = " + link); } else { GM_openInTab(link); debugLog("Download link should be opened in new tab now.. File Name = " + name + " ; File URL = " + link); } } return false; } function open_download_dialog() { if ($('#' + DIALOG_ID).length > 0 && $('#' + DIALOG_ID).dialog('isOpen')) { $('#' + DIALOG_ID).dialog('close').remove(); } var dialogButtons = [{ text: "Cancel Download", click: cancel_download }]; addStyle_external('https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css', true, true); addGlobalStyle("#progressbar" + RANDOM + "{margin-top: 20px;}.progress-label" + RANDOM + "{font-weight: bold; text-shadow: 1px 1px 0 #fff;}", true, 'gm_added_style_dmotiondl'); download_div = $("<div title='File Download' id='" + DIALOG_ID + "'></div>").dialog({ resizable: false, closeText: "Continue in background", buttons: dialogButtons, close: function(event, ui) { $(this).dialog('destroy').remove(); } }); $("button.ui-dialog-titlebar-close").tooltip(); $('#' + DIALOG_ID).append('<div class="progress-label' + RANDOM + '">Starting download...</div>' + '<div id="extrainfo' + RANDOM + '"></div>' + '<div id="progressbar' + RANDOM + '"></div>'); /* $("#master" + RANDOM).slider({ value: volume, create: function() { $("#handle" + RANDOM).text(' = %' + $(this).slider("value")); }, slide: function(event, ui) { $("#handle" + RANDOM).text(' = %' + ui.value); SetVolume(ui.value); } });*/ progressbar = $("#progressbar" + RANDOM); progressLabel = $(".progress-label" + RANDOM); progressbar.progressbar({ value: false, change: function() { progressLabel.text("Current Progress: " + progressbar.progressbar("value") + "%"); }, complete: function() { progressLabel.text("Complete!"); change_button_to_close(); } }); } function gm_dl_progress(response) { if ($('#' + DIALOG_ID).length === 0 || !$('#' + DIALOG_ID).dialog('isOpen')) { return; } if (response.lengthComputable === false) { return; } //console.log(response); var fs_html = "<p>File size: " + filesize(response.total) + "</p>"; if (typeof dl_handle.my_filename === "string") { fs_html += "<p>File name: " + dl_handle.my_filename + "</p>"; } if ($("#extrainfo" + RANDOM).html() !== fs_html) { $("#extrainfo" + RANDOM).html(fs_html); } var val = Math.floor(response.done / response.total * 100); progressbar.progressbar("value", val); } function gm_dl_load(response) { is_downloading = false; if ($('#' + DIALOG_ID).length === 0 || !$('#' + DIALOG_ID).dialog('isOpen')) { return; } progressbar.progressbar("value", 100); change_button_to_close(); } function gm_dl_timeout(response) { is_downloading = false; if ($('#' + DIALOG_ID).length === 0 || !$('#' + DIALOG_ID).dialog('isOpen')) { return; } progressbar.progressbar("value", false); progressLabel.text("Download time-out!"); change_button_to_close(); } function gm_dl_error(response) { is_downloading = false; if ($('#' + DIALOG_ID).length === 0 || !$('#' + DIALOG_ID).dialog('isOpen')) { return; } progressbar.progressbar("value", false); progressLabel.text("Download error!"); change_button_to_close(); } function change_button_to_close() { download_div.dialog("option", "buttons", [{ text: "Close", click: function(event, ui) { $(this).dialog('close'); } }]); download_div.dialog("option", "closeText", "Close"); } function cancel_download() { is_downloading = false; dl_handle.abort(); if ($('#' + DIALOG_ID).length === 0 || !$('#' + DIALOG_ID).dialog('isOpen')) { return; } download_div.dialog("close"); } function are_we_on_video_page(){ var url = window.location.href; var video_id = getDailyMotionId(url); if (video_id === null){ return false; } // else return true; } function setup(new_data) { if (((usw && '__PLAYER_CONFIG__' in usw) || (typeof new_data === "object")) && find("p[class^='QueueInfoContent__stats']")) { try { if (typeof new_data === "object" && new_data !== null ) { debugLog("DEBUG: using XHR metadata"); var video_id=new_data.id; var video_title=new_data.title; var video_qualities=new_data.qualities; } else if (typeof usw.__PLAYER_CONFIG__.metadata === "object" && usw.__PLAYER_CONFIG__.metadata !== null) { debugLog("DEBUG: using __PLAYER_CONFIG__ metadata"); var video_id = usw.__PLAYER_CONFIG__.metadata.id; var video_title = usw.__PLAYER_CONFIG__.metadata.title; var video_qualities = usw.__PLAYER_CONFIG__.metadata.qualities; } else if (are_we_on_video_page()===true) { debugLog("DEBUG: can't find any metadata, but we are on video page, running XHR"); clearTimeout(timer3); timer3=setTimeout(xhr_video_info,1000); return; } else { debugLog("NOTICE: couldnt find any metadata nor video ID. Exiting.."); return; } var container = document.createElement("div"); container.setAttribute('class', 'dailymotion_downloader'); var url; for (var resolution in video_qualities) { video_qualities[resolution].some(function(element) { if (element.type === "video/mp4") { url = element.url; //console.log(resolution); console.log(url); // for debug var div = document.createElement("div"); div.style.display = "inline-block"; var span = document.createElement("span"); //span.innerHTML = resolution; span.style.display = "inline-block"; span.style.width = "130px"; div.appendChild(span); var a = document.createElement("a"); a.title = video_title; a.href = url; a.textContent = 'Download ' + resolution + 'p'; span.appendChild(a); container.appendChild(div); // listen to click event div.addEventListener('click', downloadVideoNatively, false); } }); } clearTimeout(timer1); // we created the button, stop setup() loop clearInterval(timer2); // we will setInterval, clear previous one first. timer2 = setInterval(function() { var node = find("p[class^='QueueInfoContent__stats']"); if (node === null) { return; } var oldButton = find('.dailymotion_downloader'); if (oldButton !== null && oldButton.innerHTML === container.innerHTML) { return; } //oldButton && console.log(oldButton.outerHTML); // for debugging only. //console.log(button.outerHTML); // for debugging only. oldButton && oldButton.remove(); if (find('.dailymotion_downloader') === null) { node.parentNode.insertBefore(container, node); } }, 500); } catch (error) { // log the error console.error("[DailyMotion Download] Error retrieving video meta data:", error); } } else { // try again later timer1 = setTimeout(setup, 500,(typeof new_data === "object" ? new_data : false)); } } function getDailyMotionId(url) { //return url.substring(url.lastIndexOf('/') + 1); // old buggy method. var m = url.match(/^.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/); if (m !== null) { if (m[4] !== undefined) { return m[4]; } return m[2]; } return null; } function xhr_video_info() { var url = window.location.href; var video_id = getDailyMotionId(url); if (video_id === null){ debugLog("DEBUG: xhr_video_info() couldnt find video id"); return ; } GM_xmlhttpRequest({ method: "GET", url: "https://www.dailymotion.com/player/metadata/video/" + video_id, onerror: function(oEvent) { alert("Error " + oEvent.target.status + " occurred while receiving the document."); }, onload: function(response) { if (response.readyState !== 4 || response.status !== 200) return; setup(JSON.parse(response.responseText)); } }); } // start looking for video player setup(); // f*cking dailymotion does not update window.__PLAYER_CONFIG__ object. $(window).bind('popstate', function() { debugLog("DEBUG: popstate event: calling xhr_video_info()"); xhr_video_info(); }); var window_history_pushState = window.history.pushState; window.history.pushState = function() { window_history_pushState.apply(window.history, arguments); debugLog("DEBUG: pushstate event: calling xhr_video_info()"); xhr_video_info(); } //console.log(container);