您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Intercepts Rork snapshot data and allows exporting code which stupidly is a premium feature of rork
// ==UserScript== // @name Rork Downloader // @namespace https://github.com/deeeeone/userscripts // @version 1.4 // @description Intercepts Rork snapshot data and allows exporting code which stupidly is a premium feature of rork // @author Custom // @match https://rork.com/p/* // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; // we need jszip to zip everything up const jszipScript = document.createElement('script'); jszipScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.0/jszip.min.js'; document.head.appendChild(jszipScript); let latestSnapshot = null; let latestSnapshotId = null; function saveSnapshotToDB(id, snapshotObj) { return new Promise((resolve, reject) => { const req = indexedDB.open('rorkSnapshots', 1); req.onupgradeneeded = function(e) { const db = e.target.result; if (!db.objectStoreNames.contains('snapshots')) { db.createObjectStore('snapshots'); } }; req.onsuccess = function(e) { const db = e.target.result; const tx = db.transaction('snapshots', 'readwrite'); const store = tx.objectStore('snapshots'); store.put(snapshotObj, id); tx.oncomplete = () => resolve(); tx.onerror = () => reject(tx.error); }; req.onerror = () => reject(req.error); }); } function getSnapshotFromDB(id) { return new Promise((resolve, reject) => { const req = indexedDB.open('rorkSnapshots', 1); req.onupgradeneeded = function(e) { e.target.result.createObjectStore('snapshots'); }; req.onsuccess = function(e) { const db = e.target.result; const tx = db.transaction('snapshots', 'readonly'); const store = tx.objectStore('snapshots'); const getReq = store.get(id); getReq.onsuccess = () => resolve(getReq.result); getReq.onerror = () => reject(getReq.error); }; req.onerror = () => reject(req.error); }); } // cheating but idc it works const originalFetch = window.fetch; window.fetch = async function(...args) { const response = await originalFetch.apply(this, args); const url = args[0]; if (typeof url === 'string' && url.includes('/trpc/projects.fetchSnapshot')) { response.clone().json().then(data => { try { const json = data.result?.data?.json; if (!json) return; latestSnapshot = json.snapshot; latestSnapshotId = json.snapshotId; // Save to IndexedDB saveSnapshotToDB(latestSnapshotId, latestSnapshot).catch(console.error); console.log('Rork snapshot stored:', latestSnapshotId); } catch (err) { console.error('Error parsing Rork snapshot:', err); } }).catch(console.error); } return response; }; // build zip file from the snapshot object function buildZip(snapshotObj) { const zip = new JSZip(); for (const [path, entry] of Object.entries(snapshotObj)) { if (entry.type === 'folder') { zip.folder(path); } else if (entry.type === 'file') { zip.file(path, entry.contents); } } return zip; } // download zip file async function downloadSnapshot(id, snapshotObj) { if (!window.JSZip) { alert('JSZip not loaded yet. Please try again in a moment.'); return; } const zip = buildZip(snapshotObj); const blob = await zip.generateAsync({ type: 'blob' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `rork_snapshot_${id}.zip`; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); } // add into header function insertButton() { const header = document.querySelector('header'); if (!header) return; if (document.getElementById('rork-download-btn')) return; const btn = document.createElement('button'); btn.id = 'rork-download-btn'; btn.innerText = 'Download Snapshot'; btn.style.backgroundColor = '#10B981'; // emerald cause why not btn.style.color = '#FFFFFF'; btn.style.border = 'none'; btn.style.padding = '8px 12px'; btn.style.marginLeft = '10px'; btn.style.borderRadius = '4px'; btn.style.fontSize = '14px'; btn.style.cursor = 'pointer'; btn.addEventListener('click', async () => { if (latestSnapshot && latestSnapshotId) { await downloadSnapshot(latestSnapshotId, latestSnapshot); } else if (latestSnapshotId) { // load everything from indexeddb const stored = await getSnapshotFromDB(latestSnapshotId); if (stored) { await downloadSnapshot(latestSnapshotId, stored); } else { alert('Snapshot data not available yet. Please wait for the project to load.'); } } else { alert('No snapshot captured yet. Please wait for the project to load.'); } }); header.appendChild(btn); } // wait WAIT WAITTT function waitForHeader() { const header = document.querySelector('header'); if (header) { insertButton(); } else { requestAnimationFrame(waitForHeader); } } document.addEventListener('DOMContentLoaded', () => { waitForHeader(); }); })();