| <!DOCTYPE html> |
| <html lang="zh-CN"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>URL to Google Drive Saver</title> |
| <style> |
| :root { --primary: #4F46E5; --bg: #F3F4F6; --card: #ffffff; } |
| body { font-family: 'Segoe UI', sans-serif; background: var(--bg); display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; } |
| .container { background: var(--card); padding: 2rem; border-radius: 1rem; box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1); width: 90%; max-width: 500px; } |
| h1 { color: #111827; margin-bottom: 0.5rem; font-size: 1.5rem; text-align: center; } |
| p { color: #6B7280; text-align: center; margin-bottom: 1.5rem; font-size: 0.9rem; } |
| .input-group { margin-bottom: 1rem; } |
| input { width: 100%; padding: 0.75rem; border: 1px solid #D1D5DB; border-radius: 0.5rem; box-sizing: border-box; outline: none; transition: border 0.2s; } |
| input:focus { border-color: var(--primary); ring: 2px var(--primary); } |
| button { width: 100%; background: var(--primary); color: white; padding: 0.75rem; border: none; border-radius: 0.5rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s; } |
| button:hover { opacity: 0.9; } |
| button:disabled { background: #9CA3AF; cursor: not-allowed; } |
| #status { margin-top: 1rem; padding: 1rem; border-radius: 0.5rem; background: #F9FAFB; border: 1px solid #E5E7EB; white-space: pre-wrap; word-break: break-all; font-size: 0.9rem; display: none; } |
| .success { border-left: 4px solid #10B981 !important; color: #065F46; } |
| .error { border-left: 4px solid #EF4444 !important; color: #7F1D1D; } |
| .spinner { display: inline-block; width: 1rem; height: 1rem; border: 2px solid #fff; border-radius: 50%; border-top-color: transparent; animation: spin 1s linear infinite; margin-right: 0.5rem; vertical-align: middle; } |
| @keyframes spin { to { transform: rotate(360deg); } } |
| </style> |
| </head> |
| <body> |
|
|
| <div class="container"> |
| <h1>☁️ URL 转存助手</h1> |
| <p>直接将网络文件保存到您的 Google Drive</p> |
| |
| <div class="input-group"> |
| <input type="url" id="fileUrl" placeholder="在此粘贴文件 URL (例如 .mp4, .zip)" required> |
| </div> |
| |
| <button id="submitBtn" onclick="startUpload()"> |
| <span id="btnText">开始转存</span> |
| </button> |
| |
| <div id="status"></div> |
| </div> |
|
|
| |
| <script type="module"> |
| import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"; |
| |
| |
| |
| const HF_SPACE_ID = "iyougame/url2drive"; |
| |
| window.startUpload = async function() { |
| const urlInput = document.getElementById('fileUrl'); |
| const btn = document.getElementById('submitBtn'); |
| const btnText = document.getElementById('btnText'); |
| const statusDiv = document.getElementById('status'); |
| |
| const url = urlInput.value.trim(); |
| if (!url) { |
| alert("请输入有效的文件 URL"); |
| return; |
| } |
| |
| |
| btn.disabled = true; |
| btnText.innerHTML = '<span class="spinner"></span> 处理中...'; |
| statusDiv.style.display = 'block'; |
| statusDiv.className = ''; |
| statusDiv.innerHTML = "⏳ 正在连接后端服务器..."; |
| |
| try { |
| |
| const client = await Client.connect(HF_SPACE_ID); |
| |
| statusDiv.innerHTML = "🚀 已连接! 正在下载并上传..."; |
| |
| |
| const result = await client.predict("/save_to_drive", { |
| file_url: url |
| }); |
| |
| |
| const responseText = result.data[0]; |
| |
| |
| let htmlContent = responseText |
| .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') |
| .replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" target="_blank" style="color:blue;text-decoration:underline;">$1</a>') |
| .replace(/\n/g, '<br>'); |
| |
| statusDiv.innerHTML = htmlContent; |
| |
| if (responseText.includes("❌")) { |
| statusDiv.classList.add("error"); |
| btnText.innerText = "重试"; |
| } else { |
| statusDiv.classList.add("success"); |
| btnText.innerText = "再次转存"; |
| urlInput.value = ""; |
| } |
| |
| } catch (error) { |
| console.error(error); |
| statusDiv.classList.add("error"); |
| statusDiv.innerHTML = `❌ **系统错误**: ${error.message}<br>请检查 Space 是否正在运行。`; |
| btnText.innerText = "重试"; |
| } finally { |
| btn.disabled = false; |
| } |
| } |
| </script> |
|
|
| </body> |
| </html> |
|
|