cloud115

package
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 18, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Overview

Package cloud115 – raw HTTP client for the 115 cloud API.

This file implements the API struct: a thin HTTP layer that handles cookies, rate-limiting, retry, 429/405 recovery, and M115/EC115 encryption. Higher-level caching lives in client.go / cached_client.go.

Package cloud115 – CachedClient: cache-first reads + write-through writes.

Client wraps API and Cache into a single high-level facade. Every read checks the SQLite cache first (respecting TTL); every write calls the API then updates the cache so subsequent reads stay warm.

Package cloud115 implements M115 (RSA+XOR) and EC115 (ECDH-P224+AES-CBC+LZ4) encryption for the 115 cloud storage API.

Ported from py115 (MIT license, github.com/deadblue/py115).

Index

Constants

View Source
const (
	WebAPI      = "https://webapi.115.com"
	ProAPI      = "https://proapi.115.com"
	QRAPI       = "https://qrcodeapi.115.com"
	PassportAPI = "https://passportapi.115.com"
)

API endpoint base URLs.

View Source
const TokenSalt = "Qclm8MGWUv59TnrR0XPg"

TokenSalt is exported for callers that need the HMAC-style token salt.

Variables

This section is empty.

Functions

func DefaultCachePath

func DefaultCachePath() string

DefaultCachePath returns the default path for the SQLite cache database.

func GenerateM115Key

func GenerateM115Key() []byte

GenerateM115Key returns 16 cryptographically random bytes suitable for use as an M115 session key.

func M115Decode

func M115Decode(key []byte, ciphertext string) string

M115Decode decodes a base64 ciphertext from the M115 download channel.

Pipeline: base64 → RSA decrypt → extract serverKey(16) → XOR(deriveKey(serverKey,12)) → reverse → XOR(deriveKey(key,4)).

func M115Encode

func M115Encode(key []byte, plaintext string) string

M115Encode encodes a plaintext string for the M115 download channel.

Pipeline: XOR(deriveKey(key,4)) → reverse → XOR(clientKey) → prepend key → RSA encrypt → base64.

Types

type API

type API struct {
	// contains filtered or unexported fields
}

API is a low-level 115 cloud HTTP client (cookie mode only). Every public method maps to one HTTP endpoint.

func NewAPI

func NewAPI(cookies string, cache *Cache) *API

NewAPI constructs an API client from a cookie string. cache may be nil (disables rate-limit persistence).

func (*API) BatchRename

func (a *API) BatchRename(renames map[string]string) (map[string]any, error)

BatchRename renames multiple files in one API call. renames maps fileID newName.

func (*API) CheckLogin

func (a *API) CheckLogin() bool

CheckLogin returns true if the current cookies are valid.

func (*API) Delete

func (a *API) Delete(fileIDs []string) (map[string]any, error)

Delete deletes fileIDs.

func (*API) DownloadURL

func (a *API) DownloadURL(pickCode, userAgent string) (string, error)

DownloadURL returns the download URL for the given pick code. userAgent is sent in the request (affects whether CDN gives a direct URL).

func (*API) ExportTree

func (a *API) ExportTree(dirID string) (string, error)

ExportTree exports a directory tree and returns the UTF-16LE decoded text.

func (*API) GetCookies

func (a *API) GetCookies() string

GetCookies returns the current cookie string.

func (*API) GetDirID

func (a *API) GetDirID(path string) (string, error)

GetDirID resolves an absolute path string to a directory ID. Returns "" when the path does not exist (including when the API returns id=0).

func (*API) ListFiles

func (a *API) ListFiles(dirID string, limit, offset int) ([]map[string]any, error)

ListFiles returns up to limit entries in dirID starting at offset.

func (*API) ListFilesAll

func (a *API) ListFilesAll(dirID string) ([]map[string]any, error)

ListFilesAll returns all entries in dirID, handling pagination automatically.

func (*API) Mkdir

func (a *API) Mkdir(parentID, name string) (map[string]any, error)

Mkdir creates a directory named name under parentID.

func (*API) Move

func (a *API) Move(fileIDs []string, targetDirID string) (map[string]any, error)

Move moves fileIDs into targetDirID.

func (*API) QRGetToken

func (a *API) QRGetToken(app string) (*QRSession, error)

QRGetToken fetches a QR login token and returns the session (phase 1). Call QRWaitAndLogin with the returned session to complete the login (phase 2).

func (*API) QRLogin

func (a *API) QRLogin(app string) error

QRLogin performs an interactive QR-code login and updates the client cookies.

func (*API) QRWaitAndLogin

func (a *API) QRWaitAndLogin(sess *QRSession) error

QRWaitAndLogin polls for QR scan completion and finalizes login (phase 2). Updates the API cookie string on success.

func (*API) RapidUpload

func (a *API) RapidUpload(dirID, filename string, fileSize int64, fileSHA1 string, fileStream io.ReadSeeker) (map[string]any, error)

RapidUpload attempts an instant (hash-match) upload. Returns status 2 on success.

func (*API) Rename

func (a *API) Rename(fileID, newName string) (map[string]any, error)

Rename renames fileID to newName.

func (*API) RenewCookies

func (a *API) RenewCookies(app string) bool

RenewCookies attempts to silently refresh the session cookies via QR token flow.

func (*API) SaveCookies

func (a *API) SaveCookies(path string) error

SaveCookies updates the TOML config file at path, replacing the cookies value.

func (*API) Search

func (a *API) Search(keyword, dirID string) ([]map[string]any, error)

Search returns entries matching keyword in dirID.

func (*API) UploadFile

func (a *API) UploadFile(localPath, targetDirID, filename string) (map[string]any, error)

UploadFile uploads a local file to targetDirID via OSS.

func (*API) UploadInfo

func (a *API) UploadInfo() (userID, userKey string, err error)

UploadInfo returns the userID and userKey required for rapid-upload requests.

type BatchRenameItem

type BatchRenameItem struct {
	Path    string
	NewName string
}

BatchRenameItem pairs a cloud path with its desired new name.

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

Cache is a SQLite-backed file/directory cache for cloud115. Every public method commits immediately (or runs in its own transaction).

func NewCache

func NewCache(dbPath string) (*Cache, error)

NewCache opens (or creates) the SQLite cache at dbPath. Pass an empty string to use the default path.

func (*Cache) AddEntry

func (c *Cache) AddEntry(parentCID string, entry Entry)

AddEntry upserts a single entry into the cached listing.

func (*Cache) Clear

func (c *Cache) Clear()

Clear deletes everything including rate_limit.

func (*Cache) ClearMetadata

func (c *Cache) ClearMetadata()

ClearMetadata clears all cache data except rate_limit.

func (*Cache) ClearTree

func (c *Cache) ClearTree()

ClearTree deletes all tree_entry rows.

func (*Cache) Close

func (c *Cache) Close() error

Close closes the database connection. Idempotent.

func (*Cache) DeleteDirMeta

func (c *Cache) DeleteDirMeta(cid string)

DeleteDirMeta marks directory cid as stale (removes meta, keeps entries).

func (*Cache) DeletePathPrefix

func (c *Cache) DeletePathPrefix(prefix string)

DeletePathPrefix deletes path itself and every entry whose path starts with prefix + "/".

func (*Cache) FindEntries

func (c *Cache) FindEntries(parentCID, name string) []Entry

FindEntries returns all entries matching name inside parentCID.

func (*Cache) FindEntry

func (c *Cache) FindEntry(parentCID, name string) *Entry

FindEntry returns the first entry matching name inside parentCID, or nil.

func (*Cache) GetDirEntries

func (c *Cache) GetDirEntries(cid string) []Entry

GetDirEntries returns cached entries for cid, dirs first then by name.

func (*Cache) GetDirTS

func (c *Cache) GetDirTS(cid string) (ts int64, ok bool)

GetDirTS returns the freshness timestamp for directory cid, or ok=false.

func (*Cache) GetPath

func (c *Cache) GetPath(path string) (cid string, ts int64, ok bool)

GetPath returns the cid and timestamp for path, or ok=false if not found.

func (*Cache) GetRateLimit

func (c *Cache) GetRateLimit(name string) RateLimitState

GetRateLimit returns the rate-limit state for name (defaults all to 0).

func (*Cache) GetSnapshotMeta

func (c *Cache) GetSnapshotMeta() SnapshotMeta

GetSnapshotMeta returns the snapshot metadata recorded by SetTree.

func (*Cache) GetTreeEntries

func (c *Cache) GetTreeEntries(category string) []TreeEntry

GetTreeEntries returns all tree entries, optionally filtered by a category path prefix (entries whose path starts with category + "/" or equals category).

func (*Cache) IncrementMinuteCount

func (c *Cache) IncrementMinuteCount(name string)

IncrementMinuteCount atomically bumps minute_count for name (creates row if needed).

func (*Cache) InvalidateDir

func (c *Cache) InvalidateDir(cid string)

InvalidateDir removes both the dir_meta row and all dir_entry rows for cid.

func (*Cache) MoveEntry

func (c *Cache) MoveEntry(oldParentCID, nodeID, newParentCID string)

