ChandimaPrabath commited on
Commit
98b82d8
·
1 Parent(s): e1cb714

0.0.2.7 V Beta

Browse files
Files changed (3) hide show
  1. LoadBalancer.py +1 -1
  2. app.py +215 -20
  3. requirements.txt +2 -5
LoadBalancer.py CHANGED
@@ -15,7 +15,7 @@ download_progress = {}
15
 
16
  class LoadBalancer:
17
  def __init__(self, cache_dir, index_file, token, repo, polling_interval=4, max_retries=3, initial_delay=1):
18
- self.version = "0.0.2.7 V Beta"
19
  self.instances = []
20
  self.instances_health = {}
21
  self.polling_interval = polling_interval
 
15
 
16
  class LoadBalancer:
17
  def __init__(self, cache_dir, index_file, token, repo, polling_interval=4, max_retries=3, initial_delay=1):
18
+ self.version = "0.0.2.10 V Beta"
19
  self.instances = []
20
  self.instances_health = {}
21
  self.polling_interval = polling_interval
app.py CHANGED
@@ -1,22 +1,217 @@
1
- import subprocess
2
- import sys
3
-
4
- def run_uvicorn():
5
- # Command to run the FastAPI app with uvicorn
6
- command = [
7
- "uvicorn",
8
- "main:app",
9
- "--host", "0.0.0.0",
10
- "--port", "7860",
11
- "--reload"
12
- ]
13
-
14
- # Run the command
15
- subprocess.run(command, check=True)
16
 
