Skip to main content

osz2.py

Python Version GitHub License GitHub Actions Workflow Status

osz2.py is a Python library for reading osz2 files. It's a direct port of the existing Osz2Decryptor project by xxCherry and osz2-go by me.

This project won't provide beatmap parsing support. You will have to implement that by yourself, if you decide to use this library for implementing the beatmap submission system.

Installation

pip install osz2

Or install from source:

git clone https://github.com/Lekuruu/osz2.py
cd osz2.py
pip install -e .

Usage

This repository provides a command-line interface for easy testing:

python -m osz2 decrypt <input.osz2> <output_directory>
python -m osz2 encrypt <target_directory> <output.osz2>

But that's not all!
Here is an example of how to use osz2.py as a library:

from osz2 import Osz2Package, MetadataType

# Parse package from file
package = Osz2Package.from_file("beatmap.osz2")

# Access metadata
print("Title:", package.metadata.get(MetadataType.Title))
print("Artist:", package.metadata.get(MetadataType.Artist))
print("Creator:", package.metadata.get(MetadataType.Creator))
print("Difficulty:", package.metadata.get(MetadataType.Difficulty))

# Access files
for file in package.files:
    print(f"File: {file.filename}, Size: {len(file.content)} bytes")

# Extract specific files
for file in package.files:
    if not file.filename.endswith(".osu"):
        continue

    with open(file.filename, "wb") as f:
        f.write(file.content)

# Create a regular .osz package
with open("beatmap.osz", "wb") as f:
    f.write(package.create_osz_package())

Metadata-only Mode

If you only need to read metadata without extracting files, you can use the metadata_only parameter:

# Only parse metadata
package = Osz2Package.from_file("beatmap.osz2", metadata_only=True)

# Access metadata
print("Title:", package.metadata.get(MetadataType.Title))
print("BeatmapSet ID:", package.metadata.get(MetadataType.BeatmapSetID))

Alternative Constructors

# From file path
package = Osz2Package.from_file("beatmap.osz2")

# From bytes
with open("beatmap.osz2", "rb") as f:
    data = f.read()
    package = Osz2Package.from_bytes(data)

# From an io.BufferedReader-like object, e.g. a file stream
with open("beatmap.osz2", "rb") as f:
    package = Osz2Package(f)

Exporting an osz2 package

You can initialize and export osz2 packages from a directory:

from osz2 import Osz2Package, MetadataType

# Initialize package from a directory containing beatmap files
package = Osz2Package.from_directory("./my_beatmap_folder")

# Export to osz2 format
osz2_data = package.export()

with open("output.osz2", "wb") as f:
    f.write(osz2_data)

# Or save directly to a file
package.save("./output.osz2")

Managing Files

You can add, remove, and modify files within a package:

from osz2 import Osz2Package, MetadataType

# Create a new package
package = Osz2Package()

# Add metadata (required for export)
package.add_metadata(MetadataType.Title, "My Beatmap")
package.add_metadata(MetadataType.Artist, "Artist Name")
package.add_metadata(MetadataType.Creator, "Mapper Name")
package.add_metadata(MetadataType.BeatmapSetID, 123456)

# Add a file from memory
beatmap_content = b"osu file format v14\n..."
package.add_file("my_beatmap.osu", beatmap_content)

# Add a file from disk
package.add_file_from_disk("audio.mp3", "./path/to/audio.mp3")

# Add an entire directory (non-recursive)
package.add_directory("./beatmap_files", recursive=False)

# Add an entire directory (recursive, preserves folder structure)
package.add_directory("./beatmap_folder", recursive=True)

# Remove a file
package.remove_file("old_file.osu")

# Find a file by name
file = package.find_file_by_name("audio.mp3")
if file:
    print(f"Found: {file.filename}, size: {file.size}")

# Set beatmap IDs
package.set_beatmap_id("my_beatmap.osu", 789012)

# Export the package
package.save("my_beatmap.osz2")

Managing Metadata

Metadata can be added, retrieved, and removed:

from osz2 import Osz2Package, MetadataType

package = Osz2Package.from_file("beatmap.osz2")

# Add or update metadata
package.add_metadata(MetadataType.Title, "New Title")
package.add_metadata(MetadataType.Artist, "New Artist")

# Get metadata
title = package.get_metadata(MetadataType.Title)
print(f"Title: {title}")

# Remove metadata
package.remove_metadata(MetadataType.Difficulty)

# Convenience method for setting beatmapset ID
package.set_beatmapset_id(999999)

# Save changes
package.save("modified.osz2")

Applying a patch

When developing an implementation of the beatmap submission system, this could come in handy:

# Assuming you have a source osz2 file and a patch file
osz2_file = b"..."
patch_file = b"..."

updated_osz2 = osz2.apply_bsdiff_patch(osz2_file, patch_file)
osz2 = Osz2Package.from_bytes(updated_osz2)

Using osu!stream .osf2 files

I have not tested this, but in theory this should work by passing in KeyType.OSF2 when initializing the osz2 package:

osf2 = Osz2Package.from_file("beatmap.osf2", key_type=KeyType.OSF2)

You can also specify this when using the command-line interface:

python -m osz2 <input.osz2> <output_directory> --key-type osf2

Building the crypto.c extension

If you change any code under osz2/crypto.c, rebuild the module in place before running tests:

python -m venv venv
source venv/bin/activate
pip install -e .

Or, if you only need the extension locally:

python setup.py build_ext --inplace

The resulting shared object is picked up automatically by the package import system.

Metadata

Release files for osz2 1.1.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for osz2 1.1.7
File Size Uploaded
osz2-1.1.7.tar.gz 23.5 kB Details

Release files / osz2-1.1.7.tar.gz

Download URL osz2-1.1.7.tar.gz
Size 23.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b5866a8a876eb4f6556325348f437e7b568cc56fe9e778fcc71c698755e360d1
BLAKE2b-256 checksum
How to use checksums
7d08738c6a891f253141b817f63c9abfe8fa423776fdfc4754d07e8db68a00cd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.20

Release history Release notifications | RSS feed

This release

1.1.7 This release

1 release file

1.1.6

1 release file

1.1.5

1 release file

1.1.4

1 release file

1.1.3

1 release file

1.1.2

1 release file

1.1.1

1 release file

1.1.0

1 release file

1.0.7

1 release file

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page