Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import requests
- import os
- import bs4
- import zipfile
- import re
- import shutil
- import json
- # Itch Data
- GAME_URL = 'https://hellbrain.itch.io/9-months-with-ellie'
- GAME_UPLOAD_ID = 3378179
- # Game paths
- GAME_DOWNLOAD_FILE_PATH = 'game.zip'
- EXTRACTED_GAME_PATH = '.'
- # HD asset paths
- ASSETS_DOWNLOAD_PATH = 'assets.zip'
- EXTRACTED_ASSETS_PATH = '.'
- # Kemono data
- KEMONO_PLATFORM = 'patreon'
- KEMONO_USER_ID = 56930602
- KEMONO_POST_ID = 74537908
- DRIVE_URL_PATTERN = re.compile('https://drive.google.com/file/d/(.*)/')
- CHUNK_SIZE = 1024 * 1024
- # Image Asset Map
- IMAGE_MAP = {
- # Scenes Dir
- #
- # Original Size: 1224 x 624
- # HD Size: 4883 x 5444
- 'Scenes/M1 Cooking.png': 'M1Cooking.png',
- # Original Size: 816 x 1248
- # HD Size: 2933 x 5520
- 'Scenes/M2 Shower.png': 'M2 Shower.png',
- # Original Size: 1224 x 624
- # HD Size: 5037 x 5150
- 'Scenes/M3 Work.png': 'M3Work.png',
- # Original Size: 1224 x 624
- # HD Size: 5766 x 4291
- 'Scenes/M4 Bath.png': 'M4Bath.png',
- # Original Size: 1224 x 624
- # HD Size: 5051 x 5153
- 'Scenes/M5 Game.png': 'M5Game.png',
- # Original Size: 1224 x 624
- # HD Size: 5796 x 3103
- 'Scenes/M6 Couch.png': 'M6Couch.png',
- # Original Size: 816 x 1248
- # HD Size: 3241 x 4438
- 'Scenes/M7 Walk.png': 'M7Walk.png',
- # Original Size: 1224 x 624
- # HD Size: 4844 x 4645
- 'Scenes/M8 Checkup.png': 'M8Checkup.png',
- # Original Size: 1224 x 624
- # HD Size: 4791 x 4984
- 'Scenes/M9 Bed.png': 'M9Bed.png',
- # Original Size: 1224 x 624
- # HD Size: 5603 x 4430
- 'Scenes/M10 Goblins.png': 'M10Goblins.png',
- # Mirror Selfies Dir
- #
- # Original Size: 816 x 1248
- # HD Size: 3307 x 4857
- 'Mirror Selfies/MirrorScenes 0.png': 'Mirror1.png',
- 'Mirror Selfies/MirrorScenes 1.png': 'Mirror2.png',
- 'Mirror Selfies/MirrorScenes 2.png': 'Mirror3.png',
- 'Mirror Selfies/MirrorScenes 3.png': 'Mirror4.png',
- 'Mirror Selfies/MirrorScenes 4.png': 'Mirror5.png',
- 'Mirror Selfies/MirrorScenes 5.png': 'Mirror6.png',
- 'Mirror Selfies/MirrorScenes 6.png': 'Mirror7.png',
- 'Mirror Selfies/MirrorScenes 7.png': 'Mirror8.png',
- 'Mirror Selfies/MirrorScenes 8.png': 'Mirror9.png',
- 'Mirror Selfies/MirrorScenes 9.png': 'Mirror10.png',
- 'Mirror Selfies/MirrorScenes 10.png': 'Mirror11.png',
- }
- MAP_NAME_PATTERN = re.compile('Map\d\d\d.json')
- # RPGM Command Codes
- SHOW_PICTURE_CODE = 231
- MOVE_PICTURE_CODE = 232
- GAME_TITLE = '9 Months With Ellie'
- PRELOADER_SCRIPT = """
- var images = [
- 'M1Cooking',
- 'M2 Shower',
- 'M3Work',
- 'M4Bath',
- 'M5Game',
- 'M6Couch',
- 'M7Walk',
- 'M8Checkup',
- 'M9Bed',
- 'M10Goblins',
- 'Mirror1',
- 'Mirror2',
- 'Mirror3',
- 'Mirror4',
- 'Mirror5',
- 'Mirror6',
- 'Mirror7',
- 'Mirror8',
- 'Mirror9',
- 'Mirror10',
- 'Mirror11',
- ];
- for(var i = 0; i < images.length; i++) {
- ImageManager.loadPicture(images[i]);
- }
- """
- def download_itch_io_game(url, upload_id, out_file):
- with requests.Session() as session:
- game_page = None
- with session.get(GAME_URL) as r:
- r.raise_for_status()
- game_page = bs4.BeautifulSoup(
- r.text,
- features = 'html.parser'
- )
- csrf_token = game_page.select('meta[name=csrf_token]')[0]['value']
- upload_ids = [int(element['data-upload_id']) for element in game_page.select('.upload a')]
- assert upload_id in upload_ids
- download_url = None
- with session.post(f'{url}/file/{upload_id}?source=view_game&as_props=1&after_download_lightbox=true', data={'csrf_token': csrf_token}) as r:
- r.raise_for_status()
- json = r.json()
- download_url = json['url']
- with session.get(download_url, stream=True) as r:
- r.raise_for_status()
- for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
- out_file.write(chunk)
- def download_kemono_file(platform, user_id, post_id, out_file):
- with requests.Session() as session:
- post_page = None
- with session.get(f'https://kemono.party/{platform}/user/{user_id}/post/{post_id}') as r:
- r.raise_for_status()
- post_page = bs4.BeautifulSoup(
- r.text,
- features = 'html.parser'
- )
- drive_url = post_page.select('.post__files a')[0]['href']
- file_id = DRIVE_URL_PATTERN.search(drive_url).group(1)
- drive_download_page = None
- with session.get(f'https://drive.google.com/uc?id={file_id}&export=download') as r:
- r.raise_for_status()
- drive_download_page = bs4.BeautifulSoup(
- r.text,
- features = 'html.parser'
- )
- download_url = drive_download_page.select('form')[0]['action']
- with session.get(download_url, stream=True) as r:
- r.raise_for_status()
- for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
- out_file.write(chunk)
- def main():
- game_path = f'{EXTRACTED_GAME_PATH}/9 Months With Ellie'
- assets_path = f'{EXTRACTED_ASSETS_PATH}/9MWE Deluxe Folder'
- has_game_download_zip = os.path.exists(GAME_DOWNLOAD_FILE_PATH)
- has_extracted_game = os.path.exists(game_path)
- has_assets_zip = os.path.exists(ASSETS_DOWNLOAD_PATH)
- has_extracted_assets = os.path.exists(assets_path)
- if not has_game_download_zip and not has_extracted_game:
- print('Download game zip not detected, downloading...')
- with open(GAME_DOWNLOAD_FILE_PATH, 'wb') as f:
- download_itch_io_game(
- url = GAME_URL,
- upload_id = GAME_UPLOAD_ID,
- out_file = f
- )
- if not has_extracted_game:
- print('Extracted game folder not detected, extracting..')
- with zipfile.ZipFile(GAME_DOWNLOAD_FILE_PATH, 'r') as zip:
- zip.extractall(EXTRACTED_GAME_PATH)
- if not has_assets_zip and not has:
- print('Download assets zip not detected, downloading...')
- with open(ASSETS_DOWNLOAD_PATH, 'wb') as f:
- download_kemono_file(
- platform = KEMONO_PLATFORM,
- user_id = KEMONO_USER_ID,
- post_id = KEMONO_POST_ID,
- out_file = f
- )
- if not has_extracted_assets:
- print('Extracted assets folder not detected, extracting..')
- with zipfile.ZipFile(ASSETS_DOWNLOAD_PATH, 'r') as zip:
- zip.extractall(EXTRACTED_ASSETS_PATH)
- # Begin patching
- print('Patching...')
- # Fix https://github.com/rpgtkoolmv/corescript/pull/191
- print('=> Patching rpg_core.js...')
- with open(f'{game_path}/www/js/rpg_core.js', 'r+') as f:
- content = f.read()
- content = content.replace('if (this._skipCount === 0)', 'if (this._skipCount <= 0)')
- f.truncate(0)
- f.seek(0)
- f.write(content)
- # Patch package.json
- print('=> Patching package.json...')
- with open(f'{game_path}/package.json', 'r+') as f:
- package = json.loads(f.read())
- # Technically not valid,
- # but what used to be there wasn't either so idc
- package['name'] = GAME_TITLE
- package['window']['title'] = GAME_TITLE
- content = json.dumps(package, indent=4)
- f.truncate(0)
- f.seek(0)
- f.write(content)
- # Insert Image preloader
- print('=> Patching main.js...')
- with open(f'{game_path}/www/js/main.js', 'r+') as f:
- content = f.read()
- content = content.replace('SceneManager.run(Scene_Boot);', f'SceneManager.run(Scene_Boot );{PRELOADER_SCRIPT}')
- f.truncate(0)
- f.seek(0)
- f.write(content)
- # Rename game executable
- print('=> Renaming game executable...')
- try:
- os.rename(f'{game_path}/Game.exe', f'{game_path}/{GAME_TITLE}.exe')
- except FileNotFoundError:
- # Allow missing exe so that repatching a patched build will probably work
- pass
- # Copy images
- print('=> Copying HD images...')
- for (hd_asset_path, game_asset_path) in IMAGE_MAP.items():
- hd_asset_path = f'{assets_path}/REDRAW/{hd_asset_path}'
- game_asset_path = f'{game_path}/www/img/pictures/{game_asset_path}'
- print(f' => {hd_asset_path} -> {game_asset_path}')
- shutil.copy2(hd_asset_path, game_asset_path)
- # Patch Map files for new image sizes
- print('=> Patching Maps...')
- data_path = f'{game_path}/www/data'
- for filename in os.listdir(data_path):
- if not MAP_NAME_PATTERN.match(filename):
- continue
- map_path = f'{data_path}/{filename}'
- print(f' => {map_path}')
- with open(map_path, 'r+') as f:
- map = json.loads(f.read())
- for event in map['events']:
- if event is None:
- continue
- for page in event['pages']:
- last_image = None
- for command in page['list']:
- parameters = command['parameters']
- mirror_x_value = 0
- mirror_scale_value = 100.0 / (4857.0 / 1248.0)
- scene_1_scale_value = 100.0 / 5.9
- scene_2_scale_value = 100.0 / (2933.0 / 816.0)
- scene_3_scale_value = 100.0 / 6.0
- scene_4_scale_value = 100.0 / 6.0
- scene_5_scale_value = 100.0 / 6.0
- scene_6_scale_value = 100.0 / 4.9
- scene_7_scale_value = 100.0 / 3.95
- scene_8_scale_value = 100.0 / 5.9
- scene_9_scale_value = 100.0 / 5.85
- scene_10_scale_value = 100.0 / 5.8
- if command['code'] == SHOW_PICTURE_CODE:
- # Command: ShowPicture
- # parameters[1]: name
- # parameters[4]: x
- # parameters[5]: y
- # parameters[6]: scaleX
- # parameters[7]: scaleY
- image_name = parameters[1]
- if image_name.startswith('Mirror'):
- parameters[4] = mirror_x_value
- parameters[6] = mirror_scale_value
- parameters[7] = mirror_scale_value
- last_image = 'mirror'
- elif image_name == 'M1Cooking':
- parameters[4] = 0
- parameters[5] = -300
- parameters[6] = scene_1_scale_value
- parameters[7] = scene_1_scale_value
- last_image = 'scene1'
- elif image_name == 'M2 Shower':
- parameters[5] = -900
- parameters[6] = scene_2_scale_value
- parameters[7] = scene_2_scale_value
- last_image = 'scene2'
- elif image_name == 'M3Work':
- parameters[4] = 0
- parameters[5] = -200
- parameters[6] = scene_3_scale_value
- parameters[7] = scene_3_scale_value
- last_image = 'scene3'
- elif image_name == 'M4Bath':
- parameters[6] = scene_4_scale_value
- parameters[7] = scene_4_scale_value
- last_image = 'scene4'
- elif image_name == 'M5Game':
- parameters[4] = -20
- parameters[5] = -230
- parameters[6] = scene_5_scale_value
- parameters[7] = scene_5_scale_value
- last_image = 'scene5'
- elif image_name == 'M6Couch':
- parameters[6] = scene_6_scale_value
- parameters[7] = scene_6_scale_value
- last_image = 'scene6'
- elif image_name == 'M7Walk':
- parameters[6] = scene_7_scale_value
- parameters[7] = scene_7_scale_value
- last_image = 'scene7'
- elif image_name == 'M8Checkup':
- parameters[4] = 0
- parameters[5] = -100
- parameters[6] = scene_8_scale_value
- parameters[7] = scene_8_scale_value
- last_image = 'scene8'
- elif image_name == 'M9Bed':
- parameters[4] = 0
- parameters[5] = -230
- parameters[6] = scene_9_scale_value
- parameters[7] = scene_9_scale_value
- last_image = 'scene9'
- elif image_name == 'M10Goblins':
- parameters[4] = -150
- parameters[5] = -80
- parameters[6] = scene_10_scale_value
- parameters[7] = scene_10_scale_value
- last_image = 'scene10'
- elif command['code'] == MOVE_PICTURE_CODE:
- # Command: MovePicture
- # parameters[4]: x
- # parameters[5]: y
- # parameters[6]: scaleX, default 100
- # parameters[7]: scaleY, default 100
- if last_image == 'mirror':
- parameters[4] = mirror_x_value
- parameters[5] = -150
- parameters[6] = mirror_scale_value
- parameters[7] = mirror_scale_value
- last_image = None
- elif last_image == 'scene1':
- parameters[4] = 0
- parameters[5] = -50
- parameters[6] = scene_1_scale_value
- parameters[7] = scene_1_scale_value
- last_image = None
- elif last_image == 'scene2':
- parameters[5] = -200
- parameters[6] = scene_2_scale_value
- parameters[7] = scene_2_scale_value
- last_image = None
- elif last_image == 'scene3':
- parameters[4] = 0
- parameters[5] = 0
- parameters[6] = scene_3_scale_value
- parameters[7] = scene_3_scale_value
- last_image = None
- elif last_image == 'scene4':
- parameters[4] = -140
- parameters[6] = scene_4_scale_value
- parameters[7] = scene_4_scale_value
- last_image = None
- elif last_image == 'scene5':
- parameters[4] = -20
- parameters[5] = 0
- parameters[6] = scene_5_scale_value
- parameters[7] = scene_5_scale_value
- last_image = None
- elif last_image == 'scene6':
- parameters[4] = -350
- parameters[6] = scene_6_scale_value
- parameters[7] = scene_6_scale_value
- last_image = None
- elif last_image == 'scene7':
- parameters[5] = -450
- parameters[6] = scene_7_scale_value
- parameters[7] = scene_7_scale_value
- last_image = None
- elif last_image == 'scene8':
- parameters[4] = 0
- parameters[5] = 0
- parameters[6] = scene_8_scale_value
- parameters[7] = scene_8_scale_value
- last_image = None
- elif last_image == 'scene9':
- parameters[4] = 0
- parameters[5] = -130
- parameters[6] = scene_9_scale_value
- parameters[7] = scene_9_scale_value
- last_image = None
- elif last_image == 'scene10':
- parameters[4] = 0
- parameters[5] = -80
- parameters[6] = scene_10_scale_value
- parameters[7] = scene_10_scale_value
- last_image = None
- content = json.dumps(map)
- f.truncate(0)
- f.seek(0)
- f.write(content)
- print('Done.')
- if __name__ == '__main__':
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement