You've already forked JapariBypass
Compare commits
12 Commits
debug
...
06b4bca63a
| Author | SHA1 | Date | |
|---|---|---|---|
| 06b4bca63a | |||
| 92e46a56f5 | |||
| ed77fc6b44 | |||
| 50144307ac | |||
| aee9c05cf4 | |||
| e4809e098b | |||
| 95e4057a49 | |||
| c454d7b8be | |||
| b398bcd054 | |||
| 6d8bf97e77 | |||
| c77290fd51 | |||
| 1a6e96ee47 |
29
README.md
Normal file
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Japari Bypass
|
||||||
|
Efficient KF3/DMM game launcher.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
- Python 3 and pip.
|
||||||
|
- DMM account that owns KF3
|
||||||
|
|
||||||
|
KF3 installed from DMM is recommended but not required.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
Download the files from this repo. Unzip them to a safe place.
|
||||||
|
|
||||||
|
Run `run_KF3.bat`, it will ask you for some information.
|
||||||
|
|
||||||
|
It will ask for the location of the KF3 executable. Generally this will be `C:\users\[your name]\KFP2G\けもフレ3.exe`.
|
||||||
|
|
||||||
|
Input your DMM email and then password when prompted, and set the desired trust level (more info on that below). If you choose not to use the public VPN, then you will need to enable your own Japanese VPN while logging in to the game.
|
||||||
|
|
||||||
|
If you make a mistake or you want to change login details, edit the `kfp2g.cfg` config file, or delete it to run the configuration again.
|
||||||
|
|
||||||
|
If KF3 needs to update, use `update_and_run_KF3.bat` and it will install any new updates.
|
||||||
|
|
||||||
|
## Trust levels
|
||||||
|
DMM uses Geo-blocking for some requests, that requires the user to be in Japan. This can be bypassed with a VPN. I have access to an OpenVPN server owned by HAV0X that can be used to bypass this restriction. However, this comes with several security vulnerabilities for the user:
|
||||||
|
- trust level 2 - Your login and password are sent to my device. The request is processed and sent through the VPN to DMM server, and my device sends you the response. I could access the information sent in the request if I wanted to (I will not do that though).
|
||||||
|
- trust level 1 - My device is used as a proxy. A connection is made between your device, my device, and DMM, with no way of me viewing the request data (that I know of). This takes longer.
|
||||||
|
- trust level 0 - You use your own VPN. The launcher will prompt you to enable/disable VPN when needed.
|
||||||
|
|
||||||
|
I do not intentionally view or store any data sent through my server. There is no guarantee of my and HAV0X's proxy server being active at any given time.
|
||||||
219
dmmBypass.py
219
dmmBypass.py
@@ -1,12 +1,57 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import wmi
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import requests
|
import pathlib
|
||||||
import dmmUpdater
|
import argparse
|
||||||
import subprocess
|
import subprocess
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from uuid import getnode
|
from uuid import getnode
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='DMM bypass script')
|
||||||
|
parser.add_argument('-g', '--game', type=str, help="DMM code name of the game", default="kfp2g")
|
||||||
|
parser.add_argument('-t', '--type', help="DMM game type (ACL/GCL)", default="GCL")
|
||||||
|
parser.add_argument('-u', '--update', help="Check for game update before launching", action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
def load_config(config_name):
|
||||||
|
with open(config_name, "rt", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
def save_config(config_name, config):
|
||||||
|
with open(config_name, 'wt', encoding="utf-8") as f:
|
||||||
|
json.dump(config, f, indent=1, ensure_ascii=False)
|
||||||
|
|
||||||
|
config_name = args.game + '.cfg'
|
||||||
|
|
||||||
|
if not os.path.exists(config_name):
|
||||||
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "requests", "beautifulsoup4", "PyPasser"])
|
||||||
|
config = {
|
||||||
|
"game_id" : args.game,
|
||||||
|
"file_path" : input('Enter full file path to KF3 .exe: ').strip('\"'),
|
||||||
|
"dmm_login" : input('DMM Login (email): '),
|
||||||
|
"dmm_password" : input('DMM Password: '),
|
||||||
|
}
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
trust_level = int(input('\t0 - Use your own VPN\n\t1 - Use Katboi\'s VPN as a proxy (slower, more secure)\n\t2 - Use Katboi\'s VPN to process the request (fastest, unsecure)\nTrust level (0-2): '))
|
||||||
|
if trust_level < 0 or trust_level > 2: raise Exception()
|
||||||
|
config["trust_level"] = trust_level
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
print("Value must be in 0-2 range")
|
||||||
|
|
||||||
|
save_config(config_name, config)
|
||||||
|
else:
|
||||||
|
config = load_config(config_name)
|
||||||
|
print(f'Loaded settings from {config_name}')
|
||||||
|
|
||||||
|
config["update_game"] = args.update
|
||||||
|
config["game_type"] = args.type
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import dmmUpdater
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from pypasser import reCaptchaV3
|
from pypasser import reCaptchaV3
|
||||||
|
|
||||||
@@ -20,8 +65,19 @@ def get_mac():
|
|||||||
mac = getnode()
|
mac = getnode()
|
||||||
return ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2)).lower()
|
return ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2)).lower()
|
||||||
|
|
||||||
def get_motherboard():
|
def get_game_root_path(user_path, game_dir, exe_name):
|
||||||
return wmi.WMI().Win32_BaseBoard()[0].SerialNumber
|
"""Return valid game install directory"""
|
||||||
|
path = pathlib.Path(user_path)
|
||||||
|
parts = list(path.parts)
|
||||||
|
if path.name == exe_name:
|
||||||
|
return str(path.parent.resolve())
|
||||||
|
elif game_dir in parts:
|
||||||
|
#get index of last occurence of game_dir in user path (+1)
|
||||||
|
dir_idx = len(parts) - parts[::-1].index(game_dir)
|
||||||
|
parts = parts[:dir_idx]
|
||||||
|
return str(pathlib.Path(*parts).resolve())
|
||||||
|
else:
|
||||||
|
raise Exception(f"Path to game files is incorrect! Ensure it points to {exe_name} or contains {game_dir}!")
|
||||||
|
|
||||||
def retrieve_login_token(session : requests.Session):
|
def retrieve_login_token(session : requests.Session):
|
||||||
try:
|
try:
|
||||||
@@ -54,92 +110,127 @@ def retrieve_auth_keys(login, password, token, captcha, session : requests.Sessi
|
|||||||
return cookies["login_secure_id"], cookies["login_session_id"]
|
return cookies["login_secure_id"], cookies["login_session_id"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed to log in:", e)
|
print("Failed to log in:", e)
|
||||||
|
return None, None
|
||||||
def retrieve_update_params(game_id, login_secure, login_session, use_proxy):
|
|
||||||
|
def agree_to_game_terms(game_id, trust_level):
|
||||||
try:
|
try:
|
||||||
print("Retrieving update file list")
|
print("Accepting updated game terms of use")
|
||||||
data = {"product_id":game_id,"game_type":"GCL","game_os":"win"}
|
|
||||||
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0", "Client-App": "DMMGamePlayer5", "Client-version": "5.3.12", "Content-Type": "application/json"}
|
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0", "Client-App": "DMMGamePlayer5", "Client-version": "5.3.12", "Content-Type": "application/json"}
|
||||||
cookies = {"login_secure_id":login_secure, "login_session_id":login_session}
|
url = "https://katworks.sytes.net/KF/Api/DMM/agreement" if trust_level == 2 else "https://katworks.sytes.net/proxy/agreement" if trust_level == 1 else "https://apidgp-gameplayer.games.dmm.com/v5/agreement/confirm/client"
|
||||||
url = "https://katworks.sytes.net/KF/Api/DMM/filelist" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/r2/filelist/cl"
|
data = {"product_id":game_id,"is_notification":False,"is_myapp":False}
|
||||||
result = requests.post(url, cookies=cookies, headers=headers, json=data)
|
result = requests.post(url, headers=headers, json=data)
|
||||||
result.raise_for_status()
|
result.raise_for_status()
|
||||||
data = result.json()["data"]
|
result_json = result.json()
|
||||||
game_version = data["latest_version"]
|
if result_json["result_code"] != 100:
|
||||||
print("Latest version:", game_version)
|
raise Exception(f'{result_json["result_code"]}: {result_json["error"]}')
|
||||||
file_list_url = data["file_list_url"]
|
return True
|
||||||
file_list_params = data["sign"]
|
|
||||||
file_list_params = "?" + file_list_params.replace(";", "&").replace("CloudFront-", "")
|
|
||||||
return file_list_url, file_list_params
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed to retrieve update file list:", e)
|
print("Failed to accept terms of use:", e)
|
||||||
|
return False
|
||||||
def retrieve_launch_params(game_id, mac_addr, hdd_serial, motherboard, login_secure, login_session, use_proxy):
|
|
||||||
|
def retrieve_launch_params(game_id, game_type, mac_addr, hdd_serial, motherboard, login_secure, login_session, trust_level, update_game):
|
||||||
try:
|
try:
|
||||||
print("Retrieving launch arguments")
|
print("Retrieving launch arguments")
|
||||||
data = {"product_id":game_id,"game_type":"GCL","game_os":"win","launch_type":"LIB","mac_address":mac_addr,"hdd_serial":hdd_serial,"motherboard":motherboard,"user_os":"win"}
|
data = {"product_id":game_id,"game_type":game_type,"game_os":"win","launch_type":"LIB","mac_address":mac_addr,"hdd_serial":hdd_serial,"motherboard":motherboard,"user_os":"win"}
|
||||||
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0", "Client-App": "DMMGamePlayer5", "Client-version": "5.3.12", "Content-Type": "application/json"}
|
headers = {"User-Agent": "DMMGamePlayer5-Win/5.3.12 Electron/32.1.0", "Client-App": "DMMGamePlayer5", "Client-version": "5.3.12", "Content-Type": "application/json"}
|
||||||
cookies = {"login_secure_id":login_secure, "login_session_id":login_session}
|
cookies = {"login_secure_id":login_secure, "login_session_id":login_session}
|
||||||
url = "https://katworks.sytes.net/KF/Api/DMM/launch" if use_proxy else "https://apidgp-gameplayer.games.dmm.com/v5/r2/launch/cl"
|
if update_game:
|
||||||
|
url = "https://katworks.sytes.net/KF/Api/DMM/update" if trust_level == 2 else "https://katworks.sytes.net/proxy/launchAndUpdate" if trust_level == 1 else "https://apidgp-gameplayer.games.dmm.com/v5/r2/launch/cl"
|
||||||
|
else:
|
||||||
|
url = "https://katworks.sytes.net/KF/Api/DMM/launch" if trust_level == 2 else "https://katworks.sytes.net/proxy/launch" if trust_level == 1 else "https://apidgp-gameplayer.games.dmm.com/v5/launch/cl"
|
||||||
result = requests.post(url, cookies=cookies, headers=headers, json=data)
|
result = requests.post(url, cookies=cookies, headers=headers, json=data)
|
||||||
result.raise_for_status()
|
result.raise_for_status()
|
||||||
data = result.json()["data"]
|
result_json = result.json()
|
||||||
return data["execute_args"]
|
if result_json["result_code"] == 308:
|
||||||
|
if agree_to_game_terms(game_id, trust_level):
|
||||||
|
result = requests.post(url, cookies=cookies, headers=headers, json=data)
|
||||||
|
result.raise_for_status()
|
||||||
|
result_json = result.json()
|
||||||
|
if result_json["result_code"] != 100:
|
||||||
|
raise Exception(f'{result_json["result_code"]}: {result_json["error"]}')
|
||||||
|
else:
|
||||||
|
raise Exception("Failed to agree to updated game terms of use. Use the DMM app to confirm.")
|
||||||
|
elif result_json["result_code"] != 100:
|
||||||
|
raise Exception(f'{result_json["result_code"]}: {result_json["error"]}')
|
||||||
|
data = result_json["data"]
|
||||||
|
return data
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Failed to retrieve launch arguments:", e)
|
print("Failed to retrieve launch arguments:", e)
|
||||||
|
|
||||||
def main(args):
|
def main(config):
|
||||||
if len(args) != 7:
|
#required arguments
|
||||||
print("Usage:",
|
game_id = config["game_id"]
|
||||||
"\tpython dmmBypass.py game_id game_path email password update_game use_proxy",
|
game_type = config["game_type"]
|
||||||
"\t- game_id: DMM code name of the game",
|
exe_location = config["file_path"]
|
||||||
"\t- game_path: full path to the game .exe. Wrap in \" if there are spaces in the path",
|
login = urllib.parse.quote_plus(config["dmm_login"])
|
||||||
"\t- email, password: dmm credentials",
|
password = urllib.parse.quote_plus(config["dmm_password"])
|
||||||
"\t- update_game: \"true\" to check for game update before launching",
|
#optional arguments
|
||||||
"\t- use_proxy: \"true\" to send required request through Katboi VPN. Otherwise use your own VPN",
|
update_game = config.get("update_game", False)
|
||||||
"\texample: python dmmBypass.py kfp2g \"D:\Games\KFP2G\けもフレ3.exe\" kat@email.com abc123 true", sep="\n")
|
trust_level = config.get("trust_level", 0)
|
||||||
return
|
saved_login = config.get("saved_login", None)
|
||||||
|
#dmm requires these values
|
||||||
game_id = args[1]
|
|
||||||
exe_location = args[2]
|
|
||||||
login = urllib.parse.quote_plus(args[3])
|
|
||||||
password = urllib.parse.quote_plus(args[4])
|
|
||||||
update_game = args[5].lower() == "true"
|
|
||||||
use_proxy = args[6].lower() == "true"
|
|
||||||
mac_addr = get_mac()
|
mac_addr = get_mac()
|
||||||
hdd_serial = get_hash('')
|
hdd_serial = get_hash('') #DMM sends an empty hash as well
|
||||||
motherboard = get_hash(get_motherboard())
|
motherboard = get_hash(getnode()) #actual moterboard serial is unknown, but this works
|
||||||
|
|
||||||
|
current_time = datetime.now()
|
||||||
|
|
||||||
with requests.Session() as session:
|
with requests.Session() as session:
|
||||||
token = retrieve_login_token(session)
|
if saved_login is not None:
|
||||||
captcha = retrieve_captcha_token()
|
login_expiration = datetime.fromtimestamp(saved_login["expiration"])
|
||||||
|
if login_expiration < current_time:
|
||||||
|
print("Login data has expired")
|
||||||
|
saved_login = None
|
||||||
|
|
||||||
if token == None or captcha == None:
|
if saved_login is not None:
|
||||||
return
|
login_secure, login_session = saved_login["login_secure"], saved_login["login_session"]
|
||||||
|
print("Loaded login data from previous session")
|
||||||
|
else:
|
||||||
|
token = retrieve_login_token(session)
|
||||||
|
captcha = retrieve_captcha_token()
|
||||||
|
|
||||||
login_secure, login_session = retrieve_auth_keys(login, password, token, captcha, session)
|
if token == None or captcha == None:
|
||||||
|
|
||||||
if not use_proxy: input("Enable VPN now and press Enter")
|
|
||||||
|
|
||||||
if update_game:
|
|
||||||
file_list_url, file_access_params = retrieve_update_params(game_id, login_secure, login_session, use_proxy)
|
|
||||||
if file_list_url == None or file_access_params == None:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
execute_args = retrieve_launch_params(game_id, mac_addr, hdd_serial, motherboard, login_secure, login_session, use_proxy)
|
login_secure, login_session = retrieve_auth_keys(login, password, token, captcha, session)
|
||||||
|
if login_secure == None or login_session == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
login_expiration = int((current_time + timedelta(days=364)).timestamp()) #expire in less than a year
|
||||||
|
config["saved_login"] = saved_login = {"login_secure" : login_secure, "login_session" : login_session, "expiration": login_expiration}
|
||||||
|
del(config["update_game"])
|
||||||
|
save_config(config_name, config)
|
||||||
|
|
||||||
|
if trust_level == 0: input("Enable VPN now and press Enter")
|
||||||
|
|
||||||
|
#execute_args, file_list_url, file_access_params
|
||||||
|
launch_data : dict = retrieve_launch_params(game_id, game_type, mac_addr, hdd_serial, motherboard, login_secure, login_session, trust_level, update_game)
|
||||||
|
|
||||||
|
execute_args : str = launch_data.get("execute_args", None)
|
||||||
if execute_args == None:
|
if execute_args == None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if update_game:
|
||||||
|
file_list_url = launch_data.get("file_list_url", None)
|
||||||
|
file_list_params : str = launch_data.get("sign", None)
|
||||||
|
if file_list_url == None or file_list_params == None:
|
||||||
|
return
|
||||||
|
|
||||||
if not use_proxy: input("Disable VPN now and press Enter")
|
print("Latest version:", launch_data["latest_version"])
|
||||||
|
file_list_params = "?" + file_list_params.replace(";", "&").replace("CloudFront-", "")
|
||||||
|
|
||||||
|
exec_name = launch_data["exec_file_name"]
|
||||||
|
install_dir = launch_data["install_dir"]
|
||||||
|
game_root_path = get_game_root_path(exe_location, install_dir, exec_name)
|
||||||
|
|
||||||
|
if trust_level == 0: input("Disable VPN now and press Enter")
|
||||||
|
|
||||||
if update_game:
|
if update_game:
|
||||||
dmmUpdater.update_game(os.path.dirname(exe_location), file_list_url, file_access_params)
|
dmmUpdater.update_game(game_root_path, file_list_url, file_list_params)
|
||||||
|
|
||||||
print("Starting game")
|
print("Starting game")
|
||||||
args = [exe_location] + execute_args.split()
|
args = [os.path.join(game_root_path, exec_name)] + execute_args.split()
|
||||||
print(args)
|
|
||||||
subprocess.Popen(args, start_new_session=True)
|
subprocess.Popen(args, start_new_session=True)
|
||||||
input("Done. Press enter to exit")
|
input("Done. Press enter to exit")
|
||||||
|
|
||||||
args = sys.argv
|
main(config)
|
||||||
main(args)
|
|
||||||
@@ -1,24 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
import requests
|
import requests
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from urllib.request import urlretrieve
|
from urllib.request import urlretrieve
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import sys
|
|
||||||
def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+
|
|
||||||
"""https://stackoverflow.com/questions/3160699/python-progress-bar"""
|
|
||||||
count = len(it)
|
|
||||||
if count == 0: return
|
|
||||||
def show(j):
|
|
||||||
x = int(size*j/count)
|
|
||||||
print("{}[{}{}] {}/{}".format(prefix, "#"*x, "."*(size-x), j, count),
|
|
||||||
end='\r', file=out, flush=True)
|
|
||||||
show(0)
|
|
||||||
for i, item in enumerate(it):
|
|
||||||
yield item
|
|
||||||
show(i+1)
|
|
||||||
print("\n", flush=True, file=out)
|
|
||||||
|
|
||||||
def get_file_list(url):
|
def get_file_list(url):
|
||||||
url = "https://apidgp-gameplayer.games.dmm.com" + url
|
url = "https://apidgp-gameplayer.games.dmm.com" + url
|
||||||
print("Retrieving file list from " + url)
|
print("Retrieving file list from " + url)
|
||||||
@@ -41,40 +28,69 @@ def get_file_hash(file_path):
|
|||||||
def update_game(game_path, files_url, files_param):
|
def update_game(game_path, files_url, files_param):
|
||||||
print("Updating game")
|
print("Updating game")
|
||||||
server_url, server_files = get_file_list(files_url)
|
server_url, server_files = get_file_list(files_url)
|
||||||
server_file_dict = {file["local_path"]: file for file in server_files}
|
server_file_dict = {str(Path(game_path, file["local_path"].lstrip('/')).resolve()): file for file in server_files}
|
||||||
|
local_file_dict = {str(Path(dp, f).resolve()): "" for dp, dn, filenames in os.walk(game_path) for f in filenames}
|
||||||
local_files = [os.path.join(dp, f).replace("\\", "/") for dp, dn, filenames in os.walk(game_path) for f in filenames]
|
|
||||||
local_file_dict = {"/" + os.path.relpath(r, game_path).replace("\\", "/"): {"abs_path":r, "hash":""} for r in local_files}
|
|
||||||
|
|
||||||
files_to_download = []
|
files_to_download = []
|
||||||
files_to_delete = []
|
files_to_delete = []
|
||||||
for server_file_key in server_file_dict.keys():
|
for abs_file_path in server_file_dict.keys():
|
||||||
server_file = server_file_dict[server_file_key]
|
server_file = server_file_dict[abs_file_path]
|
||||||
|
|
||||||
if server_file_key in local_file_dict:
|
if abs_file_path in local_file_dict:
|
||||||
local_file = local_file_dict[server_file_key]
|
|
||||||
if server_file["force_delete_flg"]:
|
if server_file["force_delete_flg"]:
|
||||||
files_to_delete.append(local_file["abs_path"])
|
files_to_delete.append(abs_file_path)
|
||||||
else:
|
else:
|
||||||
local_file["hash"] = get_file_hash(local_file["abs_path"])
|
local_file_hash = get_file_hash(abs_file_path)
|
||||||
|
|
||||||
if server_file["check_hash_flg"] and local_file["hash"] == server_file["hash"]:
|
if server_file["check_hash_flg"] and local_file_hash == server_file["hash"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param
|
download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param
|
||||||
download_path = game_path.replace("\\", "/") + server_file_key
|
files_to_download.append({"url":download_url, "path":abs_file_path})
|
||||||
files_to_download.append({"url":download_url, "path":download_path})
|
|
||||||
else:
|
else:
|
||||||
download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param
|
download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param
|
||||||
download_path = game_path.replace("\\", "/") + server_file_key
|
files_to_download.append({"url":download_url, "path":abs_file_path})
|
||||||
files_to_download.append({"url":download_url, "path":download_path})
|
|
||||||
|
|
||||||
print("Files to download:", len(files_to_download))
|
print("Files to download:", len(files_to_download))
|
||||||
|
|
||||||
for file in progressbar(files_to_download, "Downloading: ", 40):
|
count = len(files_to_download)
|
||||||
url, path = file["url"], file["path"]
|
if count > 0:
|
||||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
index = 0
|
||||||
urlretrieve(url, path)
|
max_len = 0
|
||||||
|
def show(j, downloaded, total_size):
|
||||||
|
nonlocal max_len
|
||||||
|
x = int(40*j/count)
|
||||||
|
string = "Downloading: [{}{}] {}/{} ({}/{})".format("#"*x, "."*(40-x), j, count, min(downloaded,total_size), total_size)
|
||||||
|
max_len = max(len(string), max_len)
|
||||||
|
print(string.ljust(max_len, ' '), end='\r', file=sys.stdout, flush=True)
|
||||||
|
|
||||||
|
retries = 3
|
||||||
|
show(0, 0, 0)
|
||||||
|
while index < len(files_to_download):
|
||||||
|
try:
|
||||||
|
file = files_to_download[index]
|
||||||
|
url, path = file["url"], file["path"]
|
||||||
|
|
||||||
|
response = requests.get(url, timeout=10, stream=True)
|
||||||
|
total_size = int(response.headers.get("content-length", 0))
|
||||||
|
block_size = 1024 * 1024
|
||||||
|
downloaded = 0
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||||
|
with open(path, 'wb') as out_file:
|
||||||
|
for data in response.iter_content(block_size):
|
||||||
|
out_file.write(data)
|
||||||
|
downloaded += len(data)
|
||||||
|
show(index + 1, downloaded, total_size)
|
||||||
|
index += 1
|
||||||
|
retries = 3
|
||||||
|
except Exception as e:
|
||||||
|
print(e, "retrying")
|
||||||
|
retries -= 1
|
||||||
|
if retries == 0:
|
||||||
|
print(f'Retry for file {file["url"]} failed 3 times')
|
||||||
|
return False
|
||||||
|
print("\n", flush=True, file=sys.stdout)
|
||||||
|
|
||||||
# #files_to_delete is unused until fully tested
|
# #files_to_delete is unused until fully tested
|
||||||
# for file in files_to_delete:
|
# for file in files_to_delete:
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
beautifulsoup4
|
|
||||||
PyPasser
|
|
||||||
wmi
|
|
||||||
34
run_KF3.bat
34
run_KF3.bat
@@ -1,35 +1,3 @@
|
|||||||
@echo off
|
@echo off
|
||||||
chcp 65001
|
python dmmBypass.py -g kfp2g
|
||||||
setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
set file_name="kfp2g.cfg"
|
|
||||||
|
|
||||||
IF NOT EXIST %file_name% (
|
|
||||||
set /p null="Make sure python is installed. In next step, required packages will be installed. Press Enter to continue"
|
|
||||||
pip install -r requirements.txt
|
|
||||||
set /p file_path=Enter full file path to KF3 .exe:
|
|
||||||
set /p dmm_login=DMM Login:
|
|
||||||
set /p dmm_password=DMM Password:
|
|
||||||
set /p confirm="Your login tokens will be sent through Katboi's VPN machine, is that ok? Personal VPN is required if not (yes/no):"
|
|
||||||
if /i "!confirm!"=="yes" (
|
|
||||||
set use_proxy=true
|
|
||||||
) else (
|
|
||||||
set use_proxy=false
|
|
||||||
)
|
|
||||||
echo !file_path!> %file_name%
|
|
||||||
echo !dmm_login!>> %file_name%
|
|
||||||
echo !dmm_password!>> %file_name%
|
|
||||||
echo !use_proxy!>> %file_name%
|
|
||||||
) ELSE (
|
|
||||||
< %file_name% (
|
|
||||||
set /p file_path=
|
|
||||||
set /p dmm_login=
|
|
||||||
set /p dmm_password=
|
|
||||||
set /p use_proxy=
|
|
||||||
)
|
|
||||||
echo Loaded settings from %file_name%
|
|
||||||
)
|
|
||||||
|
|
||||||
python dmmBypass.py kfp2g %file_path% %dmm_login% %dmm_password% false %use_proxy%
|
|
||||||
|
|
||||||
pause
|
pause
|
||||||
@@ -1,35 +1,3 @@
|
|||||||
@echo off
|
@echo off
|
||||||
chcp 65001
|
python dmmBypass.py -g kfp2g -u
|
||||||
setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
set file_name="kfp2g.cfg"
|
|
||||||
|
|
||||||
IF NOT EXIST %file_name% (
|
|
||||||
set /p null="Make sure python is installed. In next step, required packages will be installed. Press Enter to continue"
|
|
||||||
pip install -r requirements.txt
|
|
||||||
set /p file_path=Enter full file path to KF3 .exe:
|
|
||||||
set /p dmm_login=DMM Login:
|
|
||||||
set /p dmm_password=DMM Password:
|
|
||||||
set /p confirm="Your login tokens will be sent through Katboi's VPN machine, is that ok? Personal VPN is required if not (yes/no):"
|
|
||||||
if /i "!confirm!"=="yes" (
|
|
||||||
set use_proxy=true
|
|
||||||
) else (
|
|
||||||
set use_proxy=false
|
|
||||||
)
|
|
||||||
echo !file_path!> %file_name%
|
|
||||||
echo !dmm_login!>> %file_name%
|
|
||||||
echo !dmm_password!>> %file_name%
|
|
||||||
echo !use_proxy!>> %file_name%
|
|
||||||
) ELSE (
|
|
||||||
< %file_name% (
|
|
||||||
set /p file_path=
|
|
||||||
set /p dmm_login=
|
|
||||||
set /p dmm_password=
|
|
||||||
set /p use_proxy=
|
|
||||||
)
|
|
||||||
echo Loaded settings from %file_name%
|
|
||||||
)
|
|
||||||
|
|
||||||
python dmmBypass.py kfp2g %file_path% %dmm_login% %dmm_password% true %use_proxy%
|
|
||||||
|
|
||||||
pause
|
pause
|
||||||
Reference in New Issue
Block a user