Advertisement
Guest User

Untitled

a guest
Mar 8th, 2023
709
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 19.24 KB | None | 0 0
  1. import requests
  2. import os
  3. import bs4
  4. import zipfile
  5. import re
  6. import shutil
  7. import json
  8.  
  9. # Itch Data
  10. GAME_URL = 'https://hellbrain.itch.io/9-months-with-ellie'
  11. GAME_UPLOAD_ID = 3378179
  12.  
  13. # Game paths
  14. GAME_DOWNLOAD_FILE_PATH = 'game.zip'
  15. EXTRACTED_GAME_PATH = '.'
  16.  
  17. # HD asset paths
  18. ASSETS_DOWNLOAD_PATH = 'assets.zip'
  19. EXTRACTED_ASSETS_PATH = '.'
  20.  
  21. # Kemono data
  22. KEMONO_PLATFORM = 'patreon'
  23. KEMONO_USER_ID = 56930602
  24. KEMONO_POST_ID = 74537908
  25.  
  26. DRIVE_URL_PATTERN = re.compile('https://drive.google.com/file/d/(.*)/')
  27. CHUNK_SIZE = 1024 * 1024
  28.  
  29. # Image Asset Map
  30. IMAGE_MAP = {
  31.     # Scenes Dir
  32.     #
  33.     # Original Size: 1224 x 624
  34.     # HD Size:       4883 x 5444
  35.     'Scenes/M1 Cooking.png': 'M1Cooking.png',
  36.     # Original Size: 816  x 1248
  37.     # HD Size:       2933 x 5520
  38.     'Scenes/M2 Shower.png': 'M2 Shower.png',
  39.     # Original Size: 1224 x 624
  40.     # HD Size:       5037 x 5150
  41.     'Scenes/M3 Work.png': 'M3Work.png',
  42.     # Original Size: 1224 x  624
  43.     # HD Size:       5766 x 4291
  44.     'Scenes/M4 Bath.png': 'M4Bath.png',
  45.     # Original Size: 1224 x 624
  46.     # HD Size:       5051 x 5153
  47.     'Scenes/M5 Game.png': 'M5Game.png',
  48.     # Original Size: 1224 x 624
  49.     # HD Size:       5796 x 3103
  50.     'Scenes/M6 Couch.png': 'M6Couch.png',
  51.     # Original Size: 816  x 1248
  52.     # HD Size:       3241 x 4438
  53.     'Scenes/M7 Walk.png': 'M7Walk.png',
  54.     # Original Size: 1224 x 624
  55.     # HD Size:       4844 x 4645
  56.     'Scenes/M8 Checkup.png': 'M8Checkup.png',
  57.      # Original Size: 1224 x 624
  58.      # HD Size:       4791 x 4984
  59.     'Scenes/M9 Bed.png': 'M9Bed.png',
  60.      # Original Size: 1224 x 624
  61.      # HD Size:       5603 x 4430
  62.     'Scenes/M10 Goblins.png': 'M10Goblins.png',
  63.    
  64.     # Mirror Selfies Dir
  65.     #
  66.     # Original Size: 816  x 1248
  67.     # HD Size:       3307 x 4857
  68.     'Mirror Selfies/MirrorScenes 0.png': 'Mirror1.png',
  69.     'Mirror Selfies/MirrorScenes 1.png': 'Mirror2.png',
  70.     'Mirror Selfies/MirrorScenes 2.png': 'Mirror3.png',
  71.     'Mirror Selfies/MirrorScenes 3.png': 'Mirror4.png',
  72.     'Mirror Selfies/MirrorScenes 4.png': 'Mirror5.png',
  73.     'Mirror Selfies/MirrorScenes 5.png': 'Mirror6.png',
  74.     'Mirror Selfies/MirrorScenes 6.png': 'Mirror7.png',
  75.     'Mirror Selfies/MirrorScenes 7.png': 'Mirror8.png',
  76.     'Mirror Selfies/MirrorScenes 8.png': 'Mirror9.png',
  77.     'Mirror Selfies/MirrorScenes 9.png': 'Mirror10.png',
  78.     'Mirror Selfies/MirrorScenes 10.png': 'Mirror11.png',
  79. }
  80.  
  81. MAP_NAME_PATTERN = re.compile('Map\d\d\d.json')
  82.  
  83. # RPGM Command Codes
  84. SHOW_PICTURE_CODE = 231
  85. MOVE_PICTURE_CODE = 232
  86.  
  87. GAME_TITLE = '9 Months With Ellie'
  88.  
  89. PRELOADER_SCRIPT = """
  90.    var images = [
  91.        'M1Cooking',
  92.        'M2 Shower',
  93.        'M3Work',
  94.        'M4Bath',
  95.        'M5Game',
  96.        'M6Couch',
  97.        'M7Walk',
  98.        'M8Checkup',
  99.        'M9Bed',
  100.        'M10Goblins',
  101.                
  102.        'Mirror1',
  103.        'Mirror2',
  104.        'Mirror3',
  105.        'Mirror4',
  106.        'Mirror5',
  107.        'Mirror6',
  108.        'Mirror7',
  109.        'Mirror8',
  110.        'Mirror9',
  111.        'Mirror10',
  112.        'Mirror11',
  113.    ];
  114.            
  115.    for(var i = 0; i < images.length; i++) {
  116.        ImageManager.loadPicture(images[i]);
  117.    }
  118. """
  119.  
  120. def download_itch_io_game(url, upload_id, out_file):
  121.     with requests.Session() as session:
  122.         game_page = None
  123.         with session.get(GAME_URL) as r:
  124.             r.raise_for_status()
  125.             game_page = bs4.BeautifulSoup(
  126.                 r.text,
  127.                 features = 'html.parser'
  128.             )
  129.        
  130.         csrf_token = game_page.select('meta[name=csrf_token]')[0]['value']
  131.         upload_ids = [int(element['data-upload_id']) for element in game_page.select('.upload a')]
  132.        
  133.         assert upload_id in upload_ids
  134.        
  135.         download_url = None
  136.         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:
  137.             r.raise_for_status()
  138.             json = r.json()
  139.             download_url = json['url']
  140.        
  141.         with session.get(download_url, stream=True) as r:
  142.             r.raise_for_status()
  143.             for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
  144.                 out_file.write(chunk)
  145.                
  146. def download_kemono_file(platform, user_id, post_id, out_file):
  147.     with requests.Session() as session:
  148.         post_page = None
  149.         with session.get(f'https://kemono.party/{platform}/user/{user_id}/post/{post_id}') as r:
  150.             r.raise_for_status()
  151.             post_page = bs4.BeautifulSoup(
  152.                 r.text,
  153.                 features = 'html.parser'
  154.             )
  155.         drive_url = post_page.select('.post__files a')[0]['href']
  156.         file_id = DRIVE_URL_PATTERN.search(drive_url).group(1)
  157.        
  158.         drive_download_page = None
  159.         with session.get(f'https://drive.google.com/uc?id={file_id}&export=download') as r:
  160.             r.raise_for_status()
  161.             drive_download_page = bs4.BeautifulSoup(
  162.                 r.text,
  163.                 features = 'html.parser'
  164.             )
  165.         download_url = drive_download_page.select('form')[0]['action']
  166.        
  167.         with session.get(download_url, stream=True) as r:
  168.             r.raise_for_status()
  169.             for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
  170.                 out_file.write(chunk)
  171.            
  172.  
  173. def main():
  174.     game_path = f'{EXTRACTED_GAME_PATH}/9 Months With Ellie'
  175.     assets_path = f'{EXTRACTED_ASSETS_PATH}/9MWE Deluxe Folder'
  176.  
  177.     has_game_download_zip = os.path.exists(GAME_DOWNLOAD_FILE_PATH)
  178.     has_extracted_game = os.path.exists(game_path)
  179.     has_assets_zip = os.path.exists(ASSETS_DOWNLOAD_PATH)
  180.     has_extracted_assets = os.path.exists(assets_path)
  181.    
  182.     if not has_game_download_zip and not has_extracted_game:
  183.         print('Download game zip not detected, downloading...')
  184.         with open(GAME_DOWNLOAD_FILE_PATH, 'wb') as f:
  185.             download_itch_io_game(
  186.                 url = GAME_URL,
  187.                 upload_id = GAME_UPLOAD_ID,
  188.                 out_file = f
  189.             )
  190.            
  191.     if not has_extracted_game:
  192.         print('Extracted game folder not detected, extracting..')
  193.         with zipfile.ZipFile(GAME_DOWNLOAD_FILE_PATH, 'r') as zip:
  194.             zip.extractall(EXTRACTED_GAME_PATH)
  195.            
  196.     if not has_assets_zip and not has:
  197.         print('Download assets zip not detected, downloading...')
  198.         with open(ASSETS_DOWNLOAD_PATH, 'wb') as f:
  199.             download_kemono_file(
  200.                 platform = KEMONO_PLATFORM,
  201.                 user_id = KEMONO_USER_ID,
  202.                 post_id = KEMONO_POST_ID,
  203.                 out_file = f
  204.             )
  205.            
  206.     if not has_extracted_assets:
  207.         print('Extracted assets folder not detected, extracting..')
  208.         with zipfile.ZipFile(ASSETS_DOWNLOAD_PATH, 'r') as zip:
  209.             zip.extractall(EXTRACTED_ASSETS_PATH)
  210.            
  211.     # Begin patching
  212.     print('Patching...')
  213.    
  214.     # Fix https://github.com/rpgtkoolmv/corescript/pull/191
  215.     print('=> Patching rpg_core.js...')
  216.     with open(f'{game_path}/www/js/rpg_core.js', 'r+') as f:
  217.         content = f.read()
  218.         content = content.replace('if (this._skipCount === 0)', 'if (this._skipCount <= 0)')
  219.         f.truncate(0)
  220.         f.seek(0)
  221.         f.write(content)
  222.        
  223.     # Patch package.json
  224.     print('=> Patching package.json...')
  225.     with open(f'{game_path}/package.json', 'r+') as f:        
  226.         package = json.loads(f.read())
  227.        
  228.         # Technically not valid,
  229.         # but what used to be there wasn't either so idc
  230.         package['name'] = GAME_TITLE
  231.         package['window']['title'] = GAME_TITLE
  232.         content = json.dumps(package, indent=4)
  233.        
  234.         f.truncate(0)
  235.         f.seek(0)
  236.         f.write(content)
  237.        
  238.     # Insert Image preloader
  239.     print('=> Patching main.js...')
  240.     with open(f'{game_path}/www/js/main.js', 'r+') as f:
  241.         content = f.read()
  242.         content = content.replace('SceneManager.run(Scene_Boot);', f'SceneManager.run(Scene_Boot );{PRELOADER_SCRIPT}')
  243.         f.truncate(0)
  244.         f.seek(0)
  245.         f.write(content)
  246.        
  247.     # Rename game executable
  248.     print('=> Renaming game executable...')
  249.     try:
  250.         os.rename(f'{game_path}/Game.exe', f'{game_path}/{GAME_TITLE}.exe')
  251.     except FileNotFoundError:
  252.         # Allow missing exe so that repatching a patched build will probably work
  253.         pass
  254.        
  255.     # Copy images
  256.     print('=> Copying HD images...')
  257.     for (hd_asset_path, game_asset_path) in IMAGE_MAP.items():
  258.         hd_asset_path = f'{assets_path}/REDRAW/{hd_asset_path}'
  259.         game_asset_path = f'{game_path}/www/img/pictures/{game_asset_path}'
  260.        
  261.         print(f'  => {hd_asset_path} -> {game_asset_path}')
  262.         shutil.copy2(hd_asset_path, game_asset_path)
  263.        
  264.     # Patch Map files for new image sizes
  265.     print('=> Patching Maps...')
  266.     data_path = f'{game_path}/www/data'
  267.     for filename in os.listdir(data_path):
  268.         if not MAP_NAME_PATTERN.match(filename):
  269.             continue
  270.         map_path = f'{data_path}/{filename}'
  271.         print(f'  => {map_path}')
  272.        
  273.         with open(map_path, 'r+') as f:
  274.             map = json.loads(f.read())
  275.             for event in map['events']:
  276.                 if event is None:
  277.                     continue
  278.                    
  279.                 for page in event['pages']:
  280.                     last_image = None
  281.                     for command in page['list']:
  282.                         parameters = command['parameters']
  283.                        
  284.                         mirror_x_value = 0
  285.                         mirror_scale_value = 100.0 / (4857.0 / 1248.0)
  286.                        
  287.                         scene_1_scale_value = 100.0 / 5.9
  288.                         scene_2_scale_value = 100.0 / (2933.0 / 816.0)
  289.                         scene_3_scale_value = 100.0 / 6.0
  290.                         scene_4_scale_value = 100.0 / 6.0
  291.                         scene_5_scale_value = 100.0 / 6.0
  292.                         scene_6_scale_value = 100.0 / 4.9
  293.                         scene_7_scale_value = 100.0 / 3.95
  294.                         scene_8_scale_value = 100.0 / 5.9
  295.                         scene_9_scale_value = 100.0 / 5.85
  296.                         scene_10_scale_value = 100.0 / 5.8
  297.                        
  298.                         if command['code'] == SHOW_PICTURE_CODE:
  299.                             # Command: ShowPicture
  300.                             # parameters[1]: name
  301.                             # parameters[4]: x
  302.                             # parameters[5]: y
  303.                             # parameters[6]: scaleX
  304.                             # parameters[7]: scaleY
  305.                            
  306.                             image_name = parameters[1]
  307.                             if image_name.startswith('Mirror'):
  308.                                 parameters[4] = mirror_x_value
  309.                                 parameters[6] = mirror_scale_value
  310.                                 parameters[7] = mirror_scale_value
  311.                                
  312.                                 last_image = 'mirror'
  313.                             elif image_name == 'M1Cooking':
  314.                                 parameters[4] = 0
  315.                                 parameters[5] = -300
  316.                                 parameters[6] = scene_1_scale_value
  317.                                 parameters[7] = scene_1_scale_value
  318.  
  319.                                 last_image = 'scene1'
  320.                             elif image_name == 'M2 Shower':
  321.                                 parameters[5] = -900
  322.                                 parameters[6] = scene_2_scale_value
  323.                                 parameters[7] = scene_2_scale_value
  324.                                
  325.                                 last_image = 'scene2'
  326.                             elif image_name == 'M3Work':
  327.                                 parameters[4] = 0
  328.                                 parameters[5] = -200
  329.                                 parameters[6] = scene_3_scale_value
  330.                                 parameters[7] = scene_3_scale_value
  331.                                
  332.                                 last_image = 'scene3'
  333.                             elif image_name == 'M4Bath':
  334.                                 parameters[6] = scene_4_scale_value
  335.                                 parameters[7] = scene_4_scale_value
  336.                                
  337.                                 last_image = 'scene4'
  338.                             elif image_name == 'M5Game':
  339.                                 parameters[4] = -20
  340.                                 parameters[5] = -230
  341.                                 parameters[6] = scene_5_scale_value
  342.                                 parameters[7] = scene_5_scale_value
  343.                                
  344.                                 last_image = 'scene5'
  345.                             elif image_name == 'M6Couch':
  346.                                 parameters[6] = scene_6_scale_value
  347.                                 parameters[7] = scene_6_scale_value
  348.                                
  349.                                 last_image = 'scene6'
  350.                             elif image_name == 'M7Walk':
  351.                                 parameters[6] = scene_7_scale_value
  352.                                 parameters[7] = scene_7_scale_value
  353.                                
  354.                                 last_image = 'scene7'
  355.                             elif image_name == 'M8Checkup':
  356.                                 parameters[4] = 0
  357.                                 parameters[5] = -100
  358.                                 parameters[6] = scene_8_scale_value
  359.                                 parameters[7] = scene_8_scale_value
  360.                                
  361.                                 last_image = 'scene8'
  362.                             elif image_name == 'M9Bed':
  363.                                 parameters[4] = 0
  364.                                 parameters[5] = -230
  365.                                 parameters[6] = scene_9_scale_value
  366.                                 parameters[7] = scene_9_scale_value
  367.                                
  368.                                 last_image = 'scene9'
  369.                             elif image_name == 'M10Goblins':
  370.                                 parameters[4] = -150
  371.                                 parameters[5] = -80
  372.                                 parameters[6] = scene_10_scale_value
  373.                                 parameters[7] = scene_10_scale_value
  374.                                
  375.                                 last_image = 'scene10'
  376.                                
  377.                         elif command['code'] == MOVE_PICTURE_CODE:
  378.                             # Command: MovePicture
  379.                             # parameters[4]: x
  380.                             # parameters[5]: y
  381.                             # parameters[6]: scaleX, default 100
  382.                             # parameters[7]: scaleY, default 100
  383.                            
  384.                             if last_image == 'mirror':
  385.                                 parameters[4] = mirror_x_value
  386.                                 parameters[5] = -150
  387.                                 parameters[6] = mirror_scale_value
  388.                                 parameters[7] = mirror_scale_value
  389.                                    
  390.                                 last_image = None
  391.                             elif last_image == 'scene1':
  392.                                 parameters[4] = 0
  393.                                 parameters[5] = -50
  394.                                 parameters[6] = scene_1_scale_value
  395.                                 parameters[7] = scene_1_scale_value
  396.                                
  397.                                 last_image = None
  398.                             elif last_image == 'scene2':
  399.                                 parameters[5] = -200
  400.                                 parameters[6] = scene_2_scale_value
  401.                                 parameters[7] = scene_2_scale_value
  402.                                
  403.                                 last_image = None
  404.                             elif last_image == 'scene3':
  405.                                 parameters[4] = 0
  406.                                 parameters[5] = 0
  407.                                 parameters[6] = scene_3_scale_value
  408.                                 parameters[7] = scene_3_scale_value
  409.                                
  410.                                 last_image = None
  411.                             elif last_image == 'scene4':
  412.                                 parameters[4] = -140
  413.                                 parameters[6] = scene_4_scale_value
  414.                                 parameters[7] = scene_4_scale_value
  415.                                
  416.                                 last_image = None
  417.                             elif last_image == 'scene5':
  418.                                 parameters[4] = -20
  419.                                 parameters[5] = 0
  420.                                 parameters[6] = scene_5_scale_value
  421.                                 parameters[7] = scene_5_scale_value
  422.                                
  423.                                 last_image = None
  424.                                
  425.                             elif last_image == 'scene6':
  426.                                 parameters[4] = -350
  427.                                 parameters[6] = scene_6_scale_value
  428.                                 parameters[7] = scene_6_scale_value
  429.                                
  430.                                 last_image = None
  431.                             elif last_image == 'scene7':
  432.                                 parameters[5] = -450
  433.                                 parameters[6] = scene_7_scale_value
  434.                                 parameters[7] = scene_7_scale_value
  435.                                
  436.                                 last_image = None
  437.                                
  438.                             elif last_image == 'scene8':
  439.                                 parameters[4] = 0
  440.                                 parameters[5] = 0
  441.                                 parameters[6] = scene_8_scale_value
  442.                                 parameters[7] = scene_8_scale_value
  443.                                
  444.                                 last_image = None
  445.                                
  446.                             elif last_image == 'scene9':
  447.                                 parameters[4] = 0
  448.                                 parameters[5] = -130
  449.                                 parameters[6] = scene_9_scale_value
  450.                                 parameters[7] = scene_9_scale_value
  451.                                
  452.                                 last_image = None
  453.                                
  454.                             elif last_image == 'scene10':
  455.                                 parameters[4] = 0
  456.                                 parameters[5] = -80
  457.                                 parameters[6] = scene_10_scale_value
  458.                                 parameters[7] = scene_10_scale_value
  459.                                
  460.                                 last_image = None
  461.                                  
  462.             content = json.dumps(map)
  463.             f.truncate(0)
  464.             f.seek(0)
  465.             f.write(content)
  466.        
  467.     print('Done.')
  468.    
  469. if __name__ == '__main__':
  470.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement