Skip to main content

PK2API

Based on: https://github.com/JellyBitz/SRO.PK2API

Python library to read and write data into the PK2 file format from Silkroad Online.

Features

  • Fast search O(1) lookups
  • Create new PK2 files
  • Create new paths recursively if does not exist
  • Full read/write support
  • Bulk extract and import operations
  • Archive comparison (diff) functionality
  • Copy files/folders between archives
  • Glob pattern matching
  • Archive validation and integrity checks
  • Command-line interface (CLI)
  • Zero external dependencies (pure Python)

Installation

pip install pk2api

Or install from source:

pip install -e .

CLI Usage

After installation, the pk2 command is available:

# List all files in an archive
pk2 list Media.pk2

# List files matching a glob pattern
pk2 list Media.pk2 -p "**/*.txt"

# Extract entire archive
pk2 extract Media.pk2 -o ./output

# Extract specific folder
pk2 extract Media.pk2 -f data -o ./output

# Import directory into archive
pk2 add Media.pk2 ./files -t target

# Show archive statistics
pk2 info Media.pk2

# Validate archive integrity
pk2 validate Media.pk2

# Compare two archives
pk2 compare old.pk2 new.pk2           # Text diff output
pk2 compare old.pk2 new.pk2 -f json   # JSON output for tools
pk2 cmp old.pk2 new.pk2 --quick       # Size-only comparison (faster)

# Copy between archives
pk2 copy src.pk2 dst.pk2 path/file.txt        # Copy single file
pk2 copy src.pk2 dst.pk2 "**/*.xml"           # Copy files matching glob
pk2 copy src.pk2 dst.pk2 data/folder -r       # Copy folder recursively
pk2 cp src.pk2 dst.pk2 folder -r -d backup    # Copy to different destination

Python API Usage

from pk2api import Pk2Stream

key = "169841"  # Default SRO key

# Read-only mode
with Pk2Stream("/path/to/Media.pk2", key, read_only=True) as pk2:
    # Get file content
    file = pk2.get_file("Type.txt")
    if file:
        content = file.get_content()
        print(content.decode("utf-8"))

    # List files from root folder
    root = pk2.get_folder("")
    print("Files:")
    for path in root.files.keys():
        print(f" - {path}")

    # List folders from root folder
    print("Folders:")
    for path in root.folders.keys():
        print(f" - {path}")

    # Find files by glob pattern
    for file in pk2.glob("**/*.txt"):
        print(file.get_full_path())

    # Iterate all files
    for file in pk2.iter_files():
        print(file.get_full_path())

    # Get archive statistics
    stats = pk2.get_stats()
    print(f"Files: {stats['file_count']}, Folders: {stats['folder_count']}")

# Read-write mode
with Pk2Stream("/path/to/Media.pk2", key) as pk2:
    # Add & remove folder
    pk2.add_folder("test/new_folder")
    pk2.remove_folder("test/new_folder")

    # Add & remove file
    pk2.add_file("test/new_file.txt", b"Hello World")
    pk2.remove_file("test/new_file.txt")

    # Bulk extract
    pk2.extract_all("./output")
    pk2.extract_folder("data", "./output")

    # Bulk import from disk
    pk2.import_from_disk("./files", "target/path")

    # Validate archive integrity
    result = pk2.validate()
    print(f"Valid: {result['valid']}")

# Copy between archives
with Pk2Stream("source.pk2", key, read_only=True) as src:
    with Pk2Stream("dest.pk2", key) as dst:
        dst.copy_file_from(src, "path/to/file.txt")
        dst.copy_folder_from(src, "data/folder")
        dst.copy_files_from(src, ["file1.txt", "file2.txt"])

# Compare archives
from pk2api import compare_archives

with Pk2Stream("old.pk2", key, read_only=True) as old:
    with Pk2Stream("new.pk2", key, read_only=True) as new:
        result = compare_archives(old, new)
        print(f"Added: {len(result.added_files)}")
        print(f"Removed: {len(result.removed_files)}")
        print(f"Modified: {len(result.modified_files)}")

API Reference

Pk2Stream

Main class for reading and writing PK2 archives.

Pk2Stream(path: str, key: str, read_only: bool = False)

Core Methods:

  • get_folder(path: str) -> Pk2Folder | None - Get folder by path (O(1))
  • get_file(path: str) -> Pk2File | None - Get file by path (O(1))
  • add_folder(path: str) -> bool - Create folder (recursive)
  • add_file(path: str, data: bytes) -> bool - Add or update file
  • remove_folder(path: str) -> bool - Remove folder and contents
  • remove_file(path: str) -> bool - Remove file
  • close() - Close the stream

Iteration Methods:

  • iter_files() -> Iterator[Pk2File] - Iterate all files in archive
  • iter_folders() -> Iterator[Pk2Folder] - Iterate all folders in archive
  • glob(pattern: str) -> Iterator[Pk2File] - Find files matching glob pattern

Utility Methods:

  • get_stats() -> dict - Return file/folder counts and sizes
  • validate() -> dict - Check archive integrity
  • extract_all(output_dir: str, progress=None) - Extract entire archive
  • extract_folder(folder_path: str, output_dir: str, progress=None) - Extract subfolder
  • import_from_disk(source_dir: str, target_path: str = "", progress=None) - Bulk import

Inter-Archive Copy Methods:

  • copy_file_from(source: Pk2Stream, source_path: str, target_path: str = None) - Copy single file
  • copy_folder_from(source: Pk2Stream, source_path: str, target_path: str = None, progress=None) - Copy folder recursively
  • copy_files_from(source: Pk2Stream, paths: list, target_base: str = "", progress=None) - Copy multiple files

Pk2Folder

Represents a folder within a PK2 archive.

Properties:

  • name: str - Folder name (lowercase)
  • original_name: str - Case-preserved name from archive
  • parent: Pk2Folder | None - Parent folder
  • offset: int - Byte offset in stream
  • files: dict[str, Pk2File] - Files in this folder
  • folders: dict[str, Pk2Folder] - Subfolders

Methods:

  • get_full_path() -> str - Get full path from root (lowercase)
  • get_original_path() -> str - Get full path with original case

Pk2File

Represents a file within a PK2 archive.

Properties:

  • name: str - File name (lowercase)
  • original_name: str - Case-preserved name from archive
  • parent: Pk2Folder - Parent folder
  • offset: int - Byte offset in stream
  • size: int - File size in bytes

Methods:

  • get_full_path() -> str - Get full path from root (lowercase)
  • get_original_path() -> str - Get full path with original case
  • get_content() -> bytes - Read file content

Comparison Functions

from pk2api import compare_archives, ComparisonResult, FileChange, FolderChange, ChangeType
  • compare_archives(source: Pk2Stream, target: Pk2Stream, compute_hashes: bool = True) -> ComparisonResult

ComparisonResult Properties:

  • added_files: list[FileChange] - Files added in target
  • removed_files: list[FileChange] - Files removed from source
  • modified_files: list[FileChange] - Files modified between archives

ChangeType Enum:

  • ADDED, REMOVED, MODIFIED, UNCHANGED

Requirements

  • Python 3.10+

Special Thanks!

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pk2api-1.5.0.tar.gz (30.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pk2api-1.5.0-py3-none-any.whl (30.3 kB view details)

Uploaded Python 3

File details

Details for the file pk2api-1.5.0.tar.gz.

File metadata

  • Download URL: pk2api-1.5.0.tar.gz
  • Upload date:
  • Size: 30.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pk2api-1.5.0.tar.gz
Algorithm Hash digest
SHA256 af0496bfa5b7e0d0591e3272d214ddb41e13e58450f7131d24ce69b911ef8032
MD5 3aca3d88bc9d3dafe0446f3daa0ed85a
BLAKE2b-256 540387c3036c4645dbb4bffa84212a6272287317c3a243e2e49c25713a1b4461

See more details on using hashes here.

Provenance

The following attestation bundles were made for pk2api-1.5.0.tar.gz:

Publisher: publish.yml on dadav/pk2api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pk2api-1.5.0-py3-none-any.whl.

File metadata

  • Download URL: pk2api-1.5.0-py3-none-any.whl
  • Upload date:
  • Size: 30.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pk2api-1.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 635e12f0f62960ae7495b82b72a1555852dfe7185f84b98889db298848020bd3
MD5 17d353aee9b43b9d976eb7ba6cb0c86e
BLAKE2b-256 992b4b4cbed57e6249b9f286356b24b66fbcc6509a01eccd55bc63d8bdb0e64e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pk2api-1.5.0-py3-none-any.whl:

Publisher: publish.yml on dadav/pk2api

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.5.0 This release

2 files

1.4.1

2 files

1.4.0

2 files

1.3.0

2 files

1.2.0

2 files

1.1.0

2 files

1.0.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page