17
- if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  try:
19
- run_uvicorn()
20
- except subprocess.CalledProcessError as e:
21
- print(f"Error running uvicorn: {e}", file=sys.stderr)
22
- sys.exit(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, jsonify, request, send_from_directory
2
+ from flask_cors import CORS
3
+ from utils import is_valid_url, bytes_to_human_readable, encode_episodeid
4
+ import os
5
+ import json
6
+ from threading import Thread
7
+ import urllib.parse
8
+ from LoadBalancer import LoadBalancer
9
+ import logging
 
 
 
 
 
 
10
 
11
+
12
+ app = Flask(__name__)
13
+ CORS(app)
14
+
15
+ logging.basicConfig(level=logging.INFO)
16
+ # Constants and Configuration
17
+ CACHE_DIR = os.getenv("CACHE_DIR")
18
+ INDEX_FILE = os.getenv("INDEX_FILE")
19
+ TOKEN = os.getenv("TOKEN")
20
+ REPO = os.getenv("REPO")
21
+
22
+ load_balancer = LoadBalancer(cache_dir=CACHE_DIR, index_file=INDEX_FILE, token=TOKEN, repo=REPO)
23
+
24
+ # Start polling in a separate thread
25
+ polling_thread = Thread(target=load_balancer.start_polling)
26
+ polling_thread.start()
27
+
28
+ # API Endpoints
29
+ @app.route('/api/film/<title>', methods=['GET'])
30
+ def get_movie_api(title):
31
+ """Endpoint to get the movie by title."""
32
+ if not title:
33
+ return jsonify({"error": "Title parameter is required"}), 400
34
+
35
+ # Check if the film is already cached
36
+ if title in load_balancer.FILM_STORE:
37
+ url = load_balancer.FILM_STORE[title]
38
+ return jsonify({"url":url})
39
+
40
+ movie_path = load_balancer.find_movie_path(title)
41
+
42
+ if not movie_path:
43
+ return jsonify({"error": "Movie not found"}), 404
44
+
45
+ # Start the download in a instance
46
+ response = load_balancer.download_film_to_best_instance(title=title)
47
+ if response:
48
+ return jsonify(response)
49
+
50
+ @app.route('/api/tv/<title>/<season>/<episode>', methods=['GET'])
51
+ def get_tv_show_api(title, season, episode):
52
+ """Endpoint to get the TV show by title, season, and episode."""
53
+ if not title or not season or not episode:
54
+ return jsonify({"error": "Title, season, and episode parameters are required"}), 400
55
+
56
+ # Check if the episode is already cached
57
+ if title in load_balancer.TV_STORE and season in load_balancer.TV_STORE[title]:
58
+ for ep in load_balancer.TV_STORE[title][season]:
59
+ if episode in ep:
60
+ url = load_balancer.TV_STORE[title][season][ep]
61
+ return jsonify({"url":url})
62
+
63
+ tv_path = load_balancer.find_tv_path(title)
64
+
65
+ if not tv_path:
66
+ return jsonify({"error": "TV show not found"}), 404
67
+
68
+ episode_path = None
69
+ for directory in load_balancer.file_structure:
70
+ if directory['type'] == 'directory' and directory['path'] == 'tv':
71
+ for sub_directory in directory['contents']:
72
+ if sub_directory['type'] == 'directory' and title.lower() in sub_directory['path'].lower():
73
+ for season_dir in sub_directory['contents']:
74
+ if season_dir['type'] == 'directory' and season in season_dir['path']:
75
+ for episode_file in season_dir['contents']:
76
+ if episode_file['type'] == 'file' and episode in episode_file['path']:
77
+ episode_path = episode_file['path']
78
+ break
79
+
80
+ if not episode_path:
81
+ return jsonify({"error": "Episode not found"}), 404
82
+
83
+ # Start the download in a instance
84
+ response = load_balancer.download_episode_to_best_instance(title=title, season=season, episode=episode)
85
+ if response:
86
+ return jsonify(response)
87
+
88
+ @app.route('/api/filmid/<title>', methods=['GET'])
89
+ def get_film_id_by_title_api(title):
90
+ """Endpoint to get the film ID by providing the movie title."""
91
+ if not title:
92
+ return jsonify({"error": "Title parameter is required"}), 400
93
+ film_id = load_balancer.get_film_id(title)
94
+ return jsonify({"film_id": film_id})
95
+
96
+ @app.route('/api/episodeid/<title>/<season>/<episode>', methods=['GET'])
97
+ def get_episode_id_api(title,season,episode):
98
+ """Endpoint to get the episode ID by providing the TV show title, season, and episode."""
99
+ if not title or not season or not episode:
100
+ return jsonify({"error": "Title, season, and episode parameters are required"}), 400
101
+ episode_id = encode_episodeid(title,season,episode)
102
+ return jsonify({"episode_id": episode_id})
103
+
104
+ @app.route('/api/cache/size', methods=['GET'])
105
+ def get_cache_size_api():
106
+ total_size = 0
107
+ for dirpath, dirnames, filenames in os.walk(CACHE_DIR):
108
+ for f in filenames:
109
+ fp = os.path.join(dirpath, f)
110
+ total_size += os.path.getsize(fp)
111
+ readable_size = bytes_to_human_readable(total_size)
112
+ return jsonify({"cache_size": readable_size})
113
+
114
+ @app.route('/api/cache/clear', methods=['POST'])
115
+ def clear_cache_api():
116
+ for dirpath, dirnames, filenames in os.walk(CACHE_DIR):
117
+ for f in filenames:
118
+ fp = os.path.join(dirpath, f)
119
+ os.remove(fp)
120
+ return jsonify({"status": "Cache cleared"})
121
+
122
+ @app.route('/api/tv/store', methods=['GET'])
123
+ def get_tv_store_api():
124
+ """Endpoint to get the TV store JSON."""
125
+ return jsonify(load_balancer.TV_STORE)
126
+
127
+
128
+ @app.route('/api/film/store', methods=['GET'])
129
+ def get_film_store_api():
130
+ """Endpoint to get the film store JSON."""
131
+ return jsonify(load_balancer.FILM_STORE)
132
+
133
+
134
+ @app.route('/api/film/metadata/<title>', methods=['GET'])
135
+ def get_film_metadata_api(title):
136
+ """Endpoint to get the film metadata by title."""
137
+ if not title:
138
+ return jsonify({'error': 'No title provided'}), 400
139
+
140
+ json_cache_path = os.path.join(CACHE_DIR, f"{urllib.parse.quote(title)}.json")
141
+
142
+ if os.path.exists(json_cache_path):
143
+ with open(json_cache_path, 'r') as f:
144
+ data = json.load(f)
145
+ return jsonify(data)
146
+
147
+ return jsonify({'error': 'Metadata not found'}), 404
148
+
149
+ @app.route('/api/tv/metadata/<title>', methods=['GET'])
150
+ def get_tv_metadata_api(title):
151
+ """Endpoint to get the TV show metadata by title."""
152
+ if not title:
153
+ return jsonify({'error': 'No title provided'}), 400
154
+
155
+ json_cache_path = os.path.join(CACHE_DIR, f"{urllib.parse.quote(title)}.json")
156
+
157
+ if os.path.exists(json_cache_path):
158
+ with open(json_cache_path, 'r') as f:
159
+ data = json.load(f)
160
+
161
+ # Add the file structure to the metadata
162
+ tv_structure_data = load_balancer.get_tv_structure(title)
163
+ if tv_structure_data:
164
+ data['file_structure'] = tv_structure_data
165
+
166
+ return jsonify(data)
167
+
168
+ return jsonify({'error': 'Metadata not found'}), 404
169
+
170
+
171
+ @app.route("/api/film/all")
172
+ def get_all_films_api():
173
+ return load_balancer.get_all_films()
174
+
175
+ @app.route("/api/tv/all")
176
+ def get_all_tvshows_api():
177
+ return load_balancer.get_all_tv_shows()
178
+
179
+ @app.route('/api/instances',methods=["GET"])
180
+ def get_instances():
181
+ return load_balancer.instances
182
+
183
+ @app.route('/api/instances/health',methods=["GET"])
184
+ def get_instances_health():
185
+ return load_balancer.instances_health
186
+ #############################################################
187
+ # This API is only for instances
188
+ @app.route('/api/register', methods=['POST'])
189
+ def register_instance():
190
  try:
191
+ data = request.json
192
+ if not data or "url" not in data:
193
+ return jsonify({"error": "No URL provided"}), 400
194
+
195
+ url = data["url"]
196
+ if not is_valid_url(url):
197
+ return jsonify({"error": "Invalid URL"}), 400
198
+
199
+ # Register the instance
200
+ load_balancer.register_instance(url)
201
+ logging.info(f"Instance registered: {url}")
202
+
203
+ return jsonify({"message": f"Instance {url} registered successfully"}), 200
204
+
205
+ except Exception as e:
206
+ logging.error(f"Error registering instance: {e}")
207
+ return jsonify({"error": "Failed to register instance"}), 500
208
+
209
+ #############################################################
210
+ # Routes
211
+ @app.route('/')
212
+ def index():
213
+ return f"Load Balancer is Running {load_balancer.version}"
214
+
215
+ # Main entry point
216
+ if __name__ == "__main__":
217
+ app.run(debug=True, host="0.0.0.0", port=7860)
requirements.txt CHANGED
@@ -1,8 +1,5 @@
1
- fastapi
2
- aiofiles
3
- aiohttp
4
- tqdm
5
- uvicorn
6
  requests
7
  python-dotenv
8
  tqdm
 
1
+ Flask
2
+ Flask-Cors
 
 
 
3
  requests
4
  python-dotenv
5
  tqdm