Commit
·
1fa8166
1
Parent(s):
10ba288
0.0.2.3 V Beta. added download episode.
Browse files- LoadBalancer.py +45 -1
- api.py +23 -0
- app.py +6 -16
LoadBalancer.py
CHANGED
@@ -19,7 +19,7 @@ download_progress = {}
|
|
19 |
|
20 |
class LoadBalancer:
|
21 |
def __init__(self, cache_dir, index_file, token, repo, polling_interval=10, max_retries=3, initial_delay=1):
|
22 |
-
self.version = "0.0.2.
|
23 |
self.instances = []
|
24 |
self.instances_health = {}
|
25 |
self.polling_interval = polling_interval
|
@@ -264,6 +264,50 @@ class LoadBalancer:
|
|
264 |
logging.error("No suitable instance found for downloading the film.")
|
265 |
return {"error": "No suitable instance found for downloading the film."}
|
266 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
def _convert_to_gb(self, space_str):
|
268 |
"""
|
269 |
Converts a space string like '50 GB' or '3.33 GB' to a float representing the number of GB.
|
|
|
19 |
|
20 |
class LoadBalancer:
|
21 |
def __init__(self, cache_dir, index_file, token, repo, polling_interval=10, max_retries=3, initial_delay=1):
|
22 |
+
self.version = "0.0.2.3 V Beta"
|
23 |
self.instances = []
|
24 |
self.instances_health = {}
|
25 |
self.polling_interval = polling_interval
|
|
|
264 |
logging.error("No suitable instance found for downloading the film.")
|
265 |
return {"error": "No suitable instance found for downloading the film."}
|
266 |
|
267 |
+
def download_episode_to_best_instance(self, title, season, episode):
|
268 |
+
"""
|
269 |
+
Downloads a episode to the first instance that has more free space on the self.instance_health list variable.
|
270 |
+
The instance_health looks like this:
|
271 |
+
{
|
272 |
+
"https://unicone-studio-instance1.hf.space": {
|
273 |
+
"total": "50 GB",
|
274 |
+
"used": "3.33 GB"
|
275 |
+
}
|
276 |
+
}
|
277 |
+
Args:
|
278 |
+
title (str): The title of the Tv show.
|
279 |
+
season (str): The season of the Tv show.
|
280 |
+
episode (str): The title of the Tv show.
|
281 |
+
"""
|
282 |
+
best_instance = None
|
283 |
+
max_free_space = -1
|
284 |
+
|
285 |
+
# Calculate free space for each instance
|
286 |
+
for instance_url, space_info in self.instances_health.items():
|
287 |
+
total_space = self._convert_to_gb(space_info['total'])
|
288 |
+
used_space = self._convert_to_gb(space_info['used'])
|
289 |
+
free_space = total_space - used_space
|
290 |
+
|
291 |
+
if free_space > max_free_space:
|
292 |
+
max_free_space = free_space
|
293 |
+
best_instance = instance_url
|
294 |
+
|
295 |
+
if best_instance:
|
296 |
+
result = self.instances_api.download_episode(best_instance, title, season, episode)
|
297 |
+
episode_id = result["episode_id"]
|
298 |
+
status = result["status"]
|
299 |
+
progress_url = f'{best_instance}/api/progress/{episode_id}'
|
300 |
+
response = {
|
301 |
+
"film_id":episode_id,
|
302 |
+
"status":status,
|
303 |
+
"progress_url":progress_url
|
304 |
+
}
|
305 |
+
|
306 |
+
return response
|
307 |
+
else:
|
308 |
+
logging.error("No suitable instance found for downloading the film.")
|
309 |
+
return {"error": "No suitable instance found for downloading the film."}
|
310 |
+
|
311 |
def _convert_to_gb(self, space_str):
|
312 |
"""
|
313 |
Converts a space string like '50 GB' or '3.33 GB' to a float representing the number of GB.
|
api.py
CHANGED
@@ -38,3 +38,26 @@ class InstancesAPI:
|
|
38 |
data = {"error": str(e)}
|
39 |
|
40 |
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
data = {"error": str(e)}
|
39 |
|
40 |
return data
|
41 |
+
|
42 |
+
def download_episode(self, instance_url, title, season, episode):
|
43 |
+
"""
|
44 |
+
Download a film to an instance.
|
45 |
+
|
46 |
+
If the download started, it returns a JSON like this:
|
47 |
+
example:
|
48 |
+
{"film_id": "my_spy_2020",
|
49 |
+
"status": "Download started"}
|
50 |
+
|
51 |
+
If the film has already been downloaded, it will return the video file.
|
52 |
+
"""
|
53 |
+
data = {}
|
54 |
+
try:
|
55 |
+
response = requests.get(f"{instance_url}/api/tv/{title}/{season}/{episode}")
|
56 |
+
response.raise_for_status()
|
57 |
+
data = response.json()
|
58 |
+
|
59 |
+
except requests.exceptions.RequestException as e:
|
60 |
+
logging.error(f"Error contacting instance {instance_url}: {e}")
|
61 |
+
data = {"error": str(e)}
|
62 |
+
|
63 |
+
return data
|
app.py
CHANGED
@@ -64,10 +64,8 @@ def get_tv_show_api(title, season, episode):
|
|
64 |
if title in tv_store_data and season in tv_store_data[title]:
|
65 |
for ep in tv_store_data[title][season]:
|
66 |
if episode in ep:
|
67 |
-
|
68 |
-
|
69 |
-
if os.path.exists(cache_path):
|
70 |
-
return send_from_directory(os.path.dirname(cache_path), os.path.basename(cache_path))
|
71 |
|
72 |
tv_path = load_balancer.find_tv_path(title)
|
73 |
|
@@ -89,18 +87,10 @@ def get_tv_show_api(title, season, episode):
|
|
89 |
if not episode_path:
|
90 |
return jsonify({"error": "Episode not found"}), 404
|
91 |
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
# Start the download in a separate thread if not already downloading
|
98 |
-
if episode_id not in load_balancer.download_threads or not load_balancer.download_threads[episode_id].is_alive():
|
99 |
-
thread = Thread(target=load_balancer.download_episode, args=(file_url, TOKEN, cache_path, proxies, episode_id, title))
|
100 |
-
load_balancer.download_threads[episode_id] = thread
|
101 |
-
thread.start()
|
102 |
-
|
103 |
-
return jsonify({"status": "Download started", "episode_id": episode_id})
|
104 |
|
105 |
@app.route('/api/progress/<id>', methods=['GET'])
|
106 |
def get_progress_api(id):
|
|
|
64 |
if title in tv_store_data and season in tv_store_data[title]:
|
65 |
for ep in tv_store_data[title][season]:
|
66 |
if episode in ep:
|
67 |
+
url = tv_store_data[title][season][ep]
|
68 |
+
return jsonify({"url":url})
|
|
|
|
|
69 |
|
70 |
tv_path = load_balancer.find_tv_path(title)
|
71 |
|
|
|
87 |
if not episode_path:
|
88 |
return jsonify({"error": "Episode not found"}), 404
|
89 |
|
90 |
+
# Start the download in a instance
|
91 |
+
response = load_balancer.download_episode_to_best_instance(title=title, season=season, episode=episode)
|
92 |
+
if response:
|
93 |
+
return jsonify(response)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
@app.route('/api/progress/<id>', methods=['GET'])
|
96 |
def get_progress_api(id):
|