Skip to main content

Python client library for TeleStore — Telegram-backed file storage

Project description

telestore

A lightweight Python client library for TeleStore — a free file-storage service that uses Telegram channels as its backend.


1. What is TeleStore?

TeleStore is a REST API service that lets you store files up to 2 GB inside Telegram channels — for free. It exposes a simple HTTP API that is authentication via an API key, making it easy to use as a drop-in file-storage backend for lightweight SaaS products or hobby projects. This library wraps that API into an ergonomic Python interface so you can go from zero to first upload in under 5 minutes.

→ Live instance: https://telestore.onrender.com


2. Installation

pip install telestore

For better MIME-type detection (strongly recommended), also install python-magic:

pip install telestore python-magic
# On Windows you may also need the libmagic binary:
pip install python-magic-bin

python-magic is entirely optional — the library falls back to filename-based detection via the standard library mimetypes module when it is not installed.


3. Getting Your API Key

  1. Sign up at https://telestore.onrender.com/auth/signup/
  2. Log in and navigate to https://telestore.onrender.com/api-keys/
  3. Click Generate Key, give it a name, and copy the key starting with sk-

Keep your API key secret. Anyone who has it can upload files on your behalf.


4. Quickstart

From zero to first upload in under 10 lines:

from telestore import TeleStoreClient

client = TeleStoreClient(api_key="sk-your-api-key-here")

# Upload a file
result = client.upload("photo.jpg")
print(result.view_url)   # share this link

# Upload JSON data directly
result = client.upload_json({"user": "alice", "score": 42})
data = client.download_json(result.file_id)

# Upload raw text
result = client.upload_text("Hello, TeleStore!")
text = client.download_text(result.file_id)

5. Usage Examples

Creating the client

from telestore import TeleStoreClient

client = TeleStoreClient(
    api_key="sk-your-api-key-here",
    base_url="https://telestore.onrender.com",  # default — change for self-hosted
    timeout=120,                                 # seconds; default is 120
)

Uploading files

From a file path:

result = client.upload("path/to/document.pdf")
print(result.file_id)       # opaque identifier — keep this private
print(result.view_url)      # publicly accessible inline URL
print(result.download_url)  # publicly accessible attachment URL
print(result.mime_type)     # e.g. "application/pdf"
print(result.size_bytes)    # size in bytes

From bytes:

data = b"raw binary content"
result = client.upload(data, filename="data.bin")

From a file-like object:

with open("archive.zip", "rb") as fh:
    result = client.upload(fh)

From a remote URL:

result = client.url_upload("https://example.com/image.png")

Uploading typed content

Image (validates MIME type):

# Raises UploadError if the file is not actually an image.
result = client.upload_image("photo.jpg")

Plain text:

result = client.upload_text("Hello, world!", filename="greeting.txt")
# Custom encoding:
result = client.upload_text("こんにちは", filename="jp.txt", encoding="utf-8")

JSON dict:

result = client.upload_json({"key": "value", "items": [1, 2, 3]})

Downloading files

Into memory:

raw: bytes = client.download("abc123")

To disk:

from pathlib import Path

path = client.download("abc123", destination="downloads/file.bin")
# path is a pathlib.Path pointing to the saved file

As text:

text: str = client.download_text("abc123")

As JSON:

data: dict = client.download_json("abc123")

Getting URLs without a network call

view_url     = client.get_url("abc123", mode="view")      # inline
download_url = client.get_url("abc123", mode="download")  # attachment

6. Configuration

Parameter Default Description
api_key (required) Your TeleStore API key (sk-...).
base_url https://telestore.onrender.com Change this only when using a self-hosted TeleStore instance.
timeout 120 Request timeout in seconds. Files larger than 50 MB use a slower Telethon-based upload path on the server, so the default is intentionally generous.

Loading credentials from the environment:

import os
from dotenv import load_dotenv
from telestore import TeleStoreClient

load_dotenv()  # reads .env file

client = TeleStoreClient(
    api_key=os.environ["TELESTORE_API_KEY"],
    base_url=os.getenv("TELESTORE_BASE_URL", "https://telestore.onrender.com"),
)

Copy .env.example to .env and fill it in:

TELESTORE_API_KEY=sk-your-api-key-here
TELESTORE_BASE_URL=https://telestore.onrender.com

7. Error Handling

All exceptions inherit from TeleStoreError so you can catch them at any level of specificity:

from telestore import (
    TeleStoreClient,
    TeleStoreError,       # base — catches everything below
    AuthenticationError,  # 401 — bad or missing API key
    UploadError,          # upload failed
    DownloadError,        # download failed
    FileSizeError,        # file exceeds 2 GiB
    FileNotFoundError,    # file_id not found on server
    ServerError,          # 5xx from TeleStore
)

client = TeleStoreClient(api_key="sk-...")

try:
    result = client.upload("huge_file.iso")
except FileSizeError as exc:
    print(f"File too large: {exc}")
except AuthenticationError:
    print("Check your API key.")
except UploadError as exc:
    print(f"Upload failed: {exc}")
except ServerError as exc:
    print(f"TeleStore server error: {exc}")
except TeleStoreError as exc:
    # Catch-all for any other library error
    print(f"TeleStore error: {exc}")

Note: telestore.FileNotFoundError shadows the Python built-in in this namespace. Import it explicitly by name if you need both in the same scope.


8. File Deletion

Delete files from TeleStore using the delete endpoint:

# Delete a file
client.delete("abc123")

# The file is removed from both Telegram and TeleStore database

9. Advanced Patterns

Retry Logic with Tenacity

from tenacity import retry, stop_after_attempt, wait_exponential
from telestore import TeleStoreClient, TeleStoreError

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    reraise=True
)
def upload_with_retry(client: TeleStoreClient, path: str):
    return client.upload(path)

client = TeleStoreClient(api_key="sk-...")
result = upload_with_retry(client, "large_file.iso")

Batch Upload with Progress Tracking

from pathlib import Path
from telestore import TeleStoreClient

client = TeleStoreClient(api_key="sk-...")
files_dir = Path("./documents")

results = []
for i, file_path in enumerate(files_dir.glob("*.pdf"), 1):
    print(f"Uploading {i}/{len(list(files_dir.glob('*.pdf')))}{file_path.name}")
    result = client.upload(file_path)
    results.append(result)
    print(f"  ✓ {result.view_url}")

# Save file_id mappings for later retrieval
with open("uploaded_files.txt", "w") as f:
    for result in results:
        f.write(f"{result.original_filename},{result.file_id}\n")

Monitoring Upload Progress

For real-time progress during large file uploads, implement custom streaming:

import requests
from pathlib import Path

client = TeleStoreClient(api_key="sk-...")
file_path = Path("large_video.mp4")
file_size = file_path.stat().st_size

# Upload with callback
with open(file_path, "rb") as f:
    # Implement custom progress tracking here
    result = client.upload(f, filename=file_path.name)

Integration with Django

# In a Django view
from django.http import JsonResponse
from telestore import TeleStoreClient, UploadError

def upload_document(request):
    if not request.FILES.get('document'):
        return JsonResponse({'error': 'No file'}, status=400)
    
    try:
        client = TeleStoreClient(api_key=request.user.telestore_api_key)
        result = client.upload(request.FILES['document'])
        
        # Save mapping in your database
        UserFile.objects.create(
            user=request.user,
            filename=result.original_filename,
            file_id=result.file_id,
            size_bytes=result.size_bytes
        )
        
        return JsonResponse({
            'success': True,
            'view_url': result.view_url,
            'file_id': result.file_id
        })
    except UploadError as e:
        return JsonResponse({'error': str(e)}, status=400)

Integration with FastAPI

from fastapi import FastAPI, UploadFile, Depends, HTTPException
from telestore import TeleStoreClient

app = FastAPI()

def get_telestore_client() -> TeleStoreClient:
    return TeleStoreClient(api_key="sk-...")

@app.post("/upload/")
async def upload_file(
    file: UploadFile,
    client: TeleStoreClient = Depends(get_telestore_client)
):
    try:
        content = await file.read()
        result = client.upload(content, filename=file.filename)
        return {
            "file_id": result.file_id,
            "view_url": result.view_url,
            "download_url": result.download_url
        }
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

10. Limitations & Known Issues

