Metadata-Version: 2.4
Name: kcfinder-client
Version: 0.2.2
Summary: Python client library for KCFinder file manager
Project-URL: Changelog, https://github.com/cyberops7/kcfinder-client/releases
Project-URL: Issues, https://github.com/cyberops7/kcfinder-client/issues
Project-URL: Repository, https://github.com/cyberops7/kcfinder-client
License-Expression: MIT
License-File: LICENSE
Keywords: file-manager,httpx,kcfinder,php
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: httpx>=0.28
Description-Content-Type: text/markdown

# kcfinder-client

[![CI](https://github.com/cyberops7/kcfinder-client/actions/workflows/ci.yml/badge.svg)](https://github.com/cyberops7/kcfinder-client/actions/workflows/ci.yml)
![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)

A Python client library for [KCFinder](https://github.com/sunhater/kcfinder),
a PHP web file manager. Wraps KCFinder's HTTP action-dispatch API into a clean
Python interface with both async and sync clients.

> [!NOTE]
> Designed for and tested against HarmonySite's KCFinder fork.
> May work with other KCFinder instances via `SessionAuth`, but this
> has not been tested.

## Table of Contents

- [Install](#install)
- [Quick Start](#quick-start)
- [Auth from Environment Variables](#auth-from-environment-variables)
- [Sync Files with SyncManager](#sync-files-with-syncmanager)
- [Documentation](#documentation)

## Install

```bash
# uv
uv add kcfinder-client

# pip
pip install kcfinder-client
```

## Quick Start

### Async (recommended)

```python
import asyncio
import os
from kcfinder_client import AsyncKCFinderClient, HarmonySiteAuth

auth = HarmonySiteAuth(
    login_url="https://example.harmonysong.com/dbaction.php",
    browse_url="https://example.harmonysong.com/kcfinder/browse.php",
    username="admin",
    password="secret",
    bros_config=(
        'a:3:{s:9:"uploadDir";s:6:"files/";'
        's:9:"thumbsDir";s:14:"files/.thumbs/";'
        's:9:"uploadURL";s:0:"";}'
    ),
)

async def main():
    browse_url = "https://example.harmonysong.com/kcfinder/browse.php"
    async with AsyncKCFinderClient(browse_url, auth) as client:
        files = await client.list_files("banners")
        for f in files:
            print(f.name, f.size)

asyncio.run(main())
```

### Sync

```python
from kcfinder_client import KCFinderClient, HarmonySiteAuth

auth = HarmonySiteAuth(
    login_url="https://example.harmonysong.com/dbaction.php",
    browse_url="https://example.harmonysong.com/kcfinder/browse.php",
    username="admin",
    password="secret",
    bros_config=(
        'a:3:{s:9:"uploadDir";s:6:"files/";'
        's:9:"thumbsDir";s:14:"files/.thumbs/";'
        's:9:"uploadURL";s:0:"";}'
    ),
)

browse_url = "https://example.harmonysong.com/kcfinder/browse.php"
with KCFinderClient(browse_url, auth) as client:
    files = client.list_files("banners")
    for f in files:
        print(f.name, f.size)
```

## Auth from Environment Variables

Load credentials from the environment rather than hardcoding them:

```bash
export KCFINDER_LOGIN_URL=https://example.harmonysong.com/dbaction.php
export KCFINDER_BROWSE_URL=https://example.harmonysong.com/kcfinder/browse.php
export KCFINDER_USERNAME=admin
export KCFINDER_PASSWORD=secret
export KCFINDER_BROS_CONFIG='a:3:{s:9:"uploadDir";s:6:"files/";s:9:"thumbsDir";s:14:"files/.thumbs/";s:9:"uploadURL";s:0:"";}'
```

```python
import os
from kcfinder_client import AsyncKCFinderClient, harmonysite_auth_from_env
import asyncio

async def main():
    auth = harmonysite_auth_from_env()
    browse_url = os.environ["KCFINDER_BROWSE_URL"]
    async with AsyncKCFinderClient(browse_url, auth) as client:
        files = await client.list_files()
        print(f"Found {len(files)} files")

asyncio.run(main())
```

## Timeouts & Retries

Both clients accept optional `timeout` and `retries` parameters:

```python
from kcfinder_client import KCFinderClient

# Set a 30-second timeout
with KCFinderClient(browse_url, auth, timeout=30.0) as client:
    files = client.list_files()

# Retry up to 3 times on connection errors and 5xx responses
with KCFinderClient(browse_url, auth, retries=3) as client:
    files = client.list_files()

# Both together
with KCFinderClient(browse_url, auth, timeout=30.0, retries=3) as client:
    files = client.list_files()
```

- **`timeout`** — passed to the underlying `httpx` client. Accepts a `float`
  (seconds) or an `httpx.Timeout` object for fine-grained control. Defaults
  to the httpx default of 5 seconds.
- **`retries`** — number of retry attempts for transient failures (connection
  errors and HTTP 5xx responses). Uses exponential backoff between attempts.
  Defaults to `0` (no retries). Uploads are never retried.

## Sync Files with SyncManager

One-way push sync to make a remote directory match a local one:

```python
import os
from pathlib import Path
from kcfinder_client import KCFinderClient, SyncManagerSync, harmonysite_auth_from_env

auth = harmonysite_auth_from_env()
browse_url = os.environ["KCFINDER_BROWSE_URL"]

with KCFinderClient(browse_url, auth) as client:
    sync = SyncManagerSync(client)

    # Dry run first to preview changes
    result = sync.push("banners", Path("./banners"), dry_run=True)
    print(f"Would upload: {result.uploaded}")
    print(f"Would delete: {result.deleted}")
    print(f"Would skip:   {result.skipped}")

    # Apply the sync
    result = sync.push("banners", Path("./banners"))
```

## Documentation

- [Auth setup](docs/auth.md) — HarmonySiteAuth, SessionAuth, env vars
- [File operations](docs/files.md) — list, upload, download, delete, rename,
  thumbnails
- [Directory operations](docs/directories.md) — tree, expand, create, rename,
  delete
- [Bulk operations](docs/bulk.md) — copy, move, bulk delete, download selected
- [Sync manager](docs/sync.md) — push sync, dry run, SyncResult
- [Exceptions](docs/exceptions.md) — error handling, exception hierarchy

## License

MIT
