from flask import Blueprint, render_template, session, redirect, url_for, jsonify, request import sqlite3 import qbittorrentapi import sys import os # Import format functions sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from utils.format import format_file_size, format_status qbittorrent_bp = Blueprint('qbittorrent', __name__) def get_db_connection(): conn = sqlite3.connect('pt_manager.db') conn.row_factory = sqlite3.Row return conn def get_qbittorrent_client(): conn = get_db_connection() client_config = conn.execute( "SELECT * FROM clients WHERE name = 'qbittorrent' AND enabled = 1" ).fetchone() conn.close() if not client_config: return None try: qb = qbittorrentapi.Client( host=client_config['host'], port=client_config['port'], username=client_config['username'], password=client_config['password'] ) qb.auth_log_in() return qb except Exception as e: print(f"Failed to connect to qBittorrent: {e}") return None @qbittorrent_bp.route('/qbittorrent') def qbittorrent_index(): if 'user_id' not in session: return redirect(url_for('auth.login')) return render_template('qbittorrent/index.html') @qbittorrent_bp.route('/qbittorrent/torrents') def torrents(): if 'user_id' not in session: return redirect(url_for('auth.login')) qb = get_qbittorrent_client() if not qb: return render_template('qbittorrent/torrents.html', error='qBittorrent client not configured or unavailable') try: torrents = qb.torrents_info() # Process torrents to format file sizes and statuses processed_torrents = [] for torrent in torrents: processed_torrent = { 'hash': torrent.hash, 'name': torrent.name, 'size': format_file_size(torrent.size), 'progress': torrent.progress, 'state': torrent.state, 'status': format_status(torrent.state), 'num_seeds': getattr(torrent, 'num_seeds', 0), 'num_leechs': getattr(torrent, 'num_leechs', 0) } processed_torrents.append(processed_torrent) return render_template('qbittorrent/torrents.html', torrents=processed_torrents) except Exception as e: return render_template('qbittorrent/torrents.html', error=f'Failed to fetch torrents: {str(e)}') @qbittorrent_bp.route('/qbittorrent/torrent//pause', methods=['POST']) def pause_torrent(info_hash): if 'user_id' not in session: return jsonify({'error': 'Authentication required'}), 401 qb = get_qbittorrent_client() if not qb: return jsonify({'error': 'qBittorrent client not configured or unavailable'}), 500 try: qb.torrents_pause(hashes=info_hash) return jsonify({'success': True}) except Exception as e: return jsonify({'error': str(e)}), 500 @qbittorrent_bp.route('/qbittorrent/torrent//resume', methods=['POST']) def resume_torrent(info_hash): if 'user_id' not in session: return jsonify({'error': 'Authentication required'}), 401 qb = get_qbittorrent_client() if not qb: return jsonify({'error': 'qBittorrent client not configured or unavailable'}), 500 try: qb.torrents_resume(hashes=info_hash) return jsonify({'success': True}) except Exception as e: return jsonify({'error': str(e)}), 500 @qbittorrent_bp.route('/qbittorrent/torrent//delete', methods=['POST']) def delete_torrent(info_hash): if 'user_id' not in session: return jsonify({'error': 'Authentication required'}), 401 qb = get_qbittorrent_client() if not qb: return jsonify({'error': 'qBittorrent client not configured or unavailable'}), 500 try: # Delete torrent and data qb.torrents_delete(hashes=info_hash, delete_files=True) return jsonify({'success': True}) except Exception as e: return jsonify({'error': str(e)}), 500