Current Limitations

  • Files larger than 50 MB are uploaded through a slower Telethon MTProto path on the server side, which is significantly slower than the Bot API path. The default 120-second timeout accommodates this, but very large files on slow connections may still time out — increase timeout as needed.
  • View and download URLs are publicly accessible — no authentication required. Anyone who knows a file_id can access the file. Treat file_id values as secrets for sensitive content.
  • No file listing on anonymous accesslist_files() requires authentication. You must track file_id values yourself if uploading anonymously.
  • No async support in v0.1 — fully synchronous. Async support (asyncio / httpx) planned for v0.2.
  • No built-in retry logic — failed requests raise immediately. Use tenacity for automatic retries.
  • python-magic is optional — without it, MIME detection falls back to filename extension, less reliable for binary.

Planned Features

  • Async/await support
  • Streaming uploads with progress callbacks
  • File expiration and TTL
  • Signed/time-limited URLs
  • Multi-part uploads for large files
  • Batch operations
  • WebSocket support for real-time updates

11. Troubleshooting

"Invalid or missing API key (HTTP 401)"

Cause: API key not set, empty, or revoked.

Fix:

# Make sure your API key is valid
client = TeleStoreClient(api_key="sk-abc1234...")  # Must start with 'sk-'

# Regenerate key at https://telestore.onrender.com/api-keys/

"File size exceeds 2 GB"

Cause: Attempting to upload a file larger than Telegram's limit.

Fix:

# Split large files or use cloud storage instead
from telestore import FileSizeError

try:
    result = client.upload("huge_file.iso")
except FileSizeError:
    print("Use a different storage backend for files > 2 GB")

"Upload request failed: Connection timeout"

Cause: Server taking too long (slow network or large file via Telethon).

Fix:

# Increase timeout for large files
client = TeleStoreClient(api_key="sk-...", timeout=300)  # 5 minutes

"The requested file was not found (HTTP 404)"

Cause: File was deleted or file_id is incorrect.

Fix:

# Verify file_id before download
from telestore import FileNotFoundError

try:
    data = client.download("invalid_file_id")
except FileNotFoundError:
    print("File has been deleted or never existed")

"python-magic not installed"

Cause: Optional dependency missing.

Fix:

# Install for better MIME detection
pip install python-magic
pip install python-magic-bin  # Windows only

12. Performance Tips

  1. Use python-magic for accurate MIME detection — without it, guessing fails for binary files.
  2. Set appropriate timeout — 120s default, but increase for files >100 MB.
  3. Batch operations — upload multiple files sequentially rather than in parallel (Telegram rate limits).
  4. Stream large downloads to disk — don't load into memory:
    path = client.download("abc123", destination="cache/file.bin")
    
  5. Cache file_id values — avoid re-uploading same content.
  6. Use get_url() for public links — no network call, instant URL generation.

13. Contributing

Contributions are welcome! Please follow these guidelines:

Setting Up Development Environment

git clone <repo-url>
cd Telestore_library_v0.1
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# Install development dependencies
pip install -e ".[dev]"

Running Tests

# Run all tests
pytest tests/

# Run with coverage
pytest --cov=telestore tests/

# Run specific test
pytest tests/test_client.py::test_upload

Code Style

# Format code
black telestore tests

# Lint
flake8 telestore tests

# Type checking
mypy telestore

Submitting Changes

  1. Create a feature branch: git checkout -b feature/my-feature
  2. Write tests for new functionality
  3. Ensure all tests pass: pytest
  4. Format code: black . && flake8 .
  5. Commit: git commit -am "Add my feature"
  6. Push: git push origin feature/my-feature
  7. Open a pull request with clear description

Requirements for PR acceptance:

  • All tests must pass
  • Type hints for all new functions
  • Docstrings for all public methods
  • No breaking changes to existing API

14. API Reference

TeleStoreClient

class TeleStoreClient:
    """
    Synchronous HTTP client for TeleStore REST API.
    
    Attributes:
        api_key (str): Your TeleStore API key
        base_url (str): Server URL
        timeout (int): Request timeout in seconds
    """
    
    def __init__(
        self,
        api_key: str,
        base_url: str = "https://telestore.onrender.com",
        timeout: int = 120,
    ) -> None: ...
    
    def upload(
        self,
        source: Union[str, Path, bytes, IO[bytes]],
        filename: Optional[str] = None,
    ) -> UploadedFile: ...
    
    def download(
        self,
        file_id: str,
        destination: Optional[Union[str, Path]] = None,
    ) -> Union[bytes, Path]: ...
    
    def delete(self, file_id: str) -> None: ...
    
    def list_files(self, ids_only: bool = False) -> List[Dict]: ...
    
    def list_file_ids(self) -> List[str]: ...
    
    def get_url(self, file_id: str, mode: str = "view") -> str: ...
    
    def url_upload(
        self,
        url: str,
        filename: Optional[str] = None,
    ) -> UploadedFile: ...
    
    def upload_image(
        self,
        source: Union[str, Path, bytes, IO[bytes]],
        filename: Optional[str] = None,
    ) -> UploadedFile: ...
    
    def upload_text(
        self,
        text: str,
        filename: str = "file.txt",
        encoding: str = "utf-8",
    ) -> UploadedFile: ...
    
    def upload_json(
        self,
        data: Dict,
        filename: str = "data.json",
    ) -> UploadedFile: ...
    
    def download_text(
        self,
        file_id: str,
        encoding: str = "utf-8",
    ) -> str: ...
    
    def download_json(self, file_id: str) -> Dict: ...

UploadedFile

@dataclass
class UploadedFile:
    """
    Metadata for a successfully uploaded file.
    
    Attributes:
        file_id (str): Opaque file identifier
        view_url (str): Inline viewing URL (no auth required)
        download_url (str): Download/attachment URL (no auth required)
        original_filename (str): Filename used at upload
        size_bytes (int): File size in bytes
        mime_type (str): Detected MIME type
    """
    file_id: str
    view_url: str
    download_url: str
    original_filename: str
    size_bytes: int
    mime_type: str

Exception Hierarchy

TeleStoreError (base)
├── AuthenticationError          # 401, bad/missing API key
├── UploadError                  # Upload failed
├── DownloadError                # Download failed
├── FileSizeError                # File > 2 GB
├── FileNotFoundError             # 404, file_id not found
└── ServerError                  # 5xx, server error

15. FAQ

Q: Can I use TeleStore in production?
A: Yes, but it's a self-hosted service. TeleStore is production-ready for small-to-medium workloads. For mission-critical systems, implement backups and redundancy at the server level.

Q: What happens if Telegram deletes/bans my channel?
A: Files become inaccessible. The server tracks this via the is_banned flag on channels. TeleStore includes automatic backup to secondary channels to mitigate this.

Q: Can I encrypt files before uploading?
A: Not built-in, but you can encrypt client-side before calling upload(). Decrypt after downloading.

Q: Is there a quota per user?
A: Not enforced in v0.1. Server admin can implement rate limiting if needed.

Q: Can I run my own TeleStore instance?
A: Yes! Fork the server repository and self-host. See server README for setup.


License

MIT License — see LICENSE for details.


Made with ❤️ for developers who want free file storage

Project details


Download files

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

Source Distribution

telestore-0.1.0.tar.gz (22.0 kB view details)

Uploaded Source

Built Distribution

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

telestore-0.1.0-py3-none-any.whl (16.7 kB view details)

Uploaded Python 3

File details

Details for the file telestore-0.1.0.tar.gz.

File metadata

  • Download URL: telestore-0.1.0.tar.gz
  • Upload date:
  • Size: 22.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.1

File hashes

Hashes for telestore-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e1ec08e4f6cf3fe53dc0e6a83dda03f5c60882c52b60b8d30ceb84deb6b1a54a
MD5 a5ee0ca7dc884947eb54ff94ea1b738c
BLAKE2b-256 5ae8b8aa0c83c2b9b6fd333bf00157c7f0b5bc2fa4ddb2b03a1f864ea1b384c0

See more details on using hashes here.

File details

Details for the file telestore-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: telestore-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.1

File hashes

Hashes for telestore-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f43f08eb47f33a49466f9a999f3a0be182f1dd34f4c29cd9b75b3fccadfde17f
MD5 1c66618264611e931545fec35becbed3
BLAKE2b-256 f27607cc39091bf640b122569f401cb1b64859135ead20f55736b66a95cac2c9

See more details on using hashes here.

Supported by

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