phoenix_firmware_dumper/utils/downloaders/afh_dl.py

126 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from builtins import input
import re
import cgi
import json
import math
import clint
import argparse
import humanize
import requests
mirror_url = r"https://androidfilehost.com/libs/otf/mirrors.otf.php"
url_matchers = [
re.compile(r"fid=(?P<id>\d+)")
]
class Mirror:
def __init__(self, **entries):
self.__dict__.update(entries)
def download_file(url, fname, fsize):
dat = requests.get(url, stream=True)
with open(fname, 'wb') as f:
bar = clint.textui.progress.bar(dat.iter_content(chunk_size=4096),
expected_size=math.floor(fsize / 4096) + 1)
for chunk in bar:
f.write(chunk)
f.flush()
def get_file_info(url):
data = requests.head(url)
rsize = int(data.headers['Content-Length'])
size = humanize.naturalsize(rsize, binary=True)
ftype, fdata = cgi.parse_header(data.headers['Content-Disposition'])
return (rsize, size, fdata['filename'])
def download_servers(fid):
cook = requests.get("https://androidfilehost.com/?fid={}".format(fid))
post_data = {
"submit": "submit",
"action": "getdownloadmirrors",
"fid": fid
}
mirror_headers = {
"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/63.0.3239.132 Safari/537.36"),
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Referer": "https://androidfilehost.com/?fid={}".format(fid),
"X-MOD-SBB-CTYPE": "xhr",
"X-Requested-With": "XMLHttpRequest"
}
mirror_data = requests.post(mirror_url,
headers=mirror_headers,
data=post_data,
cookies=cook.cookies)
try:
mirror_json = json.loads(mirror_data.text)
if not mirror_json["STATUS"] == "1" or not mirror_json["CODE"] == "200":
return None
else:
mirror_opts = []
for mirror in mirror_json["MIRRORS"]:
mirror_opts.append(Mirror(**mirror))
return mirror_opts
except Exception as e:
return None
def match_url(url):
for pattern in url_matchers:
res = pattern.search(url)
if res is not None:
return res
return None
def main(link=None):
given_url = link
if not link:
given_url = input("Provide an AndroidFileHost URL: ")
file_match = match_url(given_url)
if file_match:
file_id = file_match.group('id')
print("Obtaining available download servers...")
servers = download_servers(file_id)
if servers == None:
print("Unable to retrieve download servers, you have probably been rate limited.")
return
svc = len(servers) - 1
for idx, server in enumerate(servers):
print('{}: {}'.format(idx, server.name))
choice = "0"
if not link:
choice = input("Choose a server to download from (0-{}): ".format(svc))
while not choice.isdigit() or int(choice) > svc or int(choice) < 0:
choice = input("Not a valid input, choose again: ")
server = servers[int(choice)]
print("Downloading from {}...".format(server.name))
rsize, size, fname = get_file_info(server.url)
print("Size: {} | Filename: {}".format(size, fname))
download_file(server.url, fname, rsize)
print("Downloading complete!")
else:
print("This does not appear to be a supported link.")
def entry_main():
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--interactive", action="store_true", default=False,
help="Run afh-dl in interactive mode.")
parser.add_argument("-l", "--link", action="store", nargs="?", type=str, default=None,
help="Link that should be downloaded.")
parsed = parser.parse_args()
if parsed.interactive == True:
main()
elif not parsed.link == None:
main(parsed.link)
else:
print("A link must be specified if not in interactive mode.")
if __name__ == '__main__':
entry_main()