Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Jupyter notebook file to extract the archives in Doki Doki Literature Club
{
"cells": [
{
"cell_type": "code",
"execution_count": 193,
"metadata": {},
"outputs": [],
"source": [
"from pickle import loads\n",
"from codecs import decode\n",
"import os\n",
"\n",
"os.chdir(os.path.expanduser(\"~/Desktop/\"))\n",
"\n",
"game_dir = os.environ.get(\"GAME_DIR\", os.path.expanduser(\"~/Library/Application Support/Steam/steamapps/common/Doki Doki Literature Club/game/\"))\n",
"output_dir = os.environ.get(\"OUTPUT_DIR\", 'output')\n",
"\n",
"rpa_paths = []\n",
"for filename in os.listdir(game_dir):\n",
" if filename.endswith(\".rpa\"):\n",
" rpa_paths.append(os.path.join(game_dir, filename))"
]
},
{
"cell_type": "code",
"execution_count": 194,
"metadata": {},
"outputs": [],
"source": [
"# based on renpy's loader.index_archives function\n",
"# https://github.com/renpy/renpy/blob/master/renpy/loader.py\n",
"\n",
"def index_archive(rpa_path):\n",
" prefix = os.path.basename(rpa_path)[:-4]\n",
" with open(rpa_path, \"rb\") as f:\n",
" l = f.readline()\n",
" if l.startswith(b\"RPA-3.0 \"):\n",
" offset = int(l[8:24], 16)\n",
" key = int(l[25:33], 16)\n",
" f.seek(offset)\n",
" index = loads(decode(f.read(), encoding=\"zlib\"))\n",
" for k in index.keys():\n",
" if len(index[k][0]) == 2:\n",
" index[k] = [ (offset ^ key, dlen ^ key) for offset, dlen in index[k] ]\n",
" else:\n",
" index[k] = [ (offset ^ key, dlen ^ key, start) for offset, dlen, start in index[k] ]\n",
"\n",
" return (prefix, index)\n",
" else:\n",
" raise Exception('bad format: {}'.format(l))"
]
},
{
"cell_type": "code",
"execution_count": 201,
"metadata": {},
"outputs": [],
"source": [
"# based on renpy's SubFile class\n",
"# https://github.com/renpy/renpy/blob/master/renpy/loader.py\n",
"\n",
"class SubFile(object):\n",
"\n",
" def __init__(self, fn, base, length, start):\n",
" self.fn = fn\n",
"\n",
" self.f = None\n",
"\n",
" self.base = base\n",
" self.offset = 0\n",
" self.length = length\n",
" \n",
" if type(start) is str:\n",
" start = start.encode('utf-8')\n",
" \n",
" self.start = start\n",
"\n",
" if not self.start:\n",
" self.name = fn\n",
" else:\n",
" self.name = None\n",
"\n",
" def open(self):\n",
" self.f = open(self.fn, \"rb\")\n",
" self.f.seek(self.base)\n",
"\n",
" def __enter__(self):\n",
" return self\n",
"\n",
" def __exit__(self, _type, value, tb):\n",
" self.close()\n",
" return False\n",
"\n",
" def read(self, length=None):\n",
"\n",
" if self.f is None:\n",
" self.open()\n",
"\n",
" maxlength = self.length - self.offset\n",
"\n",
" if length is not None:\n",
" length = min(length, maxlength)\n",
" else:\n",
" length = maxlength\n",
"\n",
" rv1 = self.start[self.offset:self.offset + length]\n",
" length -= len(rv1)\n",
" self.offset += len(rv1)\n",
"\n",
" if length:\n",
" rv2 = self.f.read(length)\n",
" self.offset += len(rv2)\n",
" else:\n",
" rv2 = b\"\"\n",
"\n",
" return (rv1 + rv2)\n",
"\n",
" def close(self):\n",
" if self.f is not None:\n",
" self.f.close()\n",
" self.f = None"
]
},
{
"cell_type": "code",
"execution_count": 202,
"metadata": {},
"outputs": [],
"source": [
"# based on renpy's loader.load_code function\n",
"# https://github.com/renpy/renpy/blob/master/renpy/loader.py\n",
"\n",
"def build_file(prefix, loc_tuple):\n",
" filename = prefix + '.rpa'\n",
" rpa_path = os.path.join(game_dir, filename)\n",
" if len(loc_tuple) == 2:\n",
" offset, dlen = loc_tuple\n",
" start = b''\n",
" else:\n",
" offset, dlen, start = loc_tuple\n",
" return SubFile(rpa_path, offset, dlen, start)"
]
},
{
"cell_type": "code",
"execution_count": 205,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"output/bgm/heartbeat.ogg\n",
"output/bgm/10.ogg\n",
"output/sfx/slap.ogg\n",
"output/bgm/5_ghost.ogg\n",
"output/sfx/glitch1.ogg\n",
"output/bgm/m1.ogg\n",
"output/bgm/monika-end.ogg\n",
"output/sfx/eyes.ogg\n",
"output/sfx/mscare.ogg\n",
"output/bgm/g2.ogg\n",
"output/bgm/1.ogg\n",
"output/bgm/6.ogg\n",
"output/bgm/6s.ogg\n",
"output/bgm/4.ogg\n",
"output/bgm/5.ogg\n",
"output/sfx/stab.ogg\n",
"output/bgm/g1.ogg\n",
"output/bgm/5_sayori.ogg\n",
"output/gui/font/VerilySerifMono.otf\n",
"output/sfx/interference.ogg\n",
"output/sfx/crack.ogg\n",
"output/bgm/2.ogg\n",
"output/gui/sfx/baa.ogg\n",
"output/bgm/7g.ogg\n",
"output/bgm/s_kill_early.ogg\n",
"output/sfx/s_kill_glitch1.ogg\n",
"output/sfx/yuri-kill.ogg\n",
"output/gui/sfx/select.ogg\n",
"output/sfx/monikapound.ogg\n",
"output/sfx/closet-close.ogg\n",
"output/gui/sfx/select_glitch.ogg\n",
"output/bgm/7.ogg\n",
"output/bgm/4g.ogg\n",
"output/sfx/fall.ogg\n",
"output/sfx/closet-open.ogg\n",
"output/bgm/3.ogg\n",
"output/bgm/9g.ogg\n",
"output/bgm/3g.ogg\n",
"output/sfx/pageflip.ogg\n",
"output/bgm/d.ogg\n",
"output/sfx/smack.ogg\n",
"output/bgm/6g.ogg\n",
"output/sfx/gnid.ogg\n",
"output/bgm/ghostmenu.ogg\n",
"output/sfx/glitch3.ogg\n",
"output/bgm/9.ogg\n",
"output/sfx/glitch2.ogg\n",
"output/sfx/giggle.ogg\n",
"output/bgm/5_yuri.ogg\n",
"output/bgm/10-yuri.ogg\n",
"output/sfx/run.ogg\n",
"output/bgm/2g.ogg\n",
"output/bgm/end-voice.ogg\n",
"output/sfx/fall2.ogg\n",
"output/bgm/2g2.ogg\n",
"output/bgm/credits.ogg\n",
"output/bgm/5_yuri2.ogg\n",
"output/bgm/3g2.ogg\n",
"output/bgm/5_natsuki.ogg\n",
"output/gui/sfx/hover.ogg\n",
"output/bgm/monika-start.ogg\n",
"output/bgm/8.ogg\n",
"output/bgm/6r.ogg\n",
"output/bgm/6o.ogg\n",
"output/bgm/5_monika.ogg\n",
"output/gui/font/y1.ttf\n",
"output/gui/font/RifficFree-Bold.ttf\n",
"output/gui/font/m1.TTF\n",
"output/gui/font/Halogen.ttf\n",
"output/gui/font/y2.ttf\n",
"output/gui/font/F25_Bank_Printer.ttf\n",
"output/gui/font/Aller_Rg.ttf\n",
"output/gui/font/y3.ttf\n",
"output/gui/font/s1.ttf\n",
"output/gui/font/n1.ttf\n",
"output/gui/font/Vera.ttf\n",
"output/gui/slider/horizontal_idle_thumb.png\n",
"output/images/bg/splash.png\n",
"output/images/natsuki/old2/4t.png\n",
"output/images/yuri/2l.png\n",
"output/images/cg/credits/4b.png\n",
"output/images/cg/monika/room.png\n",
"output/images/yuri/3.png\n",
"output/images/monika/q.png\n",
"output/gui/menu_art_m.png\n",
"output/gui/poemgame/y_sticker_1.png\n",
"output/gui/poemgame/s_sticker_1.png\n",
"output/gui/menu_art_s_break.png\n",
"output/gui/namebox.png\n",
"output/images/natsuki/p.png\n",
"output/images/bg/poem-glitch1.png\n",
"output/gui/menu_art_s_ghost.png\n",
"output/gui/menu_particle.png\n",
"output/images/natsuki/scream.png\n",
"output/images/yuri/glitch3.png\n",
"output/images/natsuki/u.png\n",
"output/images/cg/y_cg1_exp2.png\n",
"output/images/sayori/v.png\n",
"output/images/natsuki/old2/1l.png\n",
"output/images/yuri/f.png\n",
"output/images/cg/monika/monika_bg_glitch.png\n",
"output/images/cg/n_cg3_exp2.png\n",
"output/images/cg/credits/1.png\n",
"output/images/bg/residential.png\n",
"output/images/menu/frame-old.png\n",
"output/images/natsuki/w.png\n",
"output/gui/end.png\n",
"output/images/sayori/x.png\n",
"output/images/monika/old2/2l.png\n",
"output/images/cg/y_cg2_dust2.png\n",
"output/gui/slider/vertical_hover_bar.png\n",
"output/images/bg/corridor.png\n",
"output/images/poem_special/poem_special1.png\n",
"output/images/sayori/d.png\n",
"output/gui/button/quick_hover_background.png\n",
"output/images/sayori/1br.png\n",
"output/images/poem_special/poem_special4.png\n",
"output/images/monika/old/2.png\n",
"output/images/cg/credits/6b.png\n",
"output/images/sayori/b.png\n",
"output/images/bg/glitch.jpg\n",
"output/gui/poemgame/m_sticker_1.png\n",
"output/images/sayori/old2/2l.png\n",
"output/images/monika/l.png\n",
"output/images/natsuki/3.png\n",
"output/gui/overlay/confirm_glitch2.png\n",
"output/images/yuri/stab/3.png\n",
"output/images/cg/n_cg1_bg.png\n",
"output/images/natsuki/old2/3.png\n",
"output/images/bg/end-glitch4.JPG\n",
"output/images/sayori/end-glitch2.png\n",
"output/images/yuri/glitch1.png\n",
"output/images/cg/n_cg2_exp2.png\n",
"output/images/yuri/c.png\n",
"output/images/monika/o.png\n",
"output/images/bg/noise3.jpg\n",
"output/gui/poemgame/y_sticker_2.png\n",
"output/images/cg/n_cg3_cake.png\n",
"output/images/natsuki/2te.png\n",
"output/gui/notify.png\n",
"output/images/yuri/a.png\n",
"output/images/menu/credits_temp.png\n",
"output/images/natsuki/ghost1.png\n",
"output/images/sayori/old/5.png\n",
"output/images/natsuki/2tc.png\n",
"output/images/natsuki/old/2.png\n",
"output/images/natsuki/1br.png\n",
"output/images/monika/a.png\n",
"output/images/natsuki/s.png\n",
"output/gui/scrollbar/horizontal_poem_bar.png\n",
"output/images/sayori/old/3.png\n",
"output/images/natsuki/c.png\n",
"output/images/monika/g.png\n",
"output/images/bg/house.jpg\n",
"output/images/natsuki/old2/2l.png\n",
"output/gui/poemgame/y_sticker_cut_2.png\n",
"output/images/sayori/3d.png\n",
"output/images/yuri/2r.png\n",
"output/images/cg/monika/maskb.png\n",
"output/images/poem_special/poem_special2.png\n",
"output/images/yuri/zc.png\n",
"output/images/cg/y_cg1_base.png\n",
"output/images/yuri/stab/4_wipe.png\n",
"output/images/natsuki/ghost_blood.png\n",
"output/images/bg/noise2.jpg\n",
"output/images/poem_special/poem_special9.png\n",
"output/gui/scrollbar/vertical_hover_bar.png\n",
"output/images/bg/class.png\n",
"output/images/cg/s_cg2_base1.png\n",
"output/images/yuri/h.png\n",
"output/gui/scrollbar/horizontal_hover_thumb.png\n",
"output/images/cg/credits/5.png\n",
"output/images/yuri/d2.png\n",
"output/images/yuri/e2.png\n",
"output/images/sayori/2r.png\n",
"output/images/yuri/0b.png\n",
"output/gui/button/slot_idle_background.png\n",
"output/images/yuri/o.png\n",
"output/images/monika/k.png\n",
"output/images/natsuki/ghost3.png\n",
"output/images/cg/credits/3.png\n",
"output/gui/scrollbar/horizontal_hover_bar.png\n",
"output/images/yuri/y6.png\n",
"output/images/sayori/1bl.png\n",
"output/gui/scrollbar/horizontal_idle_bar.png\n",
"output/images/monika/i.png\n",
"output/images/yuri/u.png\n",
"output/images/monika/1l.png\n",
"output/images/sayori/h.png\n",
"output/images/yuri/3b.png\n",
"output/images/sayori/a.png\n",
"output/images/cg/y_cg2_nochoc.png\n",
"output/images/cg/n_cg1_exp5.png\n",
"output/images/bg/noise4.jpg\n",
"output/images/sayori/i.png\n",
"output/images/natsuki/q.png\n",
"output/images/bg/splash-glitch2.png\n",
"output/images/cg/s_cg2_exp3.png\n",
"output/images/cg/monika/monika_bg_highlight.png\n",
"output/images/poem_special/poem_special5b.png\n",
"output/images/yuri/y2.png\n",
"output/images/sayori/o.png\n",
"output/images/yuri/e.png\n",
"output/gui/poemgame/y_sticker_cut_1.png\n",
"output/images/cg/y_kill/3a.png\n",
"output/images/natsuki/eye.png\n",
"output/images/sayori/noface1b.png\n",
"output/images/cg/s_kill_bg2.png\n",
"output/images/yuri/glitch4.png\n",
"output/images/natsuki/1bl.png\n",
"output/images/yuri/b2.png\n",
"output/images/bg/warning.png\n",
"output/images/yuri/v.png\n",
"output/images/cg/y_cg2.png\n",
"output/images/poem_special/poem_special11.png\n",
"output/images/bg/club-skill.png\n",
"output/gui/menu_art_n.png\n",
"output/images/monika/g4.png\n",
"output/images/cg/n_cg1_exp1.png\n",
"output/images/menu/credits_temp1.png\n",
"output/gui/scrollbar/vertical_poem_thumb.png\n",
"output/images/cg/monika/child.png\n",
"output/images/natsuki/old/3.png\n",
"output/images/bg/sayori_bedroom.png\n",
"output/images/poem_special/poem_special8.png\n",
"output/images/yuri/g.png\n",
"output/images/yuri/eyes1.png\n",
"output/images/yuri/hisui.png\n",
"output/images/monika/1r.png\n",
"output/images/yuri/stab/2.png\n",
"output/images/sayori/t.png\n",
"output/images/cg/s_cg2_exp1.png\n",
"output/images/cg/s_cg1.png\n",
"output/images/bg/end-glitch2.JPG\n",
"output/images/cg/y_kill/3b.png\n",
"output/images/bg/eyes.png\n",
"output/images/monika/old/4.png\n",
"output/images/natsuki/f.png\n",
"output/gui/button/quick_idle_background.png\n",
"output/images/natsuki/2l.png\n",
"output/images/monika/e.png\n",
"output/images/bg/veinmaskb.png\n",
"output/images/sayori/old/4.png\n",
"output/images/yuri/m.png\n",
"output/images/yuri/eyes2.png\n",
"output/images/yuri/c2.png\n",
"output/images/sayori/g.png\n",
"output/images/yuri/oneeye2.png\n",
"output/images/cg/n_cg1b.png\n",
"output/images/natsuki/2bta.png\n",
"output/images/cg/n_cg1_exp3.png\n",
"output/images/monika/old/1.png\n",
"output/images/bg/house.png\n",
"output/images/bg/end-glitch3.JPG\n",
"output/images/monika/m.png\n",
"output/gui/window_icon.png\n",
"output/images/monika/old2/1r.png\n",
"output/images/natsuki/2bth.png\n",
"output/images/cg/y_cg2_exp2.png\n",
"output/images/sayori/e.png\n",
"output/gui/slider/vertical_idle_bar.png\n",
"output/images/cg/s_kill.png\n",
"output/images/cg/s_kill2.png\n",
"output/images/bg/bedroom.png\n",
"output/gui/overlay/confirm.png\n",
"output/images/bg/notebook-glitch.png\n",
"output/gui/bar/right.png\n",
"output/images/cg/credits/1b.png\n",
"output/images/bg/bsod.png\n",
"output/images/yuri/1r.png\n",
"output/images/yuri/stab/6.png\n",
"output/gui/logo.png\n",
"output/gui/button/radio_foreground.png\n",
"output/images/bg/splash-white.png\n",
"output/images/sayori/old/1.png\n",
"output/images/yuri/p.png\n",
"output/gui/poemgame/n_sticker_1.png\n",
"output/gui/slider/vertical_hover_thumb.png\n",
"output/images/yuri/stab/4.png\n",
"output/images/cg/s_cg2_exp2.png\n",
"output/images/natsuki/2bt.png\n",
"output/images/cg/n_cg2_base.png\n",
"output/images/sayori/y.png\n",
"output/images/cg/y_kill/2b.png\n",
"output/images/natsuki/vomit.png\n",
"output/images/yuri/i.png\n",
"output/images/sayori/old2/3.png\n",
"output/images/natsuki/n.png\n",
"output/images/yuri/1bl.png\n",
"output/images/natsuki/k.png\n",
"output/images/natsuki/1r.png\n",
"output/images/cg/credits/5b.png\n",
"output/images/cg/monika/monika_scare.png\n",
"output/images/yuri/k.png\n",
"output/images/monika/3a.png\n",
"output/images/cg/n_cg1_exp4.png\n",
"output/images/natsuki/i.png\n",
"output/images/cg/monika/monika_glitch2.png\n",
"output/images/poem_special/poem_end_clearall.png\n",
"output/images/bg/veinmask.png\n",
"output/images/cg/n_cg2_exp1.png\n",
"output/gui/overlay/game_menu.png\n",
"output/gui/nvl.png\n",
"output/images/sayori/noface1.png\n",
"output/images/yuri/stab/1.png\n",
"output/gui/scrollbar/horizontal_idle_thumb.png\n",
"output/images/bg/club.png\n",
"output/images/sayori/end-glitch1.png\n",
"output/hxppy thxughts.png\n",
"output/images/sayori/p.png\n",
"output/images/cg/monika/monika_bg.png\n",
"output/images/poem_special/poem_special7b.png\n",
"output/images/yuri/cuts.png\n",
"output/images/monika/old/3.png\n",
"output/images/monika/p.png\n",
"output/images/cg/y_cg1_exp1.png\n",
"output/images/bg/warning2.png\n",
"output/images/sayori/u.png\n",
"output/gui/mouse/s_head.png\n",
"output/gui/scrollbar/vertical_hover_thumb.png\n",
"output/images/cg/y_cg2_bg1.png\n",
"output/gui/slider/horizontal_hover_bar.png\n",
"output/gui/menu_bg.png\n",
"output/images/yuri/y3.png\n",
"output/gui/scrollbar/vertical_idle_thumb.png\n",
"output/images/cg/y_cg1_exp3.png\n",
"output/images/sayori/w.png\n",
"output/images/cg/y_cg2_dust1.png\n",
"output/images/sayori/3a.png\n",
"output/images/poem_special/poem_special3.png\n",
"output/images/natsuki/2t.png\n",
"output/images/natsuki/2btb.png\n",
"output/images/menu/wipedown.png\n",
"output/images/yuri/stab/6-eyes.png\n",
"output/gui/scrollbar/vertical_poem_bar.png\n",
"output/images/monika/h.png\n",
"output/images/monika/3b.png\n",
"output/images/sayori/l.png\n",
"output/images/bg/noise1.jpg\n",
"output/images/bg/closet.png\n",
"output/images/cg/monika/mask_3.png\n",
"output/images/yuri/a2.png\n",
"output/images/poem_special/poem_end.png\n",
"output/images/bg/poem.jpg\n",
"output/images/cg/y_cg2_dust4.png\n",
"output/images/cg/monika/monika_glitch4.png\n",
"output/gui/textbox.png\n",
"output/images/natsuki/2bti.png\n",
"output/images/yuri/dragon2.png\n",
"output/gui/poemgame/y_sticker_2g.png\n",
"output/images/sayori/r.png\n",
"output/gui/skip.png\n",
"output/images/cg/y_cg2_base.png\n",
"output/images/sayori/old/2.png\n",
"output/images/natsuki/2btc.png\n",
"output/gui/menu_bg_m.png\n",
"output/gui/poemgame/n_sticker_2.png\n",
"output/images/yuri/glitch2.png\n",
"output/images/cg/monika/monika_glitch1.png\n",
"output/images/sayori/c.png\n",
"output/gui/phone/overlay/game_menu.png\n",
"output/images/monika/old/5.png\n",
"output/images/natsuki/2tb.png\n",
"output/images/monika/old2/2r.png\n",
"output/images/cg/s_kill_bg.png\n",
"output/images/natsuki/old2/1t.png\n",
"output/images/cg/y_kill/2c.png\n",
"output/images/natsuki/v.png\n",
"output/images/bg/glitch-red.png\n",
"output/gui/button/idle_background.png\n",
"output/images/bg/poem-glitch2.png\n",
"output/images/cg/n_cg3_exp1.png\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"output/images/natsuki/2td.png\n",
"output/gui/poemgame/s_sticker_2.png\n",
"output/images/yuri/1l.png\n",
"output/images/yuri/y1.png\n",
"output/images/natsuki/old/4.png\n",
"output/images/sayori/s.png\n",
"output/images/cg/credits/10b.png\n",
"output/images/natsuki/d.png\n",
"output/gui/ctc.png\n",
"output/images/yuri/2bl.png\n",
"output/gui/button/choice_idle_background.png\n",
"output/images/sayori/2l.png\n",
"output/gui/poem_dismiss.png\n",
"output/images/cg/y_cg2_dust3.png\n",
"output/images/sayori/m.png\n",
"output/images/natsuki/b.png\n",
"output/images/cg/monika/mask.png\n",
"output/gui/textbox_monika.png\n",
"output/images/sayori/j.png\n",
"output/images/natsuki/r.png\n",
"output/images/sayori/3c.png\n",
"output/gui/phone/textbox.png\n",
"output/images/cg/credits/2.png\n",
"output/images/monika/r.png\n",
"output/gui/scrollbar/vertical_idle_bar.png\n",
"output/images/natsuki/old2/3t.png\n",
"output/images/natsuki/m.png\n",
"output/images/yuri/y7.png\n",
"output/images/natsuki/1l.png\n",
"output/images/bg/glitch-blue.png\n",
"output/images/sayori/q.png\n",
"output/images/cg/credits/4.png\n",
"output/images/natsuki/2tf.png\n",
"output/images/natsuki/0.png\n",
"output/images/yuri/n.png\n",
"output/images/cg/n_cg1_base.png\n",
"output/images/natsuki/z.png\n",
"output/images/cg/s_cg3.png\n",
"output/images/yuri/r.png\n",
"output/images/natsuki/old/5.png\n",
"output/gui/button/radio_selected_foreground.png\n",
"output/images/monika/b.png\n",
"output/images/yuri/stab/5.png\n",
"output/images/cg/s_kill_early.png\n",
"output/images/monika/old2/1l.png\n",
"output/images/yuri/t.png\n",
"output/images/cg/credits/2b.png\n",
"output/images/bg/poem_y2.jpg\n",
"output/images/yuri/0a.png\n",
"output/gui/frame.png\n",
"output/images/yuri/d.png\n",
"output/images/yuri/2br.png\n",
"output/images/cg/y_cg2_details.png\n",
"output/images/cg/y_cg3_exp1.png\n",
"output/gui/menu_art_m_ghost.png\n",
"output/images/sayori/2br.png\n",
"output/images/yuri/y5.png\n",
"output/images/yuri/dragon1.png\n",
"output/images/monika/2l.png\n",
"output/images/sayori/1r.png\n",
"output/images/cg/y_kill/1c.png\n",
"output/gui/bar/top.png\n",
"output/gui/overlay/confirm_glitch.png\n",
"output/images/poem_special/poem_special10.png\n",
"output/images/cg/credits/6.png\n",
"output/images/cg/y_cg2_bg2.png\n",
"output/images/monika/g3.png\n",
"output/images/sayori/glitch1.png\n",
"output/gui/phone/nvl.png\n",
"output/images/monika/d.png\n",
"output/images/natsuki/mouth.png\n",
"output/images/sayori/2bl.png\n",
"output/images/yuri/l.png\n",
"output/images/yuri/oneeye.png\n",
"output/gui/button/slot_hover_background.png\n",
"output/images/sayori/f.png\n",
"output/images/natsuki/2tg.png\n",
"output/images/natsuki/2th.png\n",
"output/gui/poemgame/m_sticker_2.png\n",
"output/images/monika/old2/3.png\n",
"output/images/natsuki/ghost2.png\n",
"output/images/cg/credits/7b.png\n",
"output/images/cg/y_cg2_exp3.png\n",
"output/gui/slider/horizontal_idle_bar.png\n",
"output/gui/button/choice_hover_background.png\n",
"output/images/sayori/old2/1r.png\n",
"output/images/natsuki/h.png\n",
"output/images/natsuki/1t.png\n",
"output/images/bg/vignette.png\n",
"output/images/natsuki/3b.png\n",
"output/images/natsuki/y.png\n",
"output/images/yuri/stab/6-full.png\n",
"output/images/natsuki/2br.png\n",
"output/images/natsuki/a.png\n",
"output/images/cg/credits/3b.png\n",
"output/gui/mouse/s_head2.png\n",
"output/gui/slider/horizontal_hover_thumb.png\n",
"output/gui/scrollbar/horizontal_poem_thumb.png\n",
"output/images/cg/monika/monika_room.png\n",
"output/images/menu/wipeleft.png\n",
"output/images/cg/monika/child_2.png\n",
"output/images/natsuki/o.png\n",
"output/images/cg/y_cg3_base.png\n",
"output/images/natsuki/2btf.png\n",
"output/images/sayori/noface2.png\n",
"output/images/cg/y_kill/3c.png\n",
"output/images/cg/s_cg2_base2.png\n",
"output/images/natsuki/2bl.png\n",
"output/gui/bar/left.png\n",
"output/images/cg/credits/7.png\n",
"output/images/yuri/eyesfull.png\n",
"output/images/cg/credits/8.png\n",
"output/gui/button/check_foreground.png\n",
"output/images/sayori/old2/2r.png\n",
"output/images/natsuki/2ti.png\n",
"output/images/cg/credits/9.png\n",
"output/images/natsuki/old2/1r.png\n",
"output/images/natsuki/j.png\n",
"output/images/cg/y_kill/2a.png\n",
"output/gui/menu_art_s.png\n",
"output/images/cg/credits/8b.png\n",
"output/images/bg/notebook.png\n",
"output/gui/menu_art_n_ghost.png\n",
"output/images/natsuki/blackeyes.png\n",
"output/images/yuri/w.png\n",
"output/images/cg/monika/mask_2.png\n",
"output/images/sayori/k.png\n",
"output/images/sayori/n.png\n",
"output/images/cg/monika/monika_room_highlight.png\n",
"output/images/menu/frame.png\n",
"output/gui/overlay/main_menu.png\n",
"output/images/yuri/j.png\n",
"output/images/monika/g1.png\n",
"output/images/yuri/s.png\n",
"output/images/natsuki/old2/2t.png\n",
"output/images/natsuki/2btd.png\n",
"output/images/natsuki/2r.png\n",
"output/images/monika/f.png\n",
"output/images/monika/2r.png\n",
"output/images/yuri/zb.png\n",
"output/images/poem_special/poem_special5a.png\n",
"output/images/sayori/glitch2.png\n",
"output/images/cg/y_kill/1b.png\n",
"output/images/cg/n_cg3_base.png\n",
"output/images/yuri/zd.png\n",
"output/gui/button/check_selected_foreground.png\n",
"output/images/natsuki/g.png\n",
"output/gui/slider/vertical_idle_thumb.png\n",
"output/images/monika/g2.png\n",
"output/images/yuri/za.png\n",
"output/images/cg/monika/monika_glitch3.png\n",
"output/images/monika/c.png\n",
"output/images/monika/n.png\n",
"output/images/natsuki/e.png\n",
"output/images/poem_special/poem_special6.png\n",
"output/gui/menu_art_y_ghost.png\n",
"output/images/bg/glitch-green.png\n",
"output/images/cg/n_cg1_exp2.png\n",
"output/images/natsuki/t.png\n",
"output/gui/button/hover_background.png\n",
"output/images/cg/y_kill/1a.png\n",
"output/images/yuri/y4.png\n",
"output/images/yuri/1br.png\n",
"output/images/cg/credits/9b.png\n",
"output/images/sayori/3b.png\n",
"output/images/natsuki/old/1.png\n",
"output/images/natsuki/2bte.png\n",
"output/images/monika/j.png\n",
"output/images/yuri/q.png\n",
"output/gui/phone/overlay/main_menu.png\n",
"output/images/bg/poem_y1.jpg\n",
"output/images/natsuki/2btg.png\n",
"output/images/natsuki/glitch1.png\n",
"output/gui/poemgame/y_sticker_1_broken.png\n",
"output/gui/blood_drop.png\n",
"output/gui/menu_art_y.png\n",
"output/images/bg/kitchen.png\n",
"output/images/bg/splash-glitch.png\n",
"output/images/cg/n_cg2_bg.png\n",
"output/images/natsuki/x.png\n",
"output/images/natsuki/l.png\n",
"output/images/natsuki/old2/2r.png\n",
"output/images/sayori/1l.png\n",
"output/images/sayori/old2/1l.png\n",
"output/images/yuri/b.png\n",
"output/images/bg/end-glitch1.JPG\n",
"output/images/yuri/stab/6-mask.png\n",
"output/images/cg/credits/10.png\n",
"output/images/natsuki/2ta.png\n",
"output/images/poem_special/poem_special7a.png\n",
"output/images/menu/notfound.png\n",
"output/images/yuri/glitch5.png\n",
"output/gui/bar/bottom.png\n",
"output/script-poemresponses2.rpyc\n",
"output/script-exclusives-yuri.rpyc\n",
"output/script-exclusives-sayori.rpyc\n",
"output/console.rpyc\n",
"output/script-ch0.rpyc\n",
"output/script-exclusives2-natsuki.rpyc\n",
"output/script-ch40.rpyc\n",
"output/script-ch10.rpyc\n",
"output/script-exclusives2-yuri.rpyc\n",
"output/poemwords.txt\n",
"output/script-ch5.rpyc\n",
"output/script-ch30.rpyc\n",
"output/script-poemgame.rpyc\n",
"output/screens.rpyc\n",
"output/natsuki.chr\n",
"output/iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.txt\n",
"output/script-ch22.rpyc\n",
"output/credits.rpyc\n",
"output/script-ch4.rpyc\n",
"output/effects.rpyc\n",
"output/options.rpyc\n",
"output/cgs.rpyc\n",
"output/glitchtext.rpyc\n",
"output/poems_special.rpyc\n",
"output/poems.rpyc\n",
"output/CAN YOU HEAR ME.txt\n",
"output/script-ch23.rpyc\n",
"output/gui.rpyc\n",
"output/script-poemresponses.rpyc\n",
"output/yuri.chr\n",
"output/script-ch1.rpyc\n",
"output/splash.rpyc\n",
"output/monika.chr\n",
"output/transforms.rpyc\n",
"output/sayori.chr\n",
"output/script-ch21.rpyc\n",
"output/script-exclusives-natsuki.rpyc\n",
"output/script-ch2.rpyc\n",
"output/script.rpyc\n",
"output/definitions.rpyc\n",
"output/script-ch3.rpyc\n",
"output/script-ch20.rpyc\n"
]
}
],
"source": [
"import pathlib\n",
"import shutil\n",
"\n",
"archives = [index_archive(rpa_path) for rpa_path in rpa_paths]\n",
"\n",
"for prefix, index in archives:\n",
" for outpath, loc_tuple_list in index.items():\n",
" write_path = os.path.join(output_dir, outpath)\n",
" out_dir = os.path.dirname(write_path)\n",
" pathlib.Path(out_dir).mkdir(parents=True, exist_ok=True)\n",
" sub_file = build_file(prefix, loc_tuple_list[0])\n",
" with open(write_path, 'wb') as outf, sub_file as inf:\n",
" print(write_path)\n",
" shutil.copyfileobj(inf, outf)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment