Skip to content

Instantly share code, notes, and snippets.

@jericjan
Last active July 5, 2026 12:04
Show Gist options
  • Select an option

  • Save jericjan/840f66c05b7d0c03a91679cc797f1017 to your computer and use it in GitHub Desktop.

Select an option

Save jericjan/840f66c05b7d0c03a91679cc797f1017 to your computer and use it in GitHub Desktop.
manilua-to-ddm

Just put this python file in a dedicated folder and just run it. It'll save the file location off DDM to a file called ddm.txt so you won't have to specify it the next time.

import re
import subprocess
import tempfile
from pathlib import Path
from zipfile import ZipFile
class KeyExtractor:
"""handles parsing of decryptions keys from lua files"""
def __init__(self, pattern: str):
self.pattern = re.compile(pattern, re.MULTILINE)
def extract_keys(self, content: str) -> list[tuple[str, str]]:
return self.pattern.findall(content)
def write_keys_file(self, keys: list[tuple[str, str]], output_path: Path) -> None:
lines = [f"{depot};{key}\n" for depot, key in keys]
output_path.write_text("".join(lines), encoding="utf-8")
class DepotDownloaderMod:
def __init__(self, exe_path: Path, keys_path: Path):
self.exe_path = exe_path
self.keys_path = keys_path
def run(self, manifest_path: Path, depot_id: str, app_id: str, target_dir: Path) -> None:
cmd = [
str(self.exe_path),
"-app",
app_id,
"-depot",
depot_id,
"-depotkeys",
str(self.keys_path),
"-manifestfile",
str(manifest_path),
"-dir",
str(target_dir)
]
subprocess.run(cmd, check=True)
def process_zip(zip_path: Path, exe_path: Path) -> None:
lua_pattern = (
r"^\s*addappid\s*\(\s*(\d+)\s*,\s*\d\s*,\s*(?:\"|')\s*(\S+)\s*(?:\"|')"
)
extractor = KeyExtractor(lua_pattern)
with tempfile.TemporaryDirectory() as temp_dir_str:
temp_dir = Path(temp_dir_str)
manifest_files: list[Path] = []
lua_file = None
with ZipFile(zip_path, "r") as archive:
for file_info in archive.infolist():
suffix = Path(file_info.filename).suffix.lower()
if suffix in (".manifest", ".lua"):
extracted_path = Path(archive.extract(file_info, temp_dir))
if suffix == ".manifest":
manifest_files.append(extracted_path)
elif suffix == ".lua":
lua_file = extracted_path
if not lua_file:
raise FileNotFoundError("no .lua file found inside the zip archive")
keys_path = temp_dir / "depot.keys"
keys = extractor.extract_keys(lua_file.read_text(encoding="utf-8"))
extractor.write_keys_file(keys, keys_path)
execution_queue: list[tuple[Path, str, str]] = []
for manifest in manifest_files:
match = re.search(r"\d+", manifest.name)
if not match:
raise ValueError(f"invalid manifest filename: {manifest.name}")
depot_id = match.group(0)
guessed_id = f"{depot_id[:-1]}0"
print(f"\n[Manifest File]: {manifest.name}")
print(f"Predicted App ID: {guessed_id}")
user_val = input("Press ENTER to confirm, or type the correct App ID: ").strip()
app_id = user_val if user_val else guessed_id
execution_queue.append((manifest, depot_id, app_id))
downloader = DepotDownloaderMod(exe_path, keys_path)
for manifest, depot_id, app_id in execution_queue:
downloader.run(manifest, depot_id, app_id, Path(zip_path.stem))
def main() -> None:
ddm_path_file = Path('ddm.txt')
ddm_path_file.touch(exist_ok=True)
with ddm_path_file.open(encoding="utf-8") as f:
ddm_path = f.read()
if ddm_path:
exe_input = ddm_path
else:
exe_input = input("Enter absolute path to DepotDownloaderMod.exe: ").strip("'\"")
exe_path = Path(exe_input).resolve()
if not exe_path.is_file():
print("Error: Executable file not found.")
return
if not ddm_path:
with ddm_path_file.open("w", encoding="utf-8") as f:
f.write(str(exe_path))
zip_input = input("Enter absolute path to the ZIP file: ").strip("'\"")
zip_path = Path(zip_input).resolve()
if not zip_path.is_file():
print("Error: ZIP file not found.")
return
try:
process_zip(zip_path, exe_path)
print("\nProcessing completed successfully.")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment