
SDK for PikPak cloud storage offering atomic, well-typed API surface with automatic token lifecycle, captcha refresh, GCID hashing, OSS multipart HMAC signing, rate-limiting, retries, and resumable uploads/downloads.
A Kotlin Multiplatform SDK for PikPak cloud storage — JVM, Android and iOS.
suspend call. Sessions, token refresh, captcha re-authentication, retries, rate limiting, content hashing and OSS upload signing happen inside the client.val client = PikPakClient(account = "you@example.com", password = "...")
// A magnet against PikPak's content index: no task, nothing in the drive. Null means PikPak has never seen it.
val resource = client.resolveMagnet("magnet:?xt=urn:btih:...") ?: return
val episode = resource.files.first { it.name.endsWith(".mkv") }
val gcid = episode.gcid ?: return
// The hash becomes a file, in the folder and under the name you choose.
val folder = client.getOrCreateDeepFolderId("", "anime/2026")
val fileId = client.instantCreate(episode, parentId = folder)
// Read it at any offset, over eight connections.
val handle = PikPakFileHandle(client, gcid, episode.size, episode.name, initialFileId = fileId)
val cache = handle.openCache() // one per file: every stream, prefetch and download shares it
val buffer = ByteArray(64 * 1024)
cache.openStream().use { stream ->
stream.seekTo(0)
stream.read(buffer, 0, buffer.size)
}repositories { mavenCentral() }
dependencies {
implementation("io.github.nihildigit:pikpak-kotlin:2.0.0")
// Ktor is compileOnly in the SDK, so it never changes the Ktor you pinned: bring the core and one engine.
implementation("io.ktor:ktor-client-core:<your-ktor-version>")
implementation("io.ktor:ktor-client-okhttp:<your-ktor-version>") // or ktor-client-darwin on iOS
}Targets: jvm, android (AAR pikpak-kotlin-android), iosArm64, iosSimulatorArm64. On Android, pass a SessionStore — there is no default location there.
The project wiki is the manual:
| Getting Started | Clients, sessions, logging in, injected HTTP clients, budgets |
| Best Practices | What works, learned building a real client, with the reasons |
| Playback | Range reads, handles, streams, priorities, prefetch, disk caching, transcodes |
| Magnets and Instant Create | The hash path, and what it costs |
| Drive Operations | Files, trash, stars, search, shares, play history, archives |
| Uploads and Offline Tasks | Resumable uploads, content hashes, offline downloads and pruning |
| Errors and Retries | What throws what, and what the client retries by itself |
| Architecture · Measurements · History | How it fits together, what PikPak was measured to do, and what was tried |
Piko — a PikPak client for Android, Windows and macOS, by the same author, and the SDK's most demanding user: a player that streams through a loopback proxy, a random-clip feed that starts in under two seconds and from disk in a quarter of one, downloads, resumable uploads, magnets and offline packs, shares and server-side archives. If you want to see any page of the wiki in working code, it is there.
JDK 21, Gradle wrapper included. ./gradlew jvmTest runs the unit tests and, with PikPak credentials in a git-ignored .env, the live integration suite; without them the live tests skip. Details, probes and the release process are in Development.
The HTTP wire format, captcha salt cascade and content hash follow the Go reference implementations 52funny/pikpakcli (endpoints, request and response shapes, captcha signing, OSS upload) and 52funny/pikpakhash (the hash's block-size table). The Xunlei CID sampling and the /drive/v1/resource/cid lookup were first seen in digbug82/PikPak_Enhancement_Master. All code here is Kotlin; only PikPak's public API behaviour is shared.
MIT, see LICENSE.
A Kotlin Multiplatform SDK for PikPak cloud storage — JVM, Android and iOS.
suspend call. Sessions, token refresh, captcha re-authentication, retries, rate limiting, content hashing and OSS upload signing happen inside the client.val client = PikPakClient(account = "you@example.com", password = "...")
// A magnet against PikPak's content index: no task, nothing in the drive. Null means PikPak has never seen it.
val resource = client.resolveMagnet("magnet:?xt=urn:btih:...") ?: return
val episode = resource.files.first { it.name.endsWith(".mkv") }
val gcid = episode.gcid ?: return
// The hash becomes a file, in the folder and under the name you choose.
val folder = client.getOrCreateDeepFolderId("", "anime/2026")
val fileId = client.instantCreate(episode, parentId = folder)
// Read it at any offset, over eight connections.
val handle = PikPakFileHandle(client, gcid, episode.size, episode.name, initialFileId = fileId)
val cache = handle.openCache() // one per file: every stream, prefetch and download shares it
val buffer = ByteArray(64 * 1024)
cache.openStream().use { stream ->
stream.seekTo(0)
stream.read(buffer, 0, buffer.size)
}repositories { mavenCentral() }
dependencies {
implementation("io.github.nihildigit:pikpak-kotlin:2.0.0")
// Ktor is compileOnly in the SDK, so it never changes the Ktor you pinned: bring the core and one engine.
implementation("io.ktor:ktor-client-core:<your-ktor-version>")
implementation("io.ktor:ktor-client-okhttp:<your-ktor-version>") // or ktor-client-darwin on iOS
}Targets: jvm, android (AAR pikpak-kotlin-android), iosArm64, iosSimulatorArm64. On Android, pass a SessionStore — there is no default location there.
The project wiki is the manual:
| Getting Started | Clients, sessions, logging in, injected HTTP clients, budgets |
| Best Practices | What works, learned building a real client, with the reasons |
| Playback | Range reads, handles, streams, priorities, prefetch, disk caching, transcodes |
| Magnets and Instant Create | The hash path, and what it costs |
| Drive Operations | Files, trash, stars, search, shares, play history, archives |
| Uploads and Offline Tasks | Resumable uploads, content hashes, offline downloads and pruning |
| Errors and Retries | What throws what, and what the client retries by itself |
| Architecture · Measurements · History | How it fits together, what PikPak was measured to do, and what was tried |
Piko — a PikPak client for Android, Windows and macOS, by the same author, and the SDK's most demanding user: a player that streams through a loopback proxy, a random-clip feed that starts in under two seconds and from disk in a quarter of one, downloads, resumable uploads, magnets and offline packs, shares and server-side archives. If you want to see any page of the wiki in working code, it is there.
JDK 21, Gradle wrapper included. ./gradlew jvmTest runs the unit tests and, with PikPak credentials in a git-ignored .env, the live integration suite; without them the live tests skip. Details, probes and the release process are in Development.
The HTTP wire format, captcha salt cascade and content hash follow the Go reference implementations 52funny/pikpakcli (endpoints, request and response shapes, captcha signing, OSS upload) and 52funny/pikpakhash (the hash's block-size table). The Xunlei CID sampling and the /drive/v1/resource/cid lookup were first seen in digbug82/PikPak_Enhancement_Master. All code here is Kotlin; only PikPak's public API behaviour is shared.
MIT, see LICENSE.