mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-16 00:43:00 -03:00
Compare commits
8 Commits
chore/test
...
github/for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c63fce8edc | ||
|
|
d93e234001 | ||
|
|
0fdd2797a5 | ||
|
|
4b763173f6 | ||
|
|
ec3748343d | ||
|
|
b4526b6f67 | ||
|
|
a09124e8be | ||
|
|
c7f2a861d5 |
File diff suppressed because one or more lines are too long
@@ -8,8 +8,8 @@
|
||||
"trending": "Tendencias",
|
||||
"surprise_me": "¡Sorpréndeme!",
|
||||
"no_results": "No se encontraron resultados",
|
||||
"hot": "Caliente ahora",
|
||||
"weekly": "📅 Los mejores juegos de la semana",
|
||||
"hot": "Popular Ahora",
|
||||
"weekly": "📅 Destacados de esta semana",
|
||||
"start_typing": "Empieza a escribir para buscar..."
|
||||
},
|
||||
"sidebar": {
|
||||
@@ -123,11 +123,11 @@
|
||||
"download": "Descargar",
|
||||
"download_count": "Descargas",
|
||||
"download_error": "Esta opción de descarga no está disponible.",
|
||||
"executable_path_in_use": "Ejecutable ya en uso por \"{{game}}\"",
|
||||
"nsfw_content_description": "{{title}} incluye contenido que puede no ser adecuado para todas las edades. \n¿Estás seguro de que quieres continuar?",
|
||||
"executable_path_in_use": "El ejecutable se encuentra en uso por \"{{game}}\"",
|
||||
"nsfw_content_description": "{{title}} puede ser no adecuado para todas las edades por su contenido. \n¿Deseas continuar de igual forma?",
|
||||
"nsfw_content_title": "Este juego contiene contenido inapropiado.",
|
||||
"player_count": "Jugadores activos",
|
||||
"refuse_nsfw_content": "Volver",
|
||||
"refuse_nsfw_content": "No, gracias",
|
||||
"stats": "Estadísticas"
|
||||
},
|
||||
"activation": {
|
||||
@@ -209,7 +209,7 @@
|
||||
"download_options_one": "",
|
||||
"download_options_other": "",
|
||||
"download_options_zero": "",
|
||||
"friends_only": "solo amigos",
|
||||
"friends_only": "Solo amigos",
|
||||
"must_be_valid_url": "La fuente debe ser una URL válida.",
|
||||
"privacy": "Privacidad",
|
||||
"private": "Privado",
|
||||
@@ -296,21 +296,21 @@
|
||||
"no_blocked_users": "No has bloqueado a ningún usuario",
|
||||
"friend_code_copied": "Código de amigo copiado",
|
||||
"undo_friendship_modal_text": "Esto deshará tu amistad con {{displayName}}",
|
||||
"displayname_max_length": "El nombre para mostrar debe tener como máximo 50 caracteres",
|
||||
"displayname_min_length": "El nombre para mostrar debe tener al menos 3 caracteres",
|
||||
"displayname_max_length": "El nombre a mostrar debe tener como máximo 50 caracteres",
|
||||
"displayname_min_length": "El nombre a mostrar debe tener al menos 3 caracteres",
|
||||
"locked_profile": "Este perfil es privado.",
|
||||
"privacy_hint": "Para ajustar quién puede ver esto, ve a <0>Configuración</0>.",
|
||||
"profile_locked": "",
|
||||
"profile_locked": "Este perfil es privado",
|
||||
"profile_reported": "Perfil reportado",
|
||||
"report": "Informe",
|
||||
"report": "Reportar",
|
||||
"report_description": "Información adicional",
|
||||
"report_description_placeholder": "Información adicional",
|
||||
"report_profile": "Reportar este perfil",
|
||||
"report_reason": "¿Por qué estás denunciando este perfil?",
|
||||
"report_reason_hate": "Discurso de odio",
|
||||
"report_reason": "¿Cual es el motivo del reporte?",
|
||||
"report_reason_hate": "Discursos de odio",
|
||||
"report_reason_other": "Otro",
|
||||
"report_reason_sexual_content": "Contenido sexual",
|
||||
"report_reason_spam": "Correo basura",
|
||||
"report_reason_spam": "Spam/Contenido no deseado",
|
||||
"report_reason_violence": "Violencia",
|
||||
"required_field": "Este campo es obligatorio",
|
||||
"image_process_failure": "Error al procesar la imagen"
|
||||
|
||||
@@ -13,10 +13,13 @@ start_download_payload = sys.argv[4]
|
||||
|
||||
torrent_downloader = None
|
||||
|
||||
if start_download_payload:
|
||||
initial_download = json.loads(urllib.parse.unquote(start_download_payload))
|
||||
torrent_downloader = TorrentDownloader(torrent_port)
|
||||
torrent_downloader.start_download(initial_download['game_id'], initial_download['magnet'], initial_download['save_path'])
|
||||
try:
|
||||
if start_download_payload:
|
||||
initial_download = json.loads(urllib.parse.unquote(start_download_payload))
|
||||
torrent_downloader = TorrentDownloader(torrent_port)
|
||||
torrent_downloader.start_download(initial_download['game_id'], initial_download['magnet'], initial_download['save_path'])
|
||||
except (json.JSONDecodeError, KeyError, ValueError) as e:
|
||||
sys.stderr.write(f"Failed to start torrent download: {e}\n")
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
rpc_password_header = 'x-hydra-rpc-password'
|
||||
@@ -30,95 +33,131 @@ class Handler(BaseHTTPRequestHandler):
|
||||
sys.stderr.write("%s - - [%s] %s\n" %
|
||||
(self.address_string(),
|
||||
self.log_date_time_string(),
|
||||
format%args))
|
||||
format % args))
|
||||
|
||||
def log_message(self, format, *args):
|
||||
for route in self.skip_log_routes:
|
||||
if route in args[0]: return
|
||||
|
||||
if route in args[0]:
|
||||
return
|
||||
super().log_message(format, *args)
|
||||
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == "/status":
|
||||
if self.headers.get(self.rpc_password_header) != rpc_password:
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
return
|
||||
try:
|
||||
if self.path == "/status":
|
||||
if self.headers.get(self.rpc_password_header) != rpc_password:
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/json")
|
||||
self.end_headers()
|
||||
|
||||
status = torrent_downloader.get_download_status()
|
||||
|
||||
self.wfile.write(json.dumps(status).encode('utf-8'))
|
||||
|
||||
elif self.path == "/healthcheck":
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
elif self.path == "/process-list":
|
||||
if self.headers.get(self.rpc_password_header) != rpc_password:
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
process_list = [proc.info for proc in psutil.process_iter(['exe', 'pid', 'username'])]
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/json")
|
||||
self.end_headers()
|
||||
|
||||
self.wfile.write(json.dumps(process_list).encode('utf-8'))
|
||||
|
||||
def do_POST(self):
|
||||
global torrent_downloader
|
||||
|
||||
if self.headers.get(self.rpc_password_header) != rpc_password:
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
content_length = int(self.headers['Content-Length'])
|
||||
post_data = self.rfile.read(content_length)
|
||||
data = json.loads(post_data.decode('utf-8'))
|
||||
|
||||
if self.path == "/profile-image":
|
||||
parsed_image_path = data['image_path']
|
||||
|
||||
try:
|
||||
parsed_image_path, mime_type = ProfileImageProcessor.process_image(parsed_image_path)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/json")
|
||||
self.end_headers()
|
||||
|
||||
self.wfile.write(json.dumps({'imagePath': parsed_image_path, 'mimeType': mime_type}).encode('utf-8'))
|
||||
except:
|
||||
self.send_response(400)
|
||||
|
||||
status = torrent_downloader.get_download_status()
|
||||
self.wfile.write(json.dumps(status).encode('utf-8'))
|
||||
|
||||
elif self.path == "/healthcheck":
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
elif self.path == "/action":
|
||||
if torrent_downloader is None:
|
||||
torrent_downloader = TorrentDownloader(torrent_port)
|
||||
elif self.path == "/process-list":
|
||||
if self.headers.get(self.rpc_password_header) != rpc_password:
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
if data['action'] == 'start':
|
||||
torrent_downloader.start_download(data['game_id'], data['magnet'], data['save_path'])
|
||||
elif data['action'] == 'pause':
|
||||
torrent_downloader.pause_download(data['game_id'])
|
||||
elif data['action'] == 'cancel':
|
||||
torrent_downloader.cancel_download(data['game_id'])
|
||||
elif data['action'] == 'kill-torrent':
|
||||
torrent_downloader.abort_session()
|
||||
torrent_downloader = None
|
||||
process_list = [proc.info for proc in psutil.process_iter(['exe', 'pid', 'username'])]
|
||||
|
||||
self.send_response(200)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/json")
|
||||
self.end_headers()
|
||||
|
||||
self.wfile.write(json.dumps(process_list).encode('utf-8'))
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Error in GET request: {e}\n")
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
def do_POST(self):
|
||||
global torrent_downloader
|
||||
try:
|
||||
if self.headers.get(self.rpc_password_header) != rpc_password:
|
||||
self.send_response(401)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
content_length = int(self.headers['Content-Length'])
|
||||
post_data = self.rfile.read(content_length)
|
||||
data = json.loads(post_data.decode('utf-8'))
|
||||
|
||||
if self.path == "/profile-image":
|
||||
parsed_image_path = data['image_path']
|
||||
try:
|
||||
parsed_image_path, mime_type = ProfileImageProcessor.process_image(parsed_image_path)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/json")
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps({'imagePath': parsed_image_path, 'mimeType': mime_type}).encode('utf-8'))
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Error processing profile image: {e}\n")
|
||||
self.send_response(400)
|
||||
self.end_headers()
|
||||
|
||||
elif self.path == "/action":
|
||||
if torrent_downloader is None:
|
||||
torrent_downloader = TorrentDownloader(torrent_port)
|
||||
|
||||
if data['action'] == 'start':
|
||||
try:
|
||||
torrent_downloader.start_download(data['game_id'], data['magnet'], data['save_path'])
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Error starting torrent: {e}\n")
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
elif data['action'] == 'pause':
|
||||
try:
|
||||
torrent_downloader.pause_download(data['game_id'])
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Error pausing torrent: {e}\n")
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
elif data['action'] == 'cancel':
|
||||
try:
|
||||
torrent_downloader.cancel_download(data['game_id'])
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Error canceling torrent: {e}\n")
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
elif data['action'] == 'kill-torrent':
|
||||
try:
|
||||
torrent_downloader.abort_session()
|
||||
torrent_downloader = None
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Error killing torrent: {e}\n")
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
return
|
||||
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Error in POST request: {e}\n")
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
|
||||
if __name__ == "__main__":
|
||||
httpd = HTTPServer(("", int(http_port)), Handler)
|
||||
httpd.serve_forever()
|
||||
try:
|
||||
httpd = HTTPServer(("", int(http_port)), Handler)
|
||||
sys.stderr.write(f"Server running on port {http_port}\n")
|
||||
httpd.serve_forever()
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"Failed to start HTTP server: {e}\n")
|
||||
|
||||
@@ -4,7 +4,11 @@ class TorrentDownloader:
|
||||
def __init__(self, port: str):
|
||||
self.torrent_handles = {}
|
||||
self.downloading_game_id = -1
|
||||
self.session = lt.session({'listen_interfaces': '0.0.0.0:{port}'.format(port=port)})
|
||||
try:
|
||||
self.session = lt.session({'listen_interfaces': '0.0.0.0:{port}'.format(port=port)})
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to initialize torrent session: {e}")
|
||||
|
||||
self.trackers = [
|
||||
"udp://tracker.opentrackr.org:1337/announce",
|
||||
"http://tracker.opentrackr.org:1337/announce",
|
||||
@@ -103,56 +107,81 @@ class TorrentDownloader:
|
||||
]
|
||||
|
||||
def start_download(self, game_id: int, magnet: str, save_path: str):
|
||||
params = {'url': magnet, 'save_path': save_path, 'trackers': self.trackers}
|
||||
torrent_handle = self.session.add_torrent(params)
|
||||
self.torrent_handles[game_id] = torrent_handle
|
||||
torrent_handle.set_flags(lt.torrent_flags.auto_managed)
|
||||
torrent_handle.resume()
|
||||
try:
|
||||
params = {'url': magnet, 'save_path': save_path, 'trackers': self.trackers}
|
||||
torrent_handle = self.session.add_torrent(params)
|
||||
self.torrent_handles[game_id] = torrent_handle
|
||||
torrent_handle.set_flags(lt.torrent_flags.auto_managed)
|
||||
torrent_handle.resume()
|
||||
|
||||
self.downloading_game_id = game_id
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to start download for game {game_id}: {e}")
|
||||
|
||||
|
||||
self.downloading_game_id = game_id
|
||||
|
||||
def pause_download(self, game_id: int):
|
||||
torrent_handle = self.torrent_handles.get(game_id)
|
||||
if torrent_handle:
|
||||
torrent_handle.pause()
|
||||
torrent_handle.unset_flags(lt.torrent_flags.auto_managed)
|
||||
self.downloading_game_id = -1
|
||||
try:
|
||||
torrent_handle = self.torrent_handles.get(game_id)
|
||||
if torrent_handle:
|
||||
torrent_handle.pause()
|
||||
torrent_handle.unset_flags(lt.torrent_flags.auto_managed)
|
||||
self.downloading_game_id = -1
|
||||
else:
|
||||
raise KeyError(f"Torrent handle not found for game {game_id}")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to pause download for game {game_id}: {e}")
|
||||
|
||||
|
||||
def cancel_download(self, game_id: int):
|
||||
torrent_handle = self.torrent_handles.get(game_id)
|
||||
if torrent_handle:
|
||||
torrent_handle.pause()
|
||||
self.session.remove_torrent(torrent_handle)
|
||||
self.torrent_handles[game_id] = None
|
||||
self.downloading_game_id = -1
|
||||
try:
|
||||
torrent_handle = self.torrent_handles.get(game_id)
|
||||
if torrent_handle:
|
||||
torrent_handle.pause()
|
||||
self.session.remove_torrent(torrent_handle)
|
||||
self.torrent_handles[game_id] = None
|
||||
self.downloading_game_id = -1
|
||||
else:
|
||||
raise KeyError(f"Torrent handle not found for game {game_id}")
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to cancel download for game {game_id}: {e}")
|
||||
|
||||
|
||||
def abort_session(self):
|
||||
for game_id in self.torrent_handles:
|
||||
torrent_handle = self.torrent_handles[game_id]
|
||||
torrent_handle.pause()
|
||||
self.session.remove_torrent(torrent_handle)
|
||||
|
||||
self.session.abort()
|
||||
self.torrent_handles = {}
|
||||
self.downloading_game_id = -1
|
||||
try:
|
||||
for game_id in self.torrent_handles:
|
||||
torrent_handle = self.torrent_handles[game_id]
|
||||
torrent_handle.pause()
|
||||
self.session.remove_torrent(torrent_handle)
|
||||
|
||||
self.session.abort()
|
||||
self.torrent_handles = {}
|
||||
self.downloading_game_id = -1
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to abort torrent session: {e}")
|
||||
|
||||
def get_download_status(self):
|
||||
if self.downloading_game_id == -1:
|
||||
return None
|
||||
|
||||
torrent_handle = self.torrent_handles.get(self.downloading_game_id)
|
||||
try:
|
||||
torrent_handle = self.torrent_handles.get(self.downloading_game_id)
|
||||
if not torrent_handle:
|
||||
raise KeyError(f"Torrent handle not found for game {self.downloading_game_id}")
|
||||
|
||||
status = torrent_handle.status()
|
||||
info = torrent_handle.get_torrent_info()
|
||||
status = torrent_handle.status()
|
||||
info = torrent_handle.get_torrent_info()
|
||||
|
||||
return {
|
||||
'folderName': info.name() if info else "",
|
||||
'fileSize': info.total_size() if info else 0,
|
||||
'gameId': self.downloading_game_id,
|
||||
'progress': status.progress,
|
||||
'downloadSpeed': status.download_rate,
|
||||
'numPeers': status.num_peers,
|
||||
'numSeeds': status.num_seeds,
|
||||
'status': status.state,
|
||||
'bytesDownloaded': status.progress * info.total_size() if info else status.all_time_download,
|
||||
}
|
||||
return {
|
||||
'folderName': info.name() if info else "",
|
||||
'fileSize': info.total_size() if info else 0,
|
||||
'gameId': self.downloading_game_id,
|
||||
'progress': status.progress,
|
||||
'downloadSpeed': status.download_rate,
|
||||
'numPeers': status.num_peers,
|
||||
'numSeeds': status.num_seeds,
|
||||
'status': status.state,
|
||||
'bytesDownloaded': status.progress * info.total_size() if info else status.all_time_download,
|
||||
}
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to get download status for game {self.downloading_game_id}: {e}")
|
||||
|
||||
Reference in New Issue
Block a user