// ==UserScript==
// @license MIT
// @name 下载USDZ
// @namespace http://tampermonkey.net/
// @version 1.0.3
// @description 用来获取苹果官网的USDZ链接,方便下载
// @author BigJie
// @match https://www.apple.com/*
// @match https://www.apple.com.cn/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @downloadURL https://update.greasyfork.icu/scripts/468466/%E4%B8%8B%E8%BD%BDUSDZ.user.js
// @updateURL https://update.greasyfork.icu/scripts/468466/%E4%B8%8B%E8%BD%BDUSDZ.meta.js
// ==/UserScript==
(function() {
'use strict';
const links = [];
function getLinks() {
// 匹配glb和usdz格式的链接
const regex = /(?:href|src)="([^"]+\.(?:glb|usdz))"/gi;
const elements = document.getElementsByTagName("*");
for (let i = 0; i < elements.length; i++) {
const matches = elements[i].outerHTML.match(regex);
if (matches) {
for (let j = 0; j < matches.length; j++) {
const link = matches[j].replace(/^(?:href|src)="(.+)"$/i, "$1");
if (links.indexOf(link) === -1) {
links.push(link);
}
}
}
}
}
function createButton() {
const button = document.createElement("button");
button.id = "file-download-button";
button.textContent = "下载3D文件";
document.body.appendChild(button);
button.onclick = function() {
const linkList = links.map(link => {
return `
`;
}).join("");
const popup = document.createElement("div");
popup.id = "file-download-list";
popup.innerHTML = ``;
document.body.appendChild(popup);
// 计算按钮和弹出窗口的位置
const rect = button.getBoundingClientRect();
const popupTop = rect.bottom + 10;
const popupLeft = rect.left;
popup.style.top = `${popupTop}px`;
popup.style.left = `${popupLeft}px`;
// 添加关闭按钮
const closeBtn = document.createElement("button");
closeBtn.id = "closePopupButton";
closeBtn.textContent = "关闭";
closeBtn.onclick = function() {
document.body.removeChild(popup);
};
popup.appendChild(closeBtn);
// 添加下载按钮
const downloadButtons = document.querySelectorAll(".download-button");
downloadButtons.forEach(button => {
button.onclick = function(event) {
const link = event.target.dataset.link;
GM_download({
url: link,
name: link.split("/").pop(),
onerror: function(error) {
console.error(error);
}
});
};
});
};
}
function addStyles() {
GM_addStyle(`
#file-download-button {
position: fixed;
top: 20px;
left: 20px;
background-color: black;
color: white;
border: none;
border-radius: 5px;
padding: 10px;
font-size: 16px;
cursor: pointer;
z-index: 9999;
}
#file-download-list {
position: fixed;
background-color: white;
border: 1px solid black;
padding: 10px;
z-index: 9998;
overflow-y: auto;
max-height: 50vh;
}
.popup-content {
display: flex;
flex-direction: column;
}
.link-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.download-button {
background-color: black;
color: white;
border: none;
border-radius: 5px;
padding: 5px 10px;
cursor: pointer;
}
#closePopupButton {
background-color: black;
color: white;
border: none;
border-radius: 5px;
padding: 5px 10px;
cursor: pointer;
margin-top: 10px;
}
`);
}
function parseGLB(url) {
GM_xmlhttpRequest({
method: "GET",
url: url,
responseType: "arraybuffer",
onload: function(response) {
const gltf = JSON.parse(new TextDecoder().decode(response.response));
glbBuffer = response.response.slice(gltf.buffers[0].byteOffset, gltf.buffers[0].byteOffset + gltf.buffers[0].byteLength);
const blob = new Blob([glbBuffer], { type: "model/gltf-binary" });
const objectUrl = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = objectUrl;
link.download = url.split("/").pop();
link.click();
},
onerror: function(error) {
console.error(error);
}
});
}
function observeXHR() {
const open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
this.addEventListener("load", function() {
if (url.endsWith(".glb")) {
if (this.responseType === "arraybuffer") {
const blob = new Blob([this.response], { type: "model/gltf-binary" });
const objectUrl = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = objectUrl;
link.download = url.split("/").pop();
link.click();
} else {
parseGLB(url);
}
}
});
open.apply(this, arguments);
};
}
function main() {
getLinks();
createButton();
addStyles();
observeXHR();
}
main();
})();