本帖最后由 堂哥哥好帅 于 2023-6-27 09:11 编辑
脚本的起源是为了给家里的老人下载戏剧,因为本地戏剧比较小众几乎找了许多视频平台最后发现只有西瓜平台有,所以想下载西瓜平台的视频下来。试着自己开发工具发现不是很好用,尝试了几种方案,而且看了许多的工具也都不好用,最后选择进行方案三脚本关联第三方下载程序进行开发。
代码:
[JavaScript] 纯文本查看 复制代码 // ==UserScript==
// [url=home.php?mod=space&uid=170990]@name[/url] 西瓜堂Down-西瓜视频下载工具
// [url=home.php?mod=space&uid=467642]@namespace[/url] Violentmonkey Scripts
// [url=home.php?mod=space&uid=195849]@match[/url] https://www.ixigua.com/*
// [url=home.php?mod=space&uid=609072]@grant[/url] none
// [url=home.php?mod=space&uid=1248337]@version[/url] 1.0
// @license MIT
// [url=home.php?mod=space&uid=686208]@AuThor[/url] 堂哥哥
// @description 2023/06/23 15:06
// ==/UserScript==
let isInit = false;
// 初始化
function HTMLInit() {
// 如果是西瓜视频则加载迅雷的js
var g = document.createElement('script');
var s = document.getElementsByTagName('script')[0];
g.setAttribute("src", "https://open.thunderurl.com/thunder-link.js");
s.parentNode.insertBefore(g, s);
isInit = true;
}
var _wr = function(type) {
var orig = history[type];
return function() {
var rv = orig.apply(this, arguments);
var e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
return rv;
};
};
history.pushState = _wr('pushState');
// 监听事件history的pushState事件
window.addEventListener('pushState', function(e) {
console.log("网页地址存在变换")
xiguaChange();
});
// 迅雷下载
function xunleiDownload(url,name){
thunderLink.newTask({
tasks: [{
name: name, // 指定下载文件名(含扩展名)。【若不填此项,将根据下载 URL 自动获取文件名】
url: url // 指定下载地址【必填项】
}]
});
}
// json转换
var safetyParse = (str) => {
try {
return JSON.parse(str);
} catch (error) {
return null;
}
};
var getXiGuaVideoInfo = async () => {
let data = null;
try {
console.log("window.location.href is "+ window.location.href);
const res = await fetch(window.location.href);
const str = await res.text();
// console.log("res is --------------",res)
// console.log(str)
data = safetyParse(
str.match(/window?._SSR_HYDRATED_DATA=([\d\D]+?)<\/script>/)[1].replaceAll("undefined", "null")
);
// console.log("data is -----------",data)
// console.log(data)
}catch (e){
console.log(e)
}
finally {
return data;
}
}
async function handlerVideoData(){
let downloadOption = [];
let ids = [];
const data = await getXiGuaVideoInfo();
if(data == null){
return null;
}
const videoResource = data?.anyVideo?.gidInformation?.packerData?.video?.videoResource || data?.anyVideo?.gidInformation?.packerData?.videoResource;
const videoList = Object.values(videoResource?.normal?.video_list ?? {}).sort(
(a, b) => b?.vheight - a?.vheight
);
for (var index in videoList) {
let video = videoList[index];
// console.log("video is -------------");
// console.log(video);
let url = atob(video.main_url);
// // 添加点击事件
let fileName = data.anyVideo.gidInformation.packerData.video.title + "." + video.vtype;
// 为了保留文件名称,后续下载重新处理
fileName = fileName.replaceAll(" ", "-空格-");
let id = "downBtId"+video.definition;
let downloadData = {id: id,mainUrl: url,videoResolution: video.definition,fileName: fileName}
ids.push(id);
downloadOption.push(downloadData)
}
let returnData = {
downloadOption,
ids
}
return returnData;
}
async function createXiguaVideoDownload(){
let downloadOption = [];
let handlerDatas = await handlerVideoData();
if(handlerDatas == null){
return null;
}
downloadOption = handlerDatas.downloadOption;
let rightGrid = document.querySelector('.xg-right-grid');
let playControl = rightGrid.querySelector('div:nth-of-type(2)');
let control = playControl.cloneNode(true);
let isDownControleId = null;
try {
isDownControleId = playControl.querySelector('#downControleId');
}catch (e){
console.log(e)
}
let entry= control.querySelector('.xgplayer-control-item__entry');
entry.innerHTML = '<div class="xgpcPlayer_textEntry"><span id="downControleId">下载</span></div>';
let popover = control.querySelector('.xgplayer-control-item__popover');
let downloadList = '<ul>';
downloadOption.forEach(function(item){
try {
downloadList += `<li tabindex="0" role="menuitemradio" aria-checked="false" id="${item.id}" data-downUrl=${item.mainUrl} data-downTitle=${item.fileName}>${item.videoResolution}</li>`;
}catch (e){
console.log("没有数据");
}
})
downloadList += '</ul>';
popover.innerHTML = downloadList;
try {
if(isDownControleId != null){
playControl.replaceWith(control);
}else {
playControl.before(control);
}
}catch (e){
console.log(e)
}
let divDom = document.createElement('div');
divDom.style="width: 80px; height: 140px;position:absolute;bottom:40px;left:20px;z-index:-1";
control.appendChild(divDom);
control.onmouseover=function(){
popover.style.display='block';
}
control.onmouseout=function(){
popover.style.display='none';
}
return handlerDatas.ids;
}
/*--Class--*/
class BaseClass{
createElement(dom,domId){
var rootElement = document.body;
var newElement = document.createElement(dom);
newElement.id = domId;
var newElementHtmlContent = document.createTextNode('');
rootElement.appendChild(newElement);
newElement.appendChild(newElementHtmlContent);
}
static getElement(css){
return new Promise((resolve,reject)=>{
let num = 0;
let timer = setInterval(function(){
num++
let dom = document.querySelector(css);
if(dom){
clearInterval(timer);
resolve(dom);
}else{
if(num==20){clearInterval(timer);resolve(false);}
}
},300)
})
}
}
async function loadingXigua() {
try{
var _this = this;
if (document.location.toString() !== "https://www.ixigua.com/") {
if(!isInit){
HTMLInit();
}
window.addEventListener('load',function(){
getControls();
})
}
}catch (e){
console.log(e);
}
}
async function xiguaChange() {
var _this = this;
if (document.location.toString() !== "https://www.ixigua.com/") {
if(!isInit){
HTMLInit();
}
getControls();
}
}
async function getControls(){
let videoDom = await BaseClass.getElement('video');
if(!videoDom){
console.log('没有找到DOM');return;
}
let ids = await createXiguaVideoDownload();
ids.forEach(function(id){
let jsId = "#" + id;
document.querySelector(jsId).addEventListener('click',function(eve){
console.log("-------------------有点击下载-------------------");
console.log(eve.target.dataset);
let fileName = eve.target.dataset.downtitle;
fileName = fileName.replaceAll("-空格-", " ");
// 转换回原来的文件名称
xunleiDownload(eve.target.dataset.downurl,fileName);
})
})
}
loadingXigua();
本脚本运行前提是安装第三方程序——迅雷,然后需要下载油猴,然后打开https://greasyfork.org/zh-CN/scripts/469452-%E8%A5%BF%E7%93%9C%E5%A0%82down-%E8%A5%BF%E7%93%9C%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD%E5%B7%A5%E5%85%B7,点击进行安装脚本。
最后说一下跟一般下载脚本的区别,一边脚本和插件都是直接调用浏览器下载,下载文件越大越容易卡浏览器,比如下载5-10G的视频文件,浏览器的下载容易卡爆,调用第三方API调用第三方程序则可以减轻浏览器的负担,而且浏览器多文件同时下载会出现一些问题,比如某些文件速度慢很多和文件没速度,暂停后未必能继续下载。第三方下载程序有非常完善的多任务下载,暂停和继续任务,最大能支持好几十个文件同时下载,多个下载链接合并成一个合集等等,浏览器下载就未必能实现该功能。
最后演示一下
|