310 lines
8.2 KiB
Python
310 lines
8.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# (c) YashDK [yash-dk@github]
|
|
|
|
import os
|
|
import time
|
|
import logging
|
|
import qbittorrentapi as qba
|
|
import asyncio
|
|
|
|
from aiohttp import web
|
|
import nodes
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
routes = web.RouteTableDef()
|
|
|
|
page = """
|
|
<html>
|
|
<head>
|
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs=" crossorigin="anonymous"></script>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<style>
|
|
body {
|
|
padding: 20px;
|
|
}
|
|
ul {
|
|
list-style: none;
|
|
margin: 5px 20px;
|
|
}
|
|
li {
|
|
margin: 10px 0;
|
|
}
|
|
|
|
|
|
p { font-size: 12px; margin: 24px;}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>slam-mirrorbot: <a href="https://github.com/breakdowns/slam-mirrorbot">@Github</a></h1>
|
|
<form action="{form_url}" method="POST">
|
|
|
|
{My_content}
|
|
|
|
<input type="submit" name="Select these files ;)">
|
|
</form>
|
|
|
|
<script>
|
|
$('input[type="checkbox"]').change(function(e) {
|
|
|
|
var checked = $(this).prop("checked"),
|
|
container = $(this).parent(),
|
|
siblings = container.siblings();
|
|
/*
|
|
$(this).attr('value', function(index, attr){
|
|
return attr == 'yes' ? 'noo' : 'yes';
|
|
});
|
|
*/
|
|
container.find('input[type="checkbox"]').prop({
|
|
indeterminate: false,
|
|
checked: checked
|
|
});
|
|
|
|
function checkSiblings(el) {
|
|
|
|
var parent = el.parent().parent(),
|
|
all = true;
|
|
|
|
el.siblings().each(function() {
|
|
let returnValue = all = ($(this).children('input[type="checkbox"]').prop("checked") === checked);
|
|
return returnValue;
|
|
});
|
|
|
|
if (all && checked) {
|
|
|
|
parent.children('input[type="checkbox"]').prop({
|
|
indeterminate: false,
|
|
checked: checked
|
|
});
|
|
|
|
checkSiblings(parent);
|
|
|
|
} else if (all && !checked) {
|
|
|
|
parent.children('input[type="checkbox"]').prop("checked", checked);
|
|
parent.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0));
|
|
checkSiblings(parent);
|
|
|
|
} else {
|
|
|
|
el.parents("li").children('input[type="checkbox"]').prop({
|
|
indeterminate: true,
|
|
checked: false
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
checkSiblings(container);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|
|
"""
|
|
|
|
code_page = """
|
|
<html>
|
|
<head>
|
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
|
|
<title>
|
|
Slam Torrent Files
|
|
</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<form action="{form_url}">
|
|
<div class="form-group">
|
|
<label for="pin_code">Pin Code</label>
|
|
<input type="text" class="form-control" name="pin_code" placeholder="Enter code to access the torrent">
|
|
<small class="form-text text-muted">Dont mess around. You download will get messed up.</small>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">Submit</button>
|
|
</form>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
|
|
@routes.get('/slam/files/{hash_id}')
|
|
async def list_torrent_contents(request):
|
|
|
|
torr = request.match_info["hash_id"]
|
|
|
|
gets = request.query
|
|
|
|
if not "pin_code" in gets.keys():
|
|
rend_page = code_page.replace("{form_url}",f"/slam/files/{torr}")
|
|
return web.Response(text=rend_page,content_type='text/html')
|
|
|
|
|
|
client = qba.Client(host="localhost",port="8090",username="admin",password="adminadmin")
|
|
client.auth_log_in()
|
|
try:
|
|
res = client.torrents_files(torrent_hash=torr)
|
|
except qba.NotFound404Error:
|
|
raise web.HTTPNotFound()
|
|
count = 0
|
|
passw = ""
|
|
for n in str(torr):
|
|
if n.isdigit():
|
|
passw += str(n)
|
|
count += 1
|
|
if count == 4:
|
|
break
|
|
if isinstance(passw, bool):
|
|
raise web.HTTPNotFound()
|
|
pincode = passw
|
|
if gets["pin_code"] != pincode:
|
|
return web.Response(text="Incorrect pin code")
|
|
|
|
|
|
par = nodes.make_tree(res)
|
|
|
|
cont = ["",0]
|
|
nodes.create_list(par,cont)
|
|
|
|
rend_page = page.replace("{My_content}",cont[0])
|
|
rend_page = rend_page.replace("{form_url}",f"/slam/files/{torr}?pin_code={pincode}")
|
|
client.auth_log_out()
|
|
return web.Response(text=rend_page,content_type='text/html')
|
|
|
|
|
|
async def re_verfiy(paused, resumed, client, torr):
|
|
|
|
paused = paused.strip()
|
|
resumed = resumed.strip()
|
|
if paused:
|
|
paused = paused.split("|")
|
|
if resumed:
|
|
resumed = resumed.split("|")
|
|
k = 0
|
|
while True:
|
|
|
|
res = client.torrents_files(torrent_hash=torr)
|
|
verify = True
|
|
|
|
for i in res:
|
|
if str(i.id) in paused:
|
|
if i.priority == 0:
|
|
continue
|
|
else:
|
|
verify = False
|
|
break
|
|
|
|
if str(i.id) in resumed:
|
|
if i.priority != 0:
|
|
continue
|
|
else:
|
|
verify = False
|
|
break
|
|
|
|
|
|
if not verify:
|
|
LOGGER.info("Reverification Failed :- correcting stuff")
|
|
# reconnect and issue the request again
|
|
client.auth_log_out()
|
|
client = qba.Client(host="localhost",port="8090",username="admin",password="adminadmin")
|
|
client.auth_log_in()
|
|
try:
|
|
client.torrents_file_priority(torrent_hash=torr,file_ids=paused,priority=0)
|
|
except:
|
|
LOGGER.error("Errored in reverification paused")
|
|
try:
|
|
client.torrents_file_priority(torrent_hash=torr,file_ids=resumed,priority=1)
|
|
except:
|
|
LOGGER.error("Errored in reverification resumed")
|
|
client.auth_log_out()
|
|
else:
|
|
break
|
|
k += 1
|
|
if k >= 2:
|
|
# avoid an infite loop here
|
|
return False
|
|
return True
|
|
|
|
|
|
|
|
@routes.post('/slam/files/{hash_id}')
|
|
async def set_priority(request):
|
|
|
|
torr = request.match_info["hash_id"]
|
|
client = qba.Client(host="localhost",port="8090",username="admin",password="adminadmin")
|
|
client.auth_log_in()
|
|
|
|
data = await request.post()
|
|
resume = ""
|
|
pause = ""
|
|
data = dict(data)
|
|
|
|
for i in data.keys():
|
|
if i.find("filenode") != -1:
|
|
node_no = i.split("_")[-1]
|
|
|
|
if data[i] == "on":
|
|
resume += f"{node_no}|"
|
|
else:
|
|
pause += f"{node_no}|"
|
|
|
|
pause = pause.strip("|")
|
|
resume = resume.strip("|")
|
|
LOGGER.info(f"Paused {pause} of {torr}")
|
|
LOGGER.info(f"Resumed {resume} of {torr}")
|
|
|
|
try:
|
|
client.torrents_file_priority(torrent_hash=torr,file_ids=pause,priority=0)
|
|
except qba.NotFound404Error:
|
|
raise web.HTTPNotFound()
|
|
except:
|
|
LOGGER.info("Errored in paused")
|
|
|
|
try:
|
|
client.torrents_file_priority(torrent_hash=torr,file_ids=resume,priority=1)
|
|
except qba.NotFound404Error:
|
|
raise web.HTTPNotFound()
|
|
except:
|
|
LOGGER.info("Errored in resumed")
|
|
|
|
await asyncio.sleep(2)
|
|
if not await re_verfiy(pause,resume,client,torr):
|
|
LOGGER.error("The torrent choose errored reverification failed")
|
|
client.auth_log_out()
|
|
return await list_torrent_contents(request)
|
|
|
|
@routes.get('/')
|
|
async def homepage(request):
|
|
|
|
return web.Response(text="<h1>See slam-mirrorbot <a href='https://github.com/breakdowns/slam-mirrorbot'>@GitHub</a> By <a href='https://github.com/breakdowns'>Breakdowns</a></h1>",content_type="text/html")
|
|
|
|
async def e404_middleware(app, handler):
|
|
|
|
async def middleware_handler(request):
|
|
|
|
try:
|
|
response = await handler(request)
|
|
if response.status == 404:
|
|
return web.Response(text="<h1>404: Page not found</h2><br><h3>slam-mirrorbot</h3>",content_type="text/html")
|
|
return response
|
|
except web.HTTPException as ex:
|
|
if ex.status == 404:
|
|
return web.Response(text="<h1>404: Page not found</h2><br><h3>slam-mirrorbot</h3>",content_type="text/html")
|
|
raise
|
|
return middleware_handler
|
|
|
|
async def start_server():
|
|
|
|
app = web.Application(middlewares=[e404_middleware])
|
|
app.add_routes(routes)
|
|
return app
|
|
|
|
async def start_server_async(port = 8080):
|
|
|
|
app = web.Application(middlewares=[e404_middleware])
|
|
app.add_routes(routes)
|
|
runner = web.AppRunner(app)
|
|
await runner.setup()
|
|
await web.TCPSite(runner,"0.0.0.0", port).start()
|