From e9ed762769ffb9c17ee774c9f566ae21f32f347d Mon Sep 17 00:00:00 2001 From: Jose134 Date: Sun, 8 Dec 2024 02:24:48 +0100 Subject: [PATCH] Organize project in files, add dotenv support and debug configuration for vscode --- .vscode/launch.json | 13 +++++ src/filemoving.py | 46 ++++++++++++++++++ src/main.py | 106 +++++++---------------------------------- src/qbittorrent_api.py | 47 ++++++++++++++++++ 4 files changed, 123 insertions(+), 89 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 src/filemoving.py create mode 100644 src/qbittorrent_api.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..adff9d1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Module", + "type": "debugpy", + "request": "launch", + "module": "uvicorn", + "cwd": "${workspaceFolder}/src", + "args": ["main:app","--reload"] + } + ] +} \ No newline at end of file diff --git a/src/filemoving.py b/src/filemoving.py new file mode 100644 index 0000000..e984bc0 --- /dev/null +++ b/src/filemoving.py @@ -0,0 +1,46 @@ +import os +import shutil +import re + +def group_files_by_prefix(directory, downloading_files): + patterns_str = _get_patterns() + + if not os.path.isdir(directory): + print(f"The directory {directory} does not exist.") + return + + files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))] + + for file in files: + skip = False + for downloading_file in downloading_files: + if file.startswith(downloading_file): + print(f"File {file} is downloading. Skipping...") + skip = True + continue + + if skip: + continue + + for pattern_str in patterns_str: + pattern = re.compile(pattern_str) + match = pattern.match(file) + if match: + prefix_dir = os.path.join(directory, match.group(1)) + + if not os.path.exists(prefix_dir): + os.makedirs(prefix_dir) + + shutil.move(os.path.join(directory, file), os.path.join(prefix_dir, file)) + +def _get_patterns(): + config_file_path = os.path.join(os.getcwd(), 'config', 'patterns.txt') + + patterns = [] + if os.path.isfile(config_file_path): + with open(config_file_path, 'r') as file: + patterns = [line.strip() for line in file if line.strip()] + else: + print(f"The config file {config_file_path} does not exist.") + + return patterns \ No newline at end of file diff --git a/src/main.py b/src/main.py index ee726c4..1f90ad0 100644 --- a/src/main.py +++ b/src/main.py @@ -1,101 +1,29 @@ import os -import shutil -import re -import requests from fastapi import FastAPI +from dotenv import load_dotenv -def login_qbittorrent(api_url, username, password): - login_url = f'{api_url}/api/v2/auth/login' - data = { - 'username': username, - 'password': password - } - response = requests.post(login_url, data=data) - - if response.status_code != 200 or response.text != 'Ok.': - print(f"Failed to login to qBittorrent: {response.status_code}") - return None +from qbittorrent_api import get_qbittorrent_files_downloading +from filemoving import group_files_by_prefix +import uuid - return response.cookies +load_dotenv() -def logout_qbittorrent(api_url, cookies): - response = requests.get(f'{api_url}/api/v2/auth/logout', cookies=cookies) - - if response.status_code != 200 or response.text != 'Ok.': - print(f"Failed to logout from qBittorrent: {response.status_code}") - return False - - return True - -def get_qbittorrent_files_downloading(api_url, cookies): - ALLOWED_EXTENSIONS = ['mkv', 'mp4', 'avi', 'wmv', 'flv', 'mov', 'webm', 'mpg', 'mpeg'] - response = requests.get(f'{api_url}/api/v2/torrents/info?filter=downloading', cookies=cookies) - - if response.status_code != 200: - print(f"Failed to fetch data from qBittorrent API: {response.status_code}") - return [] - - torrents = response.json() - files = [] - for torrent in torrents: - file_extension = torrent['name'].rpartition('.')[-1] if '.' in torrent['name'] else '' - if file_extension in ALLOWED_EXTENSIONS: - files.append(torrent['name']) - return files - -def group_files_by_prefix(directory, patterns_str, downloading_files): - if not os.path.isdir(directory): - print(f"The directory {directory} does not exist.") - return - - files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))] - - for file in files: - skip = False - for downloading_file in downloading_files: - if file.startswith(downloading_file): - print(f"File {file} is downloading. Skipping...") - skip = True - continue - - if skip: - continue - - for pattern_str in patterns_str: - pattern = re.compile(pattern_str) - match = pattern.match(file) - if match: - prefix_dir = os.path.join(directory, match.group(1)) - - if not os.path.exists(prefix_dir): - os.makedirs(prefix_dir) - - shutil.move(os.path.join(directory, file), os.path.join(prefix_dir, file)) - - - - -config_file_path = os.path.join(os.getcwd(), 'config', 'patterns.txt') - -if os.path.isfile(config_file_path): - with open(config_file_path, 'r') as file: - patterns = [line.strip() for line in file if line.strip()] -else: - print(f"The config file {config_file_path} does not exist.") - patterns = [] +qbit_url = os.getenv('QB_URL') +qbit_user = os.getenv('QB_USER') +qbit_password = os.getenv('QB_PASSWORD') +target_dir = os.getenv('TARGET_DIR') +if not qbit_url or not qbit_user or not qbit_password or not target_dir: + print("Please provide all the required environment variables.") + exit(1) app = FastAPI() @app.get("/") async def root(): - return {"Hello": "World"} + job_id = str(uuid.uuid4()) -# if len(patterns) > 0: -# # TODO: READ USER AND PASS FROM ENV FILE -# cookies = login_qbittorrent('http://qbittorrent.xdarkbird.duckdns.org', 'USER', 'PASS') -# downloading = get_qbittorrent_files_downloading('http://qbittorrent.xdarkbird.duckdns.org', cookies) -# logout_qbittorrent('http://qbittorrent.xdarkbird.duckdns.org', cookies) + # TODO Launch the job in the background + # downloading = get_qbittorrent_files_downloading(qbit_url, qbit_user, qbit_password) + # group_files_by_prefix(target_dir, downloading) -# print(f"Patterns: {patterns}") -# print(f"Downloading files: {downloading}") -# group_files_by_prefix(os.path.join(os.getcwd(), 'testfiles'), patterns, downloading) + return job_id diff --git a/src/qbittorrent_api.py b/src/qbittorrent_api.py new file mode 100644 index 0000000..b09b252 --- /dev/null +++ b/src/qbittorrent_api.py @@ -0,0 +1,47 @@ +import requests +from os import environ + +def get_qbittorrent_files_downloading(api_url, user, password): + cookies = _login_qbittorrent('http://qbittorrent.xdarkbird.duckdns.org', user, password) + if not cookies: + return [] + + ALLOWED_EXTENSIONS = ['mkv', 'mp4', 'avi', 'wmv', 'flv', 'mov', 'webm', 'mpg', 'mpeg'] + response = requests.get(f'{api_url}/api/v2/torrents/info?filter=downloading', cookies=cookies) + + if response.status_code != 200: + print(f"Failed to fetch data from qBittorrent API: {response.status_code}") + return [] + + torrents = response.json() + files = [] + for torrent in torrents: + file_extension = torrent['name'].rpartition('.')[-1] if '.' in torrent['name'] else '' + if file_extension in ALLOWED_EXTENSIONS: + files.append(torrent['name']) + + _logout_qbittorrent('http://qbittorrent.xdarkbird.duckdns.org', cookies) + return files + +def _login_qbittorrent(api_url, username, password): + login_url = f'{api_url}/api/v2/auth/login' + data = { + 'username': username, + 'password': password + } + response = requests.post(login_url, data=data) + + if response.status_code != 200 or response.text != 'Ok.': + print(f"Failed to login to qBittorrent: {response.status_code}") + return None + + return response.cookies + +def _logout_qbittorrent(api_url, cookies): + response = requests.get(f'{api_url}/api/v2/auth/logout', cookies=cookies) + + if response.status_code != 200 or response.text != 'Ok.': + print(f"Failed to logout from qBittorrent: {response.status_code}") + return False + + return True \ No newline at end of file