您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
No more buffering!!
// ==UserScript== // @name Canvas Media Gallery Grabber // @namespace http://tampermonkey.net/ // @version 0.2 // @description No more buffering!! // @author Pikachu // @include * // @run-at document-start // @grant GM_xmlhttpRequest // ==/UserScript== // DISCLAIMER: This tool is intended only for accessing authorized content offline. // You shall NOT use this tool to COPY or REDISTRIBUTE any of the downloaded content. // Have fun reading the docs ~ // https://developer.kaltura.com/api-docs/Deliver-and-Distribute-Media/playManifest-streaming-api.html // Update Log: // 0.2: Now support downloading video media with kaltura player from any page on Canvas besides playlists. // File names are finally, finally sorted out. Now downloaded file names will be automatically set to video name! function addbutton(video_title, dl_link) { // Add button var link_div = document.createElement("div"); link_div.innerHTML = '<a href="' + dl_link + '" download="' + video_title + '.mp4">Download ' + video_title + '</a>'; link_div.setAttribute("id", "download_button_container"); document.getElementById("mediaContainer").parentNode.insertBefore(link_div, document.getElementById("mediaContainer")); //GM_addStyle('.download_button_container { position: absolute; top: 0px; right: 0px }') } function getassets(video_title, video_src, entry_id) { // Retrive ks var ks = video_src.substr(video_src.indexOf("&ks=")+4, video_src.indexOf("&", video_src.indexOf("&ks=")+4)-video_src.indexOf("&ks=")-4); //console.log("ks=",ks); var video_info = { "p":null, "sp":null, "entryId":entry_id, "flavorIds":null, "format":null, "protocol":null }; for (var key in video_info) { var value = video_src.substr( video_src.indexOf(key+"/")+key.length+1, video_src.indexOf("/", video_src.indexOf(key+"/")+key.length+1)-video_src.indexOf(key+"/")-key.length-1 ); video_info[key] = value; }; // Modify format video_info["format"] = "url" //console.log(video_info["entryId"]); // Get the best resolution var assets = GM_xmlhttpRequest({ method: "GET", url: "https://www.kaltura.com/api_v3/service/flavorasset/action/getWebPlayableByEntryId?entryId="+video_info["entryId"]+"&ks="+ks, onerror: function(r) { console.log("Error when retriving assets.", "Detail: \n", r.responseText); }, onload: function(r) { var assets = parseassets(r.responseText); var chosenasset = null; var chosenassetprop = 0; // Choose the asset with highest resolution for (var entryid in assets) { if (assets[entryid]["width"] * assets[entryid]["height"] > chosenassetprop) { chosenasset = entryid; chosenassetprop = assets[entryid]["width"] * assets[entryid]["height"]; } } video_info["flavorIds"] = assets[chosenasset]["id"]; var dl_link = "https://cdnapisec.kaltura.com/p/"+video_info["p"]+"/sp/"+video_info["sp"]+"/playManifest"; for (key in video_info) { if (key != "p" && key != "sp") { dl_link += "/"+key+"/"+video_info[key]; } } // Append header dl_link += "/name/" + encodeURI(video_title) + ".mp4?ks=" + ks; getdlink(video_title, dl_link); } }) } function getdlink(video_title, req) { var dlink = GM_xmlhttpRequest({ method: "GET", url: req, onerror: function(r) { console.log("Error when retriving download link.", "Detail: \n", r.responseText); }, onreadystatechange: function(r) { if (this.readyState == this.HEADERS_RECEIVED) { var final_dlink = req; if (r.status == 200) { final_dlink = r.finalUrl; } // Stop loading before it actually loads dlink.abort(); // Black magic. Somehow we cannot have any non alphanumeric characters besides underscore in the name, or we will get 404. final_dlink = final_dlink.replace("/name/a.mp4", "/name/" + video_title.replace(/[\W_]+/g, "_") + ".mp4"); console.log(video_title + ": " + final_dlink,"\n"); addbutton(video_title, final_dlink); } } }) } function parseassets(assets) { //console.log(assets); var parser = new DOMParser(); var xmlassets = parser.parseFromString(assets, "text/xml"); var asset = {}; for (var i=0; i<xmlassets.getElementsByTagName("item").length; i++) { var item_dict = {} var item = xmlassets.getElementsByTagName("item")[i] for (var ii=0; ii<item.getElementsByTagName("*").length; ii++) { var tag = item.getElementsByTagName("*")[ii]; item_dict[tag.tagName] = tag.textContent; } if ("id" in item_dict) { asset[item_dict["id"]] = item_dict; } } return asset; } (function() { 'use strict'; // Your code here... var video_src = null; var entry_id = null; var video_title = null; if (window.top != window.self) { var checkExist = setInterval(function() { if (document.getElementById("kplayer_ifp") != null) { var player_if = document.getElementById("kplayer_ifp").contentWindow; if (player_if.document.getElementById("pid_kplayer") != null) { video_src = player_if.document.getElementById("pid_kplayer").getAttribute("src"); entry_id = player_if.document.getElementById("pid_kplayer").getAttribute("kentryid"); if (video_src != null && entry_id != null) { //console.log("src=" + video_src); clearInterval(checkExist); if (player_if.document.querySelectorAll('[data-plugin-name="titleLabel"]').length > 0) { video_title = player_if.document.querySelectorAll('[data-plugin-name="titleLabel"]')[0].getAttribute("title").trim(); } else if (document.getElementsByClassName("entryTitle").length > 0) { video_title = document.getElementsByClassName("entryTitle")[0].textContent.trim(); } getassets(video_title, video_src, entry_id); } } } else { //console.log("still waiting...") } }, 1000); // check every 1000ms } else { // Not running in iframe } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址