First commit
This commit is contained in:
+201
@@ -0,0 +1,201 @@
|
||||
# seedbox.py
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
from trackers import trackers
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="Unit3D seedbox manager",
|
||||
description="Automagically add or remove seedbox entries on any Unit3D",
|
||||
usage=f"{Path(__file__).name} tracker username [ip] [options] ",
|
||||
epilog="For bugs/errors, please DM me on FnP or make an issue on GitHub",
|
||||
)
|
||||
|
||||
parser.add_argument("tracker", type=str, help="Tracker")
|
||||
parser.add_argument("username", type=str, help="Username")
|
||||
parser.add_argument("ip", nargs="?", type=str, help="IP of the seedbox")
|
||||
parser.add_argument(
|
||||
"--print",
|
||||
default=False,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Prints list of seedboxes",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--seedbox-name",
|
||||
type=str,
|
||||
default="PikminBox",
|
||||
help="Name of the seedbox (default: %(default)s)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--delete",
|
||||
default=False,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Deletes all old seedbox entries",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cookie-file",
|
||||
type=Path,
|
||||
default=Path(__file__).parent.joinpath("unit3d.cookies"),
|
||||
help="Cookies to be used",
|
||||
)
|
||||
parsed_args = parser.parse_args()
|
||||
|
||||
COOKIE_HEADER = ""
|
||||
|
||||
|
||||
def generateHeaders(host: str) -> dict:
|
||||
headers = {
|
||||
"Host": host,
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:132.0) Gecko/20100101 Firefox/132.0",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"Accept-Language": "en-US,en;q=0.5",
|
||||
"Origin": f"https://{host}",
|
||||
"DNT": "1",
|
||||
"Sec-GPC": "1",
|
||||
"Connection": "keep-alive",
|
||||
"Upgrade-Insecure-Requests": "1",
|
||||
}
|
||||
if COOKIE_HEADER:
|
||||
headers["Cookie"] = COOKIE_HEADER
|
||||
return headers
|
||||
|
||||
|
||||
def parseTracker(tracker: str) -> dict:
|
||||
for t in trackers:
|
||||
if tracker.lower() in [x.lower() for x in t.values()]:
|
||||
return t
|
||||
print(f'No tracker in database matched "{tracker}"')
|
||||
exit(1)
|
||||
|
||||
|
||||
def parseCookieFile(file: Path, domain: str) -> None:
|
||||
global COOKIE_HEADER
|
||||
with open(file, "r") as f:
|
||||
for line in f:
|
||||
if not re.match(r"^\#", line) and not re.match(r"^\s*$", line):
|
||||
lineFields = line.strip().split("\t")
|
||||
if domain in lineFields[0]:
|
||||
COOKIE_HEADER = f"{lineFields[5]}={lineFields[6]}"
|
||||
return
|
||||
print(f"No remember_web_* cookie was found in {file}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def getSeedboxes(domain: str) -> tuple[list[dict], str]:
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
f"https://{domain}/users/{parsed_args.username}/seedboxes",
|
||||
headers=generateHeaders(domain),
|
||||
)
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
html = resp.read().decode("utf-8")
|
||||
|
||||
token_match = re.search(
|
||||
r'<meta\s+name="csrf-token"\s+content="([^"]+)"', html, re.IGNORECASE
|
||||
)
|
||||
if not token_match:
|
||||
raise Exception("Could not find CSRF token on the page.")
|
||||
add_token = token_match.group(1)
|
||||
|
||||
pattern = re.compile(
|
||||
r'<td>\s*(.*?)\s*</td>\s*<td>\s*(.*?)\s*</td>.*?action="[^"]+/seedboxes/(\d+)".*?name="_token"\s+value="([^"]+)"',
|
||||
re.DOTALL | re.IGNORECASE,
|
||||
)
|
||||
|
||||
seedboxes = [
|
||||
{
|
||||
"name": m.group(1).strip(),
|
||||
"ip": m.group(2).strip(),
|
||||
"id": m.group(3),
|
||||
"token": m.group(4),
|
||||
}
|
||||
for m in pattern.finditer(html)
|
||||
]
|
||||
|
||||
return seedboxes, add_token
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error while getting seedboxes: {e}", flush=True)
|
||||
exit(1)
|
||||
|
||||
|
||||
def addSeedbox(domain: str, token: str) -> bool:
|
||||
try:
|
||||
data = urllib.parse.urlencode(
|
||||
{
|
||||
"_token": token,
|
||||
"name": parsed_args.seedbox_name,
|
||||
"ip": parsed_args.ip,
|
||||
}
|
||||
).encode("utf-8")
|
||||
|
||||
req = urllib.request.Request(
|
||||
f"https://{domain}/users/{parsed_args.username}/seedboxes",
|
||||
data=data,
|
||||
headers=generateHeaders(domain),
|
||||
)
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
html = resp.read().decode("utf-8")
|
||||
|
||||
error_match = re.search(
|
||||
r'<div[^>]*id="ERROR_COPY"[^>]*>(.*?)</div>',
|
||||
html,
|
||||
re.DOTALL | re.IGNORECASE,
|
||||
)
|
||||
if error_match:
|
||||
clean_error = re.sub(r"<[^>]+>", "", error_match.group(1))
|
||||
error_msg = " ".join(
|
||||
[x.strip() for x in clean_error.split("\n") if x.strip()]
|
||||
)
|
||||
raise Exception(error_msg)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print("Failed to add seedbox", flush=True)
|
||||
print(f"Error: {e}", flush=True)
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
tracker = parseTracker(parsed_args.tracker)
|
||||
domain = tracker["domain"]
|
||||
parseCookieFile(parsed_args.cookie_file, domain)
|
||||
|
||||
seedboxes, add_token = getSeedboxes(domain)
|
||||
|
||||
if parsed_args.print:
|
||||
print(f"Tracker: {tracker['name']}")
|
||||
print(f"\n| {'Name':<25}{'IP':<20}{'ID':<5}")
|
||||
print("| " + "-" * 53)
|
||||
for sbox in seedboxes:
|
||||
print(f"| {sbox['name']:<25}{sbox['ip']:<20}{sbox['id']:<5}")
|
||||
print()
|
||||
|
||||
if parsed_args.delete:
|
||||
for sbox in seedboxes:
|
||||
print(f'Deleting Seedbox: "{sbox["name"]}" ({sbox["ip"]})', flush=True)
|
||||
data = urllib.parse.urlencode(
|
||||
{"_token": sbox["token"], "_method": "DELETE"}
|
||||
).encode("utf-8")
|
||||
req = urllib.request.Request(
|
||||
f"https://{domain}/users/{parsed_args.username}/seedboxes/{sbox['id']}",
|
||||
data=data,
|
||||
headers=generateHeaders(domain),
|
||||
)
|
||||
urllib.request.urlopen(req)
|
||||
|
||||
if parsed_args.ip:
|
||||
if addSeedbox(domain, add_token):
|
||||
print(
|
||||
f"Successfully added Seedbox \"{parsed_args.seedbox_name}\" ({parsed_args.ip}) to {tracker['name']}",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user