Skip to content

tgapis/TGLib

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

24 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“‘ TGLib

PyPI Version Python Versions License Stars Status

An experimental, full-featured MTProto Python client library for Telegram.

Built from scratch Β· Async-first Β· Lightweight Β· Telethon-style API


⚠️ TGLib is in early development. APIs may change without notice. Use in production at your own risk. Contributions and feedback are very welcome!


✨ Features

Feature Description
πŸ” Full MTProto Low-level Telegram protocol implementation
⚑ Async-first Built entirely on asyncio
πŸ”„ Sync & Async Use whichever style you prefer
πŸ—„οΈ Session Persistence SQLite, memory, and string sessions via aiosqlite
πŸ”’ Fast Encryption Auto-selects the fastest available AES backend
πŸ€– Bot & User Client Supports both bot tokens and phone login
πŸ“‘ Rich Event System NewMessage, Edited, Deleted, CallbackQuery, ChatAction, Raw
πŸͺΆ Lightweight Minimal dependencies, maximum control
🐍 Python 3.10+ Modern Python features throughout

πŸ“¦ Installation

# Recommended (with fastest crypto accelerator)
pip install tglib[cipheron]

# Alternative accelerator
pip install tglib[cryptogram]

# Basic install (pure Python fallback)
pip install tglib

# All accelerators β€” TGLib picks the fastest automatically
pip install tglib[all]

From source:

git clone https://github.com/ankit-chaubey/TGLib.git
cd TGLib
pip install -e .[cipheron]

πŸ”’ Crypto Backend Priority

TGLib automatically selects the fastest available AES/factorization backend:

Priority Package Description
1st βœ… cipheron ARM-CE / AES-NI via OpenSSL EVP β€” recommended
2nd cryptogram AES-NI with pure-Python fallback
3rd cryptg Legacy C extension (compatibility)
4th pycryptodome CTR/CBC only; IGE via Python
5th pyaes Pure-Python fallback (always available)

πŸš€ Quick Start

Get your api_id and api_hash from my.telegram.org. Never hardcode credentials β€” use environment variables!

export API_ID=your_api_id
export API_HASH=your_api_hash

πŸ“– Usage Styles

1. Async (recommended)

import asyncio, os
from tglib import TelegramClient

client = TelegramClient(
    session="my_session",
    api_id=int(os.environ["API_ID"]),
    api_hash=os.environ["API_HASH"],
)

async def main():
    await client.start(phone="+1234567890")
    me = await client.get_me()
    print(f"Logged in as: {me.first_name}")
    await client.disconnect()

asyncio.run(main())

2. Async Context Manager (cleanest)

import asyncio, os
from tglib import TelegramClient

async def main():
    async with TelegramClient(
        session="my_session",
        api_id=int(os.environ["API_ID"]),
        api_hash=os.environ["API_HASH"],
    ) as client:
        me = await client.get_me()
        print(f"Logged in as: {me.first_name}")

asyncio.run(main())

3. Sync (beginner-friendly, no asyncio needed)

import os
from tglib import TelegramClient

with TelegramClient(
    session="my_session",
    api_id=int(os.environ["API_ID"]),
    api_hash=os.environ["API_HASH"],
) as client:
    me = client.run(client.get_me())
    print(f"Logged in as: {me.first_name}")

πŸ€– Bot Examples

Respond to a command:

import asyncio, os
from tglib import TelegramClient, events

bot = TelegramClient("bot", int(os.environ["API_ID"]), os.environ["API_HASH"])

@bot.on(events.NewMessage(pattern="/start"))
async def start(event):
    await event.reply("Bot is running! πŸ‘‹")

asyncio.run(bot.start(bot_token=os.environ["BOT_TOKEN"]))
asyncio.run(bot.run_until_disconnected())

Userbot β€” respond to a pattern:

from tglib import TelegramClient, events

client = TelegramClient("session", API_ID, API_HASH)

@client.on(events.NewMessage(pattern="(?i)hello"))
async def greet(event):
    await event.reply("Hello there! πŸ‘‹")

async def main():
    await client.start(phone="+1234567890")
    await client.run_until_disconnected()

asyncio.run(main())

πŸ’¬ Sessions

# SQLite (default)
client = TelegramClient("my_session", api_id, api_hash)

# In-memory (no disk writes)
from tglib.sessions import MemorySession
client = TelegramClient(MemorySession(), api_id, api_hash)

# String session (env-var / database friendly)
from tglib.sessions import StringSession

# Generate once:
client = TelegramClient(StringSession(), api_id, api_hash)
await client.start(phone="+1234567890")
print(client.session.save())  # β†’ "1AQABAAHd..."  ← store this!

# Reuse:
client = TelegramClient(StringSession("1AQABAAHd..."), api_id, api_hash)

πŸ“‘ Events

from tglib import events

# New messages with regex pattern
@client.on(events.NewMessage(pattern=r"(?i)^/help"))
async def handler(event):
    await event.reply("Help text here")

# Outgoing messages only
@client.on(events.NewMessage(outgoing=True, pattern="!ping"))
async def pong(event):
    await event.reply("Pong!")

# Edited messages
@client.on(events.MessageEdited)
async def on_edit(event):
    print("Edited:", event.text)

# Deleted messages
@client.on(events.MessageDeleted)
async def on_del(event):
    print("Deleted IDs:", event.deleted_ids)

# Inline button presses (bots)
@client.on(events.CallbackQuery(data=b"btn_ok"))
async def on_btn(event):
    await event.answer("OK!", alert=False)
    await event.edit("Button pressed βœ…")