MoveEntry moves the entry identified by nodeID from oldParentCID to newParentCID.

func (*Cache) RemoveEntry

func (c *Cache) RemoveEntry(parentCID, name string)

RemoveEntry deletes all entries with the given name from parentCID.

func (*Cache) RemoveEntryByID

func (c *Cache) RemoveEntryByID(parentCID, nodeID string)

RemoveEntryByID deletes a specific entry identified by nodeID within parentCID.

func (*Cache) RenameEntry

func (c *Cache) RenameEntry(parentCID, nodeID, newName string)

RenameEntry renames the entry identified by nodeID within parentCID.

func (*Cache) SetDirListing

func (c *Cache) SetDirListing(cid string, entries []Entry)

SetDirListing atomically replaces the cached listing for directory cid.

func (*Cache) SetPath

func (c *Cache) SetPath(path, cid string)

SetPath inserts or replaces a path→cid mapping with ts = now.

func (*Cache) SetRateLimit

func (c *Cache) SetRateLimit(name string, state RateLimitState)

SetRateLimit upserts rate-limit fields, always overwriting all columns.

func (*Cache) SetTree

func (c *Cache) SetTree(entries []TreeEntry, rootPath string)

SetTree replaces all tree entries atomically and records snapshot metadata.

func (*Cache) StaleDirCount

func (c *Cache) StaleDirCount(listingTTL int) int

StaleDirCount returns the number of directories whose listing has expired.

func (*Cache) Stats

func (c *Cache) Stats() CacheStats

Stats returns a summary of cache contents and database file size.

func (*Cache) TreeStats

func (c *Cache) TreeStats() (total, videos, nfos int)

TreeStats returns total/video/nfo counts.

func (*Cache) TryAcquireSlot

func (c *Cache) TryAcquireSlot(name string, now, minInterval float64, qpm int) bool

TryAcquireSlot atomically tries to acquire a rate-limit slot. Returns true on success, false if any limit (cooldown / QPS / QPM) is active.

type CacheStats

type CacheStats struct {
	PathCount   int                       `json:"path_count"`
	DirCount    int                       `json:"dir_count"`
	EntryCount  int                       `json:"entry_count"`
	TreeEntries int                       `json:"tree_entries"`
	DBSizeBytes int64                     `json:"db_size_bytes"`
	RateLimit   map[string]RateLimitState `json:"rate_limit"`
}

CacheStats summarises the current state of the cache database.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a high-level 115 cloud client with transparent SQLite caching.

func NewClient

func NewClient(cookies string, opts ...ClientOption) (*Client, error)

NewClient creates a Client. cookies is the 115 cookie string.

func (*Client) BatchRename

func (c *Client) BatchRename(renames []BatchRenameItem) error

BatchRename renames multiple files in a single API call.

func (*Client) CacheClear

func (c *Client) CacheClear() error

CacheClear clears all cache metadata (keeps rate-limit state).

func (*Client) CacheStatus

func (c *Client) CacheStatus() (*CacheStats, error)

CacheStatus returns a summary of the current cache state.

func (*Client) CheckLogin

func (c *Client) CheckLogin() bool

CheckLogin returns true if the current cookies are valid.

func (*Client) Close

func (c *Client) Close() error

Close releases the database connection.

func (*Client) Delete

func (c *Client) Delete(paths []string) error

Delete deletes one or more cloud paths.

func (*Client) DeleteByIDs

func (c *Client) DeleteByIDs(fids []string, refreshDirs []string) error

DeleteByIDs deletes files by their file IDs. optionally refreshing dirs after the deletion.

func (*Client) DownloadURL

func (c *Client) DownloadURL(pickCode, userAgent string) (string, error)

DownloadURL returns the download URL for a pick code (direct API, no cache).

func (*Client) ExportTree

func (c *Client) ExportTree(path string) (string, error)

ExportTree exports the directory tree at path as text.

func (*Client) FindFile

func (c *Client) FindFile(path string) (*Entry, error)

FindFile looks up a file by its full path and returns its metadata.

func (*Client) GetCookies

func (c *Client) GetCookies() string

GetCookies returns the current cookie string.

func (*Client) Invalidate

func (c *Client) Invalidate(path string) error

Invalidate removes cache entries for path and everything beneath it.

func (*Client) ListDir

func (c *Client) ListDir(path string) ([]Entry, error)

ListDir lists a directory by path (cache-first).

func (*Client) ListDirUncached

func (c *Client) ListDirUncached(path string) ([]Entry, error)

ListDirUncached bypasses the cache and fetches the listing directly from the API. Useful for dedup scenarios where stale cache must not be trusted.

func (*Client) Mkdir

func (c *Client) Mkdir(path string, parents bool) (string, error)

Mkdir creates a directory at path. If parents is true, intermediate directories are created as needed. Returns the new directory cid.

func (*Client) Move

func (c *Client) Move(srcPaths []string, destPath string) error

Move moves srcPaths to destPath.

func (*Client) QRGetToken

func (c *Client) QRGetToken(app string) (*QRSession, error)

QRGetToken fetches a QR login token (phase 1 of two-phase login).

func (*Client) QRLogin

func (c *Client) QRLogin(app string) error

QRLogin performs an interactive QR-code login and refreshes client cookies.

func (*Client) QRWaitAndLogin

func (c *Client) QRWaitAndLogin(sess *QRSession) error

QRWaitAndLogin polls for QR scan and finalizes login (phase 2).

func (*Client) RapidUpload

func (c *Client) RapidUpload(localPath, remoteDir string) (*RapidResult, error)

RapidUpload attempts an instant (hash-match) upload.

func (*Client) RefreshDir

func (c *Client) RefreshDir(path string) ([]Entry, error)

RefreshDir forces a refresh of path's listing regardless of TTL.

func (*Client) RefreshPaths

func (c *Client) RefreshPaths(paths []string) error

RefreshPaths refreshes multiple directories, deduplicating first.

func (*Client) Rename

func (c *Client) Rename(path, newName string) error

Rename renames the file or directory at path to newName.

func (*Client) RenewCookies

func (c *Client) RenewCookies() bool

RenewCookies attempts a silent cookie refresh and returns true on success.

func (*Client) ResolvePath

func (c *Client) ResolvePath(path string) (string, error)

ResolvePath resolves a cloud path to a directory cid. Returns "0" for root. Returns an error wrapping fs.ErrNotExist if missing.

func (*Client) SaveCookies

func (c *Client) SaveCookies(path string) error

SaveCookies updates the TOML config file at path with the current cookies.

func (*Client) SaveTree

func (c *Client) SaveTree(text string, videoExts []string, rootPath string) (int, error)

SaveTree parses the 115 export-tree text and saves entries to the cache. videoExts is the set of lowercase extensions (e.g. {".mkv", ".mp4"}). Returns the number of entries saved.

func (*Client) Search

func (c *Client) Search(keyword, path string) ([]Entry, error)

Search searches for keyword under path.

func (*Client) Stat

func (c *Client) Stat(path string) (*Entry, error)

Stat returns metadata for path (file or directory).

func (*Client) StreamURL

func (c *Client) StreamURL(path, userAgent string) (string, error)

StreamURL resolves path pick code download URL in one step.

func (*Client) TreeEntries

func (c *Client) TreeEntries(category string) ([]TreeEntry, error)

TreeEntries returns tree entries, optionally filtered by category path prefix.

func (*Client) TreeStats

func (c *Client) TreeStats() (*TreeStats, error)

TreeStats returns count totals for the stored tree snapshot.

func (*Client) Upload

func (c *Client) Upload(localPath, remoteDir, filename string) (map[string]any, error)

Upload uploads a local file to remoteDir. If filename is empty the local file's base name is used. Returns API result data or nil.

func (*Client) Walk

func (c *Client) Walk(path string, maxDepth int, fn func(Entry, string, int) error) error

Walk recursively lists the directory tree starting at path up to maxDepth levels, calling fn(entry, dirPath, depth) for every entry encountered.

func (*Client) Warm

func (c *Client) Warm(path string, depth int, progress func(string, int)) error

Warm pre-warms the cache by recursively listing directories to depth. progress is called after each directory is listed (may be nil).

type ClientOption

type ClientOption func(*Client)

ClientOption configures a Client.

func WithCacheDir

func WithCacheDir(dir string) ClientOption

WithCacheDir overrides the directory used for cache.db.

func WithListingTTL

func WithListingTTL(d time.Duration) ClientOption

WithListingTTL overrides the directory-listing TTL (default 1 h).

func WithPathTTL

func WithPathTTL(d time.Duration) ClientOption

WithPathTTL overrides the path→cid TTL (default 24 h).

func WithStats

func WithStats(s *logging.Stats) ClientOption

WithStats attaches a Stats tracker to the client for call counting.

type EC115Cipher

type EC115Cipher struct {
	// contains filtered or unexported fields
}

EC115Cipher holds all state for a single EC115 session.

func NewEC115Cipher

func NewEC115Cipher() (*EC115Cipher, error)

NewEC115Cipher generates a fresh P-224 key pair, performs ECDH with the 115 server public key, and derives the AES session key and IV.

func (*EC115Cipher) Decode

func (c *EC115Cipher) Decode(data []byte) ([]byte, error)

Decode AES-128-CBC decrypts then LZ4-block-decompresses the server response.

Format: ciphertext (all but last 12 bytes) | trailer (12 bytes) Trailer bytes 0–3 XOR'd with byte 7 give the total uncompressed size (uint32 LE). The decrypted plaintext is a sequence of chunks:

uint16 LE src_size | src_size bytes of lz4 block

Chunks are decompressed in at most 8 KiB steps until dst_size bytes are recovered.

func (*EC115Cipher) Encode

func (c *EC115Cipher) Encode(data []byte) []byte

Encode AES-128-CBC encrypts data. Input is zero-padded to a 16-byte boundary if not already aligned (no padding added when len(data)%16 == 0).

func (*EC115Cipher) EncodeToken

func (c *EC115Cipher) EncodeToken() string

EncodeToken builds the k_ec query parameter from the client public key.

Pack layout (little-endian uint32):

pubKey[:15] | 0x00 | uint32(115) | uint32(timestamp) | pubKey[15:] | 0x00 | uint32(1)
= 15 + 1 + 4 + 4 + 15 + 1 + 4 = 44 bytes

The first 24 bytes are XOR'd with random r1; the remaining bytes with r2. A CRC32 of (crcSalt + token) is appended as a little-endian uint32.

type Entry

type Entry struct {
	Name     string `json:"name"`
	Type     string `json:"type"` // "dir" or "file"
	NodeID   string `json:"node_id"`
	Size     int64  `json:"size,omitempty"`
	PickCode string `json:"pick_code,omitempty"`
	CID      string `json:"cid,omitempty"` // convenience: same as NodeID for dirs
	FID      string `json:"fid,omitempty"` // convenience: same as NodeID for files
}

Entry represents a single file or directory returned by the cloud API.

type QRSession

type QRSession struct {
	UID   string `json:"uid"`
	Time  string `json:"time"`
	Sign  string `json:"sign"`
	App   string `json:"app"`
	QRURL string `json:"qr_url"`
}

QRSession holds the state needed for a two-phase QR login.

type RapidResult

type RapidResult struct {
	Status   int
	PickCode string
}

RapidResult holds the result of a rapid-upload attempt.

type RateLimitState

type RateLimitState struct {
	CooldownUntil float64 `json:"cooldown_until"`
	LastRequest   float64 `json:"last_request"`
	MinuteStart   float64 `json:"minute_start"`
	MinuteCount   int     `json:"minute_count"`
}

RateLimitState holds per-endpoint rate-limit counters.

type RateLimiter

type RateLimiter struct {
	// contains filtered or unexported fields
}

RateLimiter enforces QPS and QPM limits, persisting state to SQLite via Cache. When cache is nil the limiter still tracks request counts but does not block.

func NewRateLimiter

func NewRateLimiter(name string, qps float64, qpm int, cache *Cache) *RateLimiter

NewRateLimiter creates a RateLimiter. name – key used in the rate_limit table (e.g. "api", "download"). qps – target queries per second (e.g. 0.5 means one request every 2 s). qpm – maximum requests per rolling 60-second window. cache – pass nil to disable persistence (no blocking beyond mutex).

func (*RateLimiter) Acquire

func (r *RateLimiter) Acquire() error

Acquire blocks until a slot is available, then increments the request count. Returns an error only when a cooldown is active. The mutex is released during any sleep so other goroutines are not blocked.

func (*RateLimiter) SetCooldown

func (r *RateLimiter) SetCooldown(seconds float64)

SetCooldown persists a cooldown_until timestamp for this limiter. After a 429 response the caller sets a cooldown so the next Acquire will fail immediately instead of retrying.

type SnapshotMeta

type SnapshotMeta struct {
	RootPath   string `json:"root_path"`
	ExportedAt string `json:"exported_at"`
	EntryCount string `json:"entry_count"`
}

SnapshotMeta holds metadata recorded alongside a tree snapshot.

type TreeEntry

type TreeEntry struct {
	Path    string `json:"path"`
	Name    string `json:"name"`
	Parent  string `json:"parent"`
	IsVideo bool   `json:"is_video"`
	IsNFO   bool   `json:"is_nfo"`
}

TreeEntry represents a single node in the cloud file tree snapshot.

type TreeStats

type TreeStats struct {
	Total  int `json:"total"`
	Videos int `json:"videos"`
	NFOs   int `json:"nfos"`
}

TreeStats holds counts of tree entries by type.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL