-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c6d4b65
commit d7e06d6
Showing
11 changed files
with
844 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import aria2p | ||
|
||
class HttpDownloader: | ||
def __init__(self): | ||
self.download = None | ||
self.aria2 = aria2p.API( | ||
aria2p.Client( | ||
host="http://localhost", | ||
port=6800, | ||
secret="" | ||
) | ||
) | ||
|
||
def start_download(self, url: str, save_path: str, header: str): | ||
if self.download: | ||
self.aria2.resume([self.download]) | ||
else: | ||
downloads = self.aria2.add(url, options={"header": header, "dir": save_path}) | ||
self.download = downloads[0] | ||
|
||
def pause_download(self): | ||
if self.download: | ||
self.aria2.pause([self.download]) | ||
|
||
def cancel_download(self): | ||
if self.download: | ||
self.aria2.remove([self.download]) | ||
self.download = None | ||
|
||
def get_download_status(self): | ||
if self.download == None: | ||
return None | ||
|
||
download = self.aria2.get_download(self.download.gid) | ||
|
||
response = { | ||
'folderName': str(download.dir) + "/" + download.name, | ||
'fileSize': download.total_length, | ||
'progress': download.completed_length / download.total_length if download.total_length else 0, | ||
'downloadSpeed': download.download_speed, | ||
'numPeers': 0, | ||
'numSeeds': 0, | ||
'status': download.status, | ||
'bytesDownloaded': download.completed_length, | ||
} | ||
|
||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
from flask import Flask, request, jsonify | ||
import sys, json, urllib.parse, psutil | ||
from torrent_downloader import TorrentDownloader | ||
from http_downloader import HttpDownloader | ||
from profile_image_processor import ProfileImageProcessor | ||
import libtorrent as lt | ||
|
||
app = Flask(__name__) | ||
|
||
# Retrieve command line arguments | ||
torrent_port = sys.argv[1] | ||
http_port = sys.argv[2] | ||
rpc_password = sys.argv[3] | ||
|
||
downloads = {} | ||
# This can be streamed down from Node | ||
downloading_game_id = -1 | ||
|
||
torrent_session = lt.session({'listen_interfaces': '0.0.0.0:{port}'.format(port=torrent_port)}) | ||
|
||
def validate_rpc_password(): | ||
"""Middleware to validate RPC password.""" | ||
header_password = request.headers.get('x-hydra-rpc-password') | ||
if header_password != rpc_password: | ||
return jsonify({"error": "Unauthorized"}), 401 | ||
|
||
@app.route("/status", methods=["GET"]) | ||
def status(): | ||
auth_error = validate_rpc_password() | ||
if auth_error: | ||
return auth_error | ||
|
||
downloader = downloads.get(downloading_game_id) | ||
if downloader: | ||
status = downloads.get(downloading_game_id).get_download_status() | ||
return jsonify(status), 200 | ||
else: | ||
return jsonify(None) | ||
|
||
@app.route("/seed-status", methods=["GET"]) | ||
def seed_status(): | ||
auth_error = validate_rpc_password() | ||
if auth_error: | ||
return auth_error | ||
|
||
status = torrent_downloader.get_seed_status() | ||
return jsonify(status), 200 | ||
|
||
@app.route("/healthcheck", methods=["GET"]) | ||
def healthcheck(): | ||
return "", 200 | ||
|
||
@app.route("/process-list", methods=["GET"]) | ||
def process_list(): | ||
auth_error = validate_rpc_password() | ||
if auth_error: | ||
return auth_error | ||
|
||
process_list = [proc.info for proc in psutil.process_iter(['exe', 'pid', 'username'])] | ||
return jsonify(process_list), 200 | ||
|
||
@app.route("/profile-image", methods=["POST"]) | ||
def profile_image(): | ||
auth_error = validate_rpc_password() | ||
if auth_error: | ||
return auth_error | ||
|
||
data = request.get_json() | ||
image_path = data.get('image_path') | ||
|
||
try: | ||
processed_image_path, mime_type = ProfileImageProcessor.process_image(image_path) | ||
return jsonify({'imagePath': processed_image_path, 'mimeType': mime_type}), 200 | ||
except Exception as e: | ||
return jsonify({"error": str(e)}), 400 | ||
|
||
@app.route("/action", methods=["POST"]) | ||
def action(): | ||
global torrent_session | ||
global downloading_game_id | ||
|
||
auth_error = validate_rpc_password() | ||
if auth_error: | ||
return auth_error | ||
|
||
data = request.get_json() | ||
action = data.get('action') | ||
game_id = data.get('game_id') | ||
|
||
print(data) | ||
|
||
if action == 'start': | ||
url = data.get('url') | ||
|
||
existing_downloader = downloads.get(game_id) | ||
|
||
if existing_downloader: | ||
# This will resume the download | ||
existing_downloader.start_download(url, data['save_path'], data.get('header')) | ||
else: | ||
if url.startswith('magnet'): | ||
torrent_downloader = TorrentDownloader(torrent_session) | ||
downloads[game_id] = torrent_downloader | ||
torrent_downloader.start_download(url, data['save_path'], "") | ||
else: | ||
http_downloader = HttpDownloader() | ||
downloads[game_id] = http_downloader | ||
http_downloader.start_download(url, data['save_path'], data.get('header')) | ||
|
||
downloading_game_id = game_id | ||
|
||
elif action == 'pause': | ||
downloader = downloads.get(game_id) | ||
if downloader: | ||
downloader.pause_download() | ||
downloading_game_id = -1 | ||
elif action == 'cancel': | ||
downloader = downloads.get(game_id) | ||
if downloader: | ||
downloader.cancel_download() | ||
|
||
# elif action == 'kill-torrent': | ||
# torrent_downloader.abort_session() | ||
# torrent_downloader = None | ||
# elif action == 'pause-seeding': | ||
# torrent_downloader.pause_seeding(game_id) | ||
# elif action == 'resume-seeding': | ||
# torrent_downloader.resume_seeding(game_id, data['url'], data['save_path']) | ||
else: | ||
return jsonify({"error": "Invalid action"}), 400 | ||
|
||
return "", 200 | ||
|
||
if __name__ == "__main__": | ||
app.run(host="0.0.0.0", port=int(http_port)) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from PIL import Image | ||
import os, uuid, tempfile | ||
|
||
class ProfileImageProcessor: | ||
|
||
@staticmethod | ||
def get_parsed_image_data(image_path): | ||
Image.MAX_IMAGE_PIXELS = 933120000 | ||
|
||
image = Image.open(image_path) | ||
|
||
try: | ||
image.seek(1) | ||
except EOFError: | ||
mime_type = image.get_format_mimetype() | ||
return image_path, mime_type | ||
else: | ||
newUUID = str(uuid.uuid4()) | ||
new_image_path = os.path.join(tempfile.gettempdir(), newUUID) + ".webp" | ||
image.save(new_image_path) | ||
|
||
new_image = Image.open(new_image_path) | ||
mime_type = new_image.get_format_mimetype() | ||
|
||
return new_image_path, mime_type | ||
|
||
|
||
@staticmethod | ||
def process_image(image_path): | ||
return ProfileImageProcessor.get_parsed_image_data(image_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from cx_Freeze import setup, Executable | ||
|
||
# Dependencies are automatically detected, but it might need fine tuning. | ||
build_exe_options = { | ||
"packages": ["libtorrent"], | ||
"build_exe": "hydra-python-rpc", | ||
"include_msvcr": True | ||
} | ||
|
||
setup( | ||
name="hydra-python-rpc", | ||
version="0.1", | ||
description="Hydra", | ||
options={"build_exe": build_exe_options}, | ||
executables=[Executable( | ||
"python_rpc/main.py", | ||
target_name="hydra-python-rpc", | ||
icon="build/icon.ico" | ||
)] | ||
) |
Oops, something went wrong.