This commit is contained in:
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from qbittorrent import Client
|
from qbittorrent import Client
|
||||||
|
from torrent import TorrentApi
|
||||||
|
|
||||||
# Replace with your qBittorrent Web UI credentials
|
# Replace with your qBittorrent Web UI credentials
|
||||||
qb = Client('http://192.168.1.17:8112')
|
torrent = TorrentApi("http://192.168.1.17:8112", "tMHNjrJr7nhjyhJrYsahi4anq2h6LJ")
|
||||||
qb.login('admin', 'tMHNjrJr7nhjyhJrYsahi4anq2h6LJ')
|
|
||||||
|
|
||||||
# Retrieve all active torrents
|
# Retrieve all active torrents
|
||||||
torrents = qb.torrents(filter='downloading')
|
torrents = torrent.get_torrents()
|
||||||
|
|
||||||
# Print details of each active torrent
|
# Print details of each active torrent
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
@@ -17,4 +17,4 @@ for torrent in torrents:
|
|||||||
print(f"Download Speed: {torrent['dlspeed'] / 1024:.2f} KB/s")
|
print(f"Download Speed: {torrent['dlspeed'] / 1024:.2f} KB/s")
|
||||||
print(f"Upload Speed: {torrent['upspeed'] / 1024:.2f} KB/s")
|
print(f"Upload Speed: {torrent['upspeed'] / 1024:.2f} KB/s")
|
||||||
print(f"Size: {torrent['size'] / (1024 * 1024):.2f} MB")
|
print(f"Size: {torrent['size'] / (1024 * 1024):.2f} MB")
|
||||||
print('-' * 40)
|
print("-" * 40)
|
||||||
@@ -2,26 +2,33 @@
|
|||||||
|
|
||||||
from qbittorrent import Client
|
from qbittorrent import Client
|
||||||
|
|
||||||
|
|
||||||
class TorrentApi:
|
class TorrentApi:
|
||||||
def __init__(self, ip, password, username='admin'):
|
def __init__(self, ip, password, username="admin"):
|
||||||
# Initialize the qBittorrent client
|
# Initialize the qBittorrent client
|
||||||
self.qb = Client(ip)
|
self.qb = Client(ip)
|
||||||
self.qb.login(username, password)
|
self.qb.login(username, password)
|
||||||
|
|
||||||
def get_torrents(self):
|
def get_torrents(self):
|
||||||
return self.get_filtered_torrents('all')
|
return self.get_filtered_torrents("all")
|
||||||
|
|
||||||
def get_filtered_torrents(self, state):
|
def get_filtered_torrents(self, state):
|
||||||
|
|
||||||
|
self.qb.login()
|
||||||
|
|
||||||
# Retrieve torrents filtered by the given state
|
# Retrieve torrents filtered by the given state
|
||||||
torrents = self.qb.torrents(filter=state)
|
torrents = self.qb.torrents(filter=state)
|
||||||
# Extract relevant information
|
# Extract relevant information
|
||||||
torrent_list = []
|
torrent_list = []
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
torrent_info = {
|
torrent_info = {
|
||||||
'name': torrent['name'],
|
"name": torrent["name"],
|
||||||
'state': torrent['state'],
|
"state": torrent["state"],
|
||||||
'progress': torrent['progress'] * 100, # Convert to percentage
|
"progress": torrent["progress"] * 100, # Convert to percentage
|
||||||
'eta': torrent['eta']
|
"eta": torrent["eta"],
|
||||||
|
"upspeed": torrent["upspeed"],
|
||||||
|
"dlspeed": torrent["dlspeed"],
|
||||||
|
"size": torrent["size"],
|
||||||
}
|
}
|
||||||
torrent_list.append(torrent_info)
|
torrent_list.append(torrent_info)
|
||||||
return torrent_list
|
return torrent_list
|
||||||
|
|||||||
93
main.py
93
main.py
@@ -10,31 +10,46 @@ import api.torrent as torrent
|
|||||||
|
|
||||||
TOKEN = "7396669954:AAH8_I0Y-qg3j_LfbUdRTOLPDKh80NdijMo"
|
TOKEN = "7396669954:AAH8_I0Y-qg3j_LfbUdRTOLPDKh80NdijMo"
|
||||||
|
|
||||||
|
|
||||||
# --- Menu Definitions ---
|
# --- Menu Definitions ---
|
||||||
def main_menu_keyboard():
|
def main_menu_keyboard():
|
||||||
return InlineKeyboardMarkup([
|
return InlineKeyboardMarkup(
|
||||||
[InlineKeyboardButton("Torrents", callback_data='status_downloading')],
|
[
|
||||||
[InlineKeyboardButton("Status", callback_data='menu_status')]
|
[InlineKeyboardButton("Torrents", callback_data="status_downloading")],
|
||||||
])
|
[InlineKeyboardButton("Status", callback_data="menu_status")],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def torrents_menu_keyboard():
|
def torrents_menu_keyboard():
|
||||||
return InlineKeyboardMarkup([
|
return InlineKeyboardMarkup(
|
||||||
|
[
|
||||||
# First row: Display the status counts for downloading, paused, seeding
|
# First row: Display the status counts for downloading, paused, seeding
|
||||||
[InlineKeyboardButton(f"Downloading", callback_data='status_downloading')],
|
[InlineKeyboardButton(f"Downloading", callback_data="status_downloading")],
|
||||||
[InlineKeyboardButton(f"Active", callback_data='status_active')],
|
[InlineKeyboardButton(f"Active", callback_data="status_active")],
|
||||||
[InlineKeyboardButton(f"All", callback_data='status_all')],
|
[InlineKeyboardButton(f"All", callback_data="status_all")],
|
||||||
# Second row: Back button
|
# Second row: Back button
|
||||||
[InlineKeyboardButton("🔙 Back", callback_data='menu_main')]
|
[InlineKeyboardButton("🔙 Back", callback_data="menu_main")],
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def status_menu_keyboard():
|
def status_menu_keyboard():
|
||||||
return InlineKeyboardMarkup([
|
return InlineKeyboardMarkup(
|
||||||
[InlineKeyboardButton("🔙 Back", callback_data='menu_main')]
|
[[InlineKeyboardButton("🔙 Back", callback_data="menu_main")]]
|
||||||
])
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Command Handlers ---
|
# --- Command Handlers ---
|
||||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
await update.message.reply_text("Choose an option:", reply_markup=main_menu_keyboard())
|
try:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"Choose an option:", reply_markup=main_menu_keyboard()
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"An error occurred: {e}")
|
||||||
|
# Optionally log the error
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
|
||||||
def format_torrents(torrents):
|
def format_torrents(torrents):
|
||||||
@@ -45,56 +60,73 @@ def format_torrents(torrents):
|
|||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
if i > 10:
|
if i > 5:
|
||||||
text += "...\n"
|
text += "...\n"
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
text += f"Name: {torrent['name']}\n"
|
||||||
|
text += f"State: {torrent['state']}\n"
|
||||||
|
text += f"Progress: {torrent['progress']:.2f}%\n"
|
||||||
|
text += f"ETA: {torrent['eta']}\n"
|
||||||
|
text += "-" * 20 + "\n"
|
||||||
|
|
||||||
text += f"- {torrent['name']} - {torrent['progress']} ({torrent['eta']})\n"
|
text += f"- {torrent['name']} - {torrent['progress']} ({torrent['eta']})\n"
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
# --- Callback Query Handler ---
|
# --- Callback Query Handler ---
|
||||||
async def handle_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
async def handle_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
await query.answer()
|
await query.answer()
|
||||||
|
|
||||||
match query.data:
|
match query.data:
|
||||||
case 'menu_main':
|
case "menu_main":
|
||||||
await query.edit_message_text("Choose an option:", reply_markup=main_menu_keyboard())
|
await query.edit_message_text(
|
||||||
|
"Choose an option:", reply_markup=main_menu_keyboard()
|
||||||
|
)
|
||||||
|
|
||||||
case 'status_downloading':
|
case "status_downloading":
|
||||||
t_api = context.bot_data.get("torrent_api", {})
|
t_api = context.bot_data.get("torrent_api", {})
|
||||||
torrents = t_api.get_filtered_torrents("downloading")
|
torrents = t_api.get_filtered_torrents("downloading")
|
||||||
|
|
||||||
|
if len(torrents) == 0:
|
||||||
|
text = "No downloading torrents."
|
||||||
|
else:
|
||||||
text = format_torrents(torrents)
|
text = format_torrents(torrents)
|
||||||
|
|
||||||
await query.edit_message_text(text, reply_markup=torrents_menu_keyboard())
|
await query.edit_message_text(text, reply_markup=torrents_menu_keyboard())
|
||||||
|
|
||||||
case 'status_active':
|
case "status_active":
|
||||||
t_api = context.bot_data.get("torrent_api", {})
|
t_api = context.bot_data.get("torrent_api", {})
|
||||||
torrents = t_api.get_filtered_torrents("active")
|
torrents = t_api.get_filtered_torrents("active")
|
||||||
|
|
||||||
|
if len(torrents) == 0:
|
||||||
|
text = "No active torrents."
|
||||||
|
else:
|
||||||
text = format_torrents(torrents)
|
text = format_torrents(torrents)
|
||||||
|
|
||||||
await query.edit_message_text(text, reply_markup=torrents_menu_keyboard())
|
await query.edit_message_text(text, reply_markup=torrents_menu_keyboard())
|
||||||
|
|
||||||
|
case "status_all":
|
||||||
case 'status_all':
|
|
||||||
t_api = context.bot_data.get("torrent_api", {})
|
t_api = context.bot_data.get("torrent_api", {})
|
||||||
torrents = t_api.get_filtered_torrents("all")
|
torrents = t_api.get_filtered_torrents("all")
|
||||||
|
|
||||||
|
if len(torrents) == 0:
|
||||||
|
text = "No torrents."
|
||||||
|
else:
|
||||||
text = format_torrents(torrents)
|
text = format_torrents(torrents)
|
||||||
|
|
||||||
await query.edit_message_text(text, reply_markup=torrents_menu_keyboard())
|
await query.edit_message_text(text, reply_markup=torrents_menu_keyboard())
|
||||||
|
|
||||||
case 'menu_status':
|
case "menu_status":
|
||||||
k_api = context.bot_data.get("kuma_api", {})
|
k_api = context.bot_data.get("kuma_api", {})
|
||||||
monitors = k_api.get_status()
|
monitors = k_api.get_status()
|
||||||
|
|
||||||
up_text, down_text, paused_text = "", "", ""
|
up_text, down_text, paused_text = "", "", ""
|
||||||
for _, monitor in monitors.items():
|
for _, monitor in monitors.items():
|
||||||
status = monitor['status']
|
status = monitor["status"]
|
||||||
|
|
||||||
if status == MonitorStatus.UP:
|
if status == MonitorStatus.UP:
|
||||||
up_text += f" - {monitor['name']}\n"
|
up_text += f" - {monitor['name']}\n"
|
||||||
@@ -103,13 +135,17 @@ async def handle_menu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
|
|||||||
else:
|
else:
|
||||||
paused_text += f" - {monitor['name']}\n"
|
paused_text += f" - {monitor['name']}\n"
|
||||||
|
|
||||||
|
|
||||||
status_text = f"📡 *Status:*\n\n 🟢 Up:\n{up_text}\n🔴 Down\n{down_text}\n⏸️ Paused\n{paused_text}"
|
status_text = f"📡 *Status:*\n\n 🟢 Up:\n{up_text}\n🔴 Down\n{down_text}\n⏸️ Paused\n{paused_text}"
|
||||||
|
|
||||||
await query.edit_message_text(status_text, reply_markup=status_menu_keyboard())
|
await query.edit_message_text(
|
||||||
|
status_text, reply_markup=status_menu_keyboard()
|
||||||
|
)
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
await query.edit_message_text("Unknown option selected.", reply_markup=main_menu_keyboard())
|
await query.edit_message_text(
|
||||||
|
"Unknown option selected.", reply_markup=main_menu_keyboard()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Main Function ---
|
# --- Main Function ---
|
||||||
def main():
|
def main():
|
||||||
@@ -117,7 +153,9 @@ def main():
|
|||||||
|
|
||||||
# Initiate api
|
# Initiate api
|
||||||
kuma_api = kuma.KumaAPI("http://192.168.1.2:36667", "k!PTfyvoIJho9o*gX6F1")
|
kuma_api = kuma.KumaAPI("http://192.168.1.2:36667", "k!PTfyvoIJho9o*gX6F1")
|
||||||
torrent_api = torrent.TorrentApi("http://192.168.1.17:8112", "tMHNjrJr7nhjyhJrYsahi4anq2h6LJ")
|
torrent_api = torrent.TorrentApi(
|
||||||
|
"http://192.168.1.17:8112", "tMHNjrJr7nhjyhJrYsahi4anq2h6LJ"
|
||||||
|
)
|
||||||
|
|
||||||
app = Application.builder().token(TOKEN).build()
|
app = Application.builder().token(TOKEN).build()
|
||||||
app.bot_data["kuma_api"] = kuma_api
|
app.bot_data["kuma_api"] = kuma_api
|
||||||
@@ -129,5 +167,6 @@ def main():
|
|||||||
print("Bot is running... Press Ctrl+C to stop.")
|
print("Bot is running... Press Ctrl+C to stop.")
|
||||||
app.run_polling()
|
app.run_polling()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user