# Chat actions (joins, leaves, title changes)
@client.on(events.ChatAction)
async def on_action(event):
    if event.user_joined:
        await event.respond("Welcome!")

# Raw updates (any type)
@client.on(events.Raw)
async def raw(update):
    print(type(update).__name__, update)

# Filtered raw updates
from tglib.tl import types
@client.on(events.Raw(types.UpdateUserStatus))
async def status_change(update):
    print("Status:", update.status)

Dynamic handler management:

client.add_event_handler(my_handler, events.NewMessage(pattern="test"))
client.remove_event_handler(my_handler)

πŸ“¨ Messaging

# Send text (Markdown or HTML)
await client.send_message("me", "**Bold** and _italic_", parse_mode="md")
await client.send_message(chat_id, "<b>HTML</b> <i>text</i>", parse_mode="html")

# Reply, forward, pin
await client.send_message(chat, "Hello", reply_to=msg_id)
await client.forward_messages(target_chat, [msg_id], from_chat)
await client.pin_message(chat, msg_id)
await client.unpin_message(chat, msg_id)
await client.unpin_all_messages(chat)

# Edit and delete
await client.edit_message(chat, msg_id, "Updated text")
await client.delete_messages(chat, [msg_id1, msg_id2], revoke=True)

# Fetch messages
msgs = await client.get_messages(chat, limit=50)
msg  = await client.get_messages(chat, ids=[123, 456])

# Iterate messages
async for msg in client.iter_messages(chat, limit=500):
    print(msg.id, msg.message)

async for msg in client.iter_messages(chat, reverse=True, limit=200):
    ...

async for msg in client.iter_messages(chat, search="hello"):
    ...

messages = await client.iter_messages(chat, limit=100).collect()

πŸ“ Upload & Download

# Send files
await client.send_file(chat, "photo.jpg", caption="My photo")
await client.send_file(chat, "video.mp4", supports_streaming=True)
await client.send_file(chat, "doc.pdf", force_document=True)
await client.send_file(chat, "https://example.com/image.jpg")

# Album (up to 10 at a time)
await client.send_file(chat, ["photo1.jpg", "photo2.jpg", "photo3.jpg"])

# Voice / video note
await client.send_file(chat, "voice.ogg", voice_note=True)
await client.send_file(chat, "round.mp4", video_note=True)

# Download
path = await client.download_media(message)
path = await client.download_media(message, "/downloads/file.jpg")
data = await client.download_media(message, bytes)  # in-memory
path = await client.download_profile_photo("@username")

# Streaming
with open("video.mp4", "wb") as f:
    async for chunk in client.iter_download(message.media):
        f.write(chunk)

πŸ” Entity Resolution

user = await client.get_entity("me")
user = await client.get_entity("@username")
user = await client.get_entity("+1234567890")
user = await client.get_entity(123456789)
chat = await client.get_entity(-1001234567890)

# InputPeer (for raw API calls)
peer = await client.get_input_entity("@channel")

# Numeric ID
uid = await client.get_peer_id("@username")

βš™οΈ Raw API

from tglib.tl import functions, types

# Get full chat info
full = await client(functions.channels.GetFullChannelRequest(
    channel=await client.get_input_entity("@channel")
))

# Update profile
await client(functions.account.UpdateProfileRequest(
    first_name="New Name", bio="tglib user"
))

πŸ”€ Text Formatting

from tglib.extensions import markdown, html

text, entities = markdown.parse("**Bold** and __italic__ and `code`")
md_text = markdown.unparse(text, entities)

text, entities = html.parse("<b>Bold</b> and <a href='https://t.me'>link</a>")
html_text = html.unparse(text, entities)

Markdown syntax: **bold**, __italic__, ~~strikethrough~~, `code`, ||spoiler||, [text](url)

HTML tags: <b>, <i>, <u>, <s>, <code>, <pre>, <a href="...">, <blockquote>, <spoiler>


πŸ—ƒοΈ Entity Cache

print(client._entity_cache.stats())
# {'total': 42, 'live': 40, 'expired': 2, 'max_size': 10000, 'ttl': 3600}

from tglib.entitycache import EntityType
client._entity_cache.put(12345, EntityType.USER, access_hash=987654321)
client._entity_cache.invalidate(12345)

♾️ Keep Alive

# Async
await client.run_until_disconnected()

# Sync
client.run(client.run_until_disconnected())

πŸ”§ Dependencies

Package Purpose
pyaes AES encryption for MTProto
pycryptodome RSA and additional crypto
aiosqlite Async session storage
pillow (optional) Auto-resize photos before upload
aiofiles (optional) Async file I/O

🀝 Contributing

Contributions are very welcome!

# Fork the repo, then:
git clone https://github.com/YOUR_USERNAME/TGLib.git
cd TGLib
pip install -e .
  1. Create a branch: git checkout -b feature/your-feature
  2. Make your changes
  3. Push and open a Pull Request

πŸ› Issues & Feedback

Found a bug or have a suggestion? πŸ‘‰ Open an issue


πŸ™ Acknowledgements

TGLib builds upon the shoulders of:

  • Telethon by Lonami (MIT License) Core entity resolution logic, upload/download chunking, event system design, HTML/Markdown parsers, string session format, and more. Without Lonami's incredible work, TGLib would not exist.

All Telethon-derived code retains its original MIT License. See LICENSE for full details.


πŸ“„ License

This project is licensed under the MIT License see the LICENSE file for details.


πŸ‘€ Author

Ankit Chaubey


Made with ❀️ and Python

About

An experimental, full-featured MTProto Python client library for Telegram. Built from scratch. Async-first. Lightweight.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Python 100.0%