iozxv commited on
Commit
46c0813
·
verified ·
1 Parent(s): 6490e86

Create sync.py

Browse files
Files changed (1) hide show
  1. sync.py +132 -0
sync.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import time
4
+ import requests
5
+ from bs4 import BeautifulSoup
6
+ from urllib.parse import urljoin, unquote
7
+ from huggingface_hub import HfApi
8
+
9
+ # Configuration from Environment Variables (Secrets)
10
+ ONION_URL = os.getenv("ONION_URL") # e.g., http://xyz.onion/dirname/
11
+ HF_TOKEN = os.getenv("HF_TOKEN")
12
+ DATASET_REPO_ID = os.getenv("DATASET_REPO_ID") # e.g., username/dataset-name
13
+
14
+ HISTORY_FILE = "history.json"
15
+ MAX_LOCAL_STORAGE_BYTES = 35 * 1024 * 1024 * 1024 # Keep under 40GB limit (35GB threshold)
16
+
17
+ # Configure requests session to route through Tor SOCKS5 proxy
18
+ session = requests.Session()
19
+ session.proxies = {
20
+ 'http': 'socks5h://127.0.0.1:9050',
21
+ 'https': 'socks5h://127.0.0.1:9050'
22
+ }
23
+
24
+ def load_history():
25
+ if os.path.exists(HISTORY_FILE):
26
+ with open(HISTORY_FILE, "r") as f:
27
+ return set(json.load(f))
28
+ return set()
29
+
30
+ def save_history(completed_files):
31
+ with open(HISTORY_FILE, "w") as f:
32
+ json.dump(list(completed_files), f)
33
+
34
+ def get_dir_size(start_path='.'):
35
+ total_size = 0
36
+ for dirpath, dirnames, filenames in os.walk(start_path):
37
+ for f in filenames:
38
+ if f == HISTORY_FILE:
39
+ continue
40
+ fp = os.path.join(dirpath, f)
41
+ if os.path.exists(fp):
42
+ total_size += os.path.getsize(fp)
43
+ return total_size
44
+
45
+ def crawl_and_collect(url, relative_path=""):
46
+ """Recursively discover all files from the web directory listing."""
47
+ print(f"Scanning: {url}")
48
+ files_to_download = []
49
+ try:
50
+ response = session.get(url, timeout=30)
51
+ if response.status_code != 200:
52
+ print(f"Failed to fetch {url}: Status {response.status_code}")
53
+ return files_to_download
54
+
55
+ soup = BeautifulSoup(response.text, 'html.parser')
56
+ for link in soup.find_all('a'):
57
+ href = link.get('href')
58
+ if not href or href.startswith('?') or href == '../' or href == './':
59
+ continue
60
+
61
+ clean_href = unquote(href)
62
+ full_url = urljoin(url, href)
63
+ target_rel_path = os.path.join(relative_path, clean_href)
64
+
65
+ if href.endswith('/'):
66
+ # Recursive call for subdirectories
67
+ files_to_download.extend(crawl_and_collect(full_url, target_rel_path))
68
+ else:
69
+ files_to_download.append((full_url, target_rel_path))
70
+
71
+ except Exception as e:
72
+ print(f"Error crawling {url}: {e}")
73
+
74
+ return files_to_download
75
+
76
+ def main():
77
+ if not all([ONION_URL, HF_TOKEN, DATASET_REPO_ID]):
78
+ raise ValueError("Please set ONION_URL, HF_TOKEN, and DATASET_REPO_ID secrets.")
79
+
80
+ api = HfApi(token=HF_TOKEN)
81
+ completed_files = load_history()
82
+
83
+ print("Discovering file structure from .onion source...")
84
+ all_files = crawl_and_collect(ONION_URL)
85
+ print(f"Total files discovered: {len(all_files)}")
86
+
87
+ for file_url, rel_path in all_files:
88
+ if rel_path in completed_files:
89
+ continue
90
+
91
+ # Check local space utilization before downloading
92
+ while get_dir_size() > MAX_LOCAL_STORAGE_BYTES:
93
+ print("Storage threshold reached. Waiting/Cleaning...")
94
+ time.sleep(10)
95
+
96
+ print(f"Downloading: {rel_path}")
97
+ local_file_path = os.path.join("downloads", rel_path)
98
+ os.makedirs(os.path.dirname(local_file_path), exist_ok=True)
99
+
100
+ try:
101
+ # Stream download to handle large files efficiently
102
+ with session.get(file_url, stream=True, timeout=60) as r:
103
+ r.raise_for_status()
104
+ with open(local_file_path, 'wb') as f:
105
+ for chunk in r.iter_content(chunk_size=8192):
106
+ if chunk:
107
+ f.write(chunk)
108
+
109
+ # Upload immediately to Hugging Face Dataset Repo
110
+ print(f"Uploading {rel_path} to HF dataset...")
111
+ api.upload_file(
112
+ path_or_fileobj=local_file_path,
113
+ path_in_repo=rel_path,
114
+ repo_id=DATASET_REPO_ID,
115
+ repo_type="dataset"
116
+ )
117
+
118
+ # Mark as completed and remove locally to free up space
119
+ completed_files.add(rel_path)
120
+ save_history(completed_files)
121
+
122
+ if os.path.exists(local_file_path):
123
+ os.remove(local_file_path)
124
+
125
+ except Exception as e:
126
+ print(f"Error processing {rel_path}: {e}")
127
+ time.sleep(5) # Backoff on error
128
+
129
+ print("Synchronization complete!")
130
+
131
+ if __name__ == "__main__":
132
+ main()