Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
@@ -1,64 +1,140 @@
|
|
1 |
-
import os, shutil, zipfile,
|
|
|
|
|
2 |
from huggingface_hub import HfApi, login, upload_folder
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
TOKEN = os.environ.get("HF_TOKEN")
|
9 |
|
|
|
|
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
def run_backup():
|
12 |
-
|
13 |
-
shutil.rmtree(EXTRACT_DIR, ignore_errors=True)
|
14 |
-
os.makedirs(DOWNLOAD_DIR, exist_ok=True)
|
15 |
-
os.makedirs(EXTRACT_DIR, exist_ok=True)
|
16 |
-
|
17 |
-
gdown.download_folder(
|
18 |
-
url=FOLDER_URL,
|
19 |
-
output=DOWNLOAD_DIR,
|
20 |
-
use_cookies=False,
|
21 |
-
quiet=False
|
22 |
-
)
|
23 |
-
|
24 |
-
for root, _, files in os.walk(DOWNLOAD_DIR):
|
25 |
-
for f in files:
|
26 |
-
if f.endswith(".zip"):
|
27 |
-
zp = os.path.join(root, f)
|
28 |
-
with zipfile.ZipFile(zp) as z:
|
29 |
-
z.extractall(EXTRACT_DIR)
|
30 |
-
|
31 |
-
# Fix folder name typo
|
32 |
-
bad = os.path.join(EXTRACT_DIR, "world_nither")
|
33 |
-
good = os.path.join(EXTRACT_DIR, "world_nether")
|
34 |
-
if os.path.exists(bad) and not os.path.exists(good):
|
35 |
-
os.rename(bad, good)
|
36 |
-
|
37 |
-
login(token=TOKEN)
|
38 |
-
api = HfApi()
|
39 |
try:
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
)
|
63 |
-
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os, shutil, zipfile, threading, time
|
2 |
+
from flask import Flask, request, render_template_string
|
3 |
+
import gdown
|
4 |
from huggingface_hub import HfApi, login, upload_folder
|
5 |
|
6 |
+
# Environment variables (set them in HF Spaces settings)
|
7 |
+
FOLDER_URL = os.getenv("FOLDER_URL")
|
8 |
+
REPO_ID = os.getenv("REPO_ID")
|
9 |
+
TOKEN = os.getenv("HF_TOKEN")
|
|
|
10 |
|
11 |
+
DOWNLOAD_DIR = "/tmp/backups"
|
12 |
+
EXTRACT_DIR = "/tmp/extracted_backups"
|
13 |
|
14 |
+
# Global state
|
15 |
+
last_backup_time = "Never"
|
16 |
+
schedule_interval = 0
|
17 |
+
|
18 |
+
app = Flask(__name__)
|
19 |
+
|
20 |
+
# Backup logic
|
21 |
def run_backup():
|
22 |
+
global last_backup_time
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
try:
|
24 |
+
shutil.rmtree(DOWNLOAD_DIR, ignore_errors=True)
|
25 |
+
shutil.rmtree(EXTRACT_DIR, ignore_errors=True)
|
26 |
+
os.makedirs(DOWNLOAD_DIR, exist_ok=True)
|
27 |
+
os.makedirs(EXTRACT_DIR, exist_ok=True)
|
28 |
+
|
29 |
+
gdown.download_folder(
|
30 |
+
url=FOLDER_URL,
|
31 |
+
output=DOWNLOAD_DIR,
|
32 |
+
use_cookies=False,
|
33 |
+
quiet=False
|
34 |
+
)
|
35 |
+
|
36 |
+
for root, _, files in os.walk(DOWNLOAD_DIR):
|
37 |
+
for f in files:
|
38 |
+
if f.endswith(".zip"):
|
39 |
+
zp = os.path.join(root, f)
|
40 |
+
with zipfile.ZipFile(zp) as z:
|
41 |
+
z.extractall(EXTRACT_DIR)
|
42 |
+
|
43 |
+
bad = os.path.join(EXTRACT_DIR, "world_nither")
|
44 |
+
good = os.path.join(EXTRACT_DIR, "world_nether")
|
45 |
+
if os.path.exists(bad) and not os.path.exists(good):
|
46 |
+
os.rename(bad, good)
|
47 |
+
|
48 |
+
login(token=TOKEN)
|
49 |
+
api = HfApi()
|
50 |
+
try:
|
51 |
+
api.delete_repo(repo_id=REPO_ID, repo_type="dataset")
|
52 |
+
except Exception as err:
|
53 |
+
print("delete skipped:", err)
|
54 |
+
|
55 |
+
api.create_repo(repo_id=REPO_ID, repo_type="dataset", private=False, exist_ok=True)
|
56 |
+
|
57 |
+
subfolders = {
|
58 |
+
"world": os.path.join(EXTRACT_DIR, "world"),
|
59 |
+
"world_nether": os.path.join(EXTRACT_DIR, "world_nether"),
|
60 |
+
"world_the_end": os.path.join(EXTRACT_DIR, "world_the_end"),
|
61 |
+
"plugins": os.path.join(EXTRACT_DIR, "plugins")
|
62 |
+
}
|
63 |
+
|
64 |
+
for name, path in subfolders.items():
|
65 |
+
if os.path.exists(path):
|
66 |
+
upload_folder(
|
67 |
+
repo_id=REPO_ID,
|
68 |
+
folder_path=path,
|
69 |
+
repo_type="dataset",
|
70 |
+
token=TOKEN,
|
71 |
+
path_in_repo=name,
|
72 |
+
commit_message="add " + name
|
73 |
+
)
|
74 |
+
last_backup_time = time.ctime()
|
75 |
+
return "Backup completed"
|
76 |
+
except Exception as e:
|
77 |
+
return f"Error: {str(e)}"
|
78 |
+
|
79 |
+
# Background timer
|
80 |
+
def schedule_loop():
|
81 |
+
while True:
|
82 |
+
if schedule_interval > 0:
|
83 |
+
run_backup()
|
84 |
+
time.sleep(schedule_interval * 60)
|
85 |
+
else:
|
86 |
+
time.sleep(10)
|
87 |
+
|
88 |
+
# Start scheduler thread
|
89 |
+
threading.Thread(target=schedule_loop, daemon=True).start()
|
90 |
+
|
91 |
+
# HTML template
|
92 |
+
HTML = """
|
93 |
+
<!DOCTYPE html>
|
94 |
+
<html>
|
95 |
+
<head>
|
96 |
+
<title>Minecraft Backup Panel</title>
|
97 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
98 |
+
<style>
|
99 |
+
body { font-family: sans-serif; padding: 20px; max-width: 600px; margin: auto; }
|
100 |
+
h2 { font-size: 24px; }
|
101 |
+
input, button { width: 100%; padding: 10px; margin: 8px 0; font-size: 16px; }
|
102 |
+
.box { background: #f5f5f5; padding: 15px; border-radius: 8px; margin-top: 20px; }
|
103 |
+
</style>
|
104 |
+
</head>
|
105 |
+
<body>
|
106 |
+
<h2>Minecraft Backup Controller</h2>
|
107 |
+
<form method="post">
|
108 |
+
<label>Set interval (minutes)</label>
|
109 |
+
<input type="number" name="interval" value="{{ interval }}" min="1">
|
110 |
+
<button type="submit">Set Timer</button>
|
111 |
+
</form>
|
112 |
+
<form method="post">
|
113 |
+
<input type="hidden" name="manual_run" value="1">
|
114 |
+
<button type="submit">Run Backup Now</button>
|
115 |
+
</form>
|
116 |
+
<div class="box">
|
117 |
+
<p><strong>Last Backup:</strong> {{ last_run }}</p>
|
118 |
+
<p><strong>Status:</strong> {{ status }}</p>
|
119 |
+
</div>
|
120 |
+
</body>
|
121 |
+
</html>
|
122 |
+
"""
|
123 |
+
|
124 |
+
@app.route("/", methods=["GET", "POST"])
|
125 |
+
def index():
|
126 |
+
global schedule_interval
|
127 |
+
status = ""
|
128 |
+
if request.method == "POST":
|
129 |
+
if "manual_run" in request.form:
|
130 |
+
status = run_backup()
|
131 |
+
else:
|
132 |
+
try:
|
133 |
+
schedule_interval = int(request.form.get("interval", "0"))
|
134 |
+
status = f"Timer set for every {schedule_interval} minutes"
|
135 |
+
except:
|
136 |
+
status = "Invalid interval"
|
137 |
+
return render_template_string(HTML, last_run=last_backup_time, interval=schedule_interval, status=status)
|
138 |
+
|
139 |
+
if __name__ == "__main__":
|
140 |
+
app.run(host="0.0.0.0", port=7860)
|