Dalawa ang API ng Telegram. Sa bot ang isa. Ang isa, ikaw: ang mga chat mo, ang mga group mo, ang pangalan mo sa bawat message na lalabas. Hindi mo kailangang maging programmer para dito. Kailangan mo lang maintindihan kung ano ang ginagawa mo at kung saan ka pwedeng masaktan. Si Claude na ang bahala sa code.
Dalawa ang paraan para makausap ng program ang Telegram. Magkaiba sila nang husto. Kapag mali ang napili mo, hindi ito aayusin, uulitin mo talaga.
Ang bot ay bagong account na gagawin mo. May sarili siyang pangalan, sarili niyang larawan, at may nakasulat na BOT sa tabi nito. Sinadya ng Telegram na limitado siya: hindi niya mababasa ang usapan bago siya sumali, at hindi siya pwedeng mauna magmessage sa kahit sino.
Ang MTProto naman ang totoong wika ng mga opisyal na Telegram app. Ang Telethon ay isang Python library na marunong nito. Mag-lo-login ka gamit ang number mo at ang code na itetext sa iyo, katulad lang ng pag-install ng Telegram sa bagong laptop. Pagkatapos noon, parang isa nang device mo ang script mo. Lahat ng nakikita mo, nakikita niya. Lahat ng ipapadala niya, galing sa iyo.
Kapag ikaw ang nagpadala, bawal ang button. Kung susubukan mong ilagay, error ang isasagot ng Telegram, hindi keyboard. Kaya kung ang gusto mo ay "magpost ako tapos may pipindutin sila sa ilalim", hindi mo iyon magagawa mula sa account mo. Reaction ang kapalit. At kapag nagawa mo na ito nang ganoon, malamang mas gusto mo pa: isang tap lang, alam na ng lahat kung paano, at walang dagdag na nakasabit sa message.
Ito lang ang kailangan mo. Kung wala ka pa ng isa dito, dito ka muna, huwag ka nang lumaktaw.
Windows, Mac, o Linux, pareho lang. Hindi ito kayang gawin sa cellphone lang, kaya kung cellphone lang ang meron ka, dito na muna tayo huminto.
Libre. Pumunta sa python.org, i-download, i-install. Sa Windows, may checkbox doon na Add Python to PATH. Huwag mo itong kakalimutang lagyan ng tsek, dahil kapag hindi, hindi gagana ang mga utos sa baba.
Ito yung itim na window kung saan ka nagta-type ng utos. Sa Windows, hanapin mo sa Start ang PowerShell. Sa Mac, hanapin mo ang Terminal. Nakakatakot lang ito sa unang tingin. Isang beses mo lang matututunan.
Buksan ang Telegram, pumunta sa Settings, tapos Privacy and Security, tapos Two-Step Verification. Gawin mo ito ngayon bago pa ang lahat. Ito ang nagpapahirap sa iba na nakawin ang account mo.
Siya ang magsusulat ng code. Ikaw ang magsasabi kung ano ang gusto mong mangyari, at ikaw ang magtsetsek kung tama ang ginawa niya. May buong bahagi sa ibaba tungkol sa kung paano siya kausapin para hindi ka masayangan ng oras.
May totoo ka bang gagamitan nito? Ang pinakaligtas na gamit ay sa mga group na kasapi ka na, at ilang message lang bawat araw. Ang delikado ay ang magpadala sa mga taong hindi ka naman kinakausap. Kung wala ka pang tiyak na gagamitan, basahin mo muna ito hanggang dulo bago ka mag-install ng kahit ano.
Isang ideya lang ang kailangan mong maintindihan. Kapag na-gets mo ito, obvious na ang lahat ng susunod.
Bawat device na naka-login sa account mo ay parehong nakakakita ng lahat, at parehong pwedeng magpadala. Ganito talaga gawa ang Telegram. Ito ang dahilan kung bakit sabay na nagbabasa ang cellphone at laptop mo.
Ang script mo ay hindi kumakatok sa account mo mula sa labas, tulad ng ginagawa ng bot. Naka-login siya, katabi ng ibang device mo. Kapag na-gets mo ito, hindi ka na magugulat sa kahit anong kaya niyang gawin.
Isang api_id at api_hash mula sa my.telegram.org. Ito ang pangalan ng program mo, hindi ikaw. Isang beses mo lang kukunin, tapos gamitin mo na habambuhay.
Gagawin ito sa unang login mo, gamit ang number mo at ang code. Isusulat ito ng Telethon sa isang file. Sa susunod na patakbo mo, babasahin na lang niya ito, hindi ka na tatanungin ulit.
Ang buhay na koneksyon. May bukas siyang linya sa Telegram kaya alam niya agad kapag may bago. Kaya nga kailangan itong laging bukas, hindi naka-schedule.
Mga function na nagsasabing "kapag ganito ang dumating, gawin mo ito". Dito lang talaga nakatira ang gusto mong mangyari. Plumbing na lang ang lahat ng iba.
Wala ang mga ito sa karaniwang tutorial. Lahat ng lima, mararanasan mo sa unang linggo.
Ang reply_markup ay para lang sa bot. Kaya ang pipindutin nila, kailangang ilipat mo sa iba: reaction sa message, reply, o isang salitang ita-type nila. Desisyunan mo ito bago mo pa idisenyo ang feature, hindi pagkatapos.
Sa kahit anong message na nakikita mo, kaya mong itanong sa Telegram kung sino ang nag-react at ano ang inilagay nila. Buong sistema na iyon ng "sino ang nakabasa", at hindi ka na kailangang mag-imbento ng bagong UI. Marunong na silang lahat mag-react.
Ang bot, konti lang ang nakikita. Ang script mo, buong Telegram mo ang nakikita: trabaho, pamilya, pati yung group na naka-mute ka. Kaya ang unang linya ng bawat handler ay tsek kung tama ba ang chat, bago pa may kahit anong mangyari. Ito ang pinakamadalas na pagkakamali ng bago.
Sasagot siya ng FloodWaitError na may kasamang bilang ng segundo. Ang tamang gawin ay matulog nang ganoon kadami. Ang mali ay ulitin agad, at doon nagiging ban ang simpleng hintay.
Hindi ito API key na kayang palitan sa isang website. Kung sino ang may hawak ng file na iyon, siya ang naka-login bilang ikaw, at hindi na siya hihingian ng 2FA. Huwag mong ilalagay sa GitHub. Huwag mong ipapadala sa chat. Huwag mong isasama sa backup na naka-share sa iba.
Mas mahalaga ang pagkakasunod kaysa sa code mismo. Bawat hakbang, pinapaliit ang kayang sirain ng pagkakamali mo, kaya pagdating mo sa totoong group, alam mo nang gumagana ito.
Pumunta sa my.telegram.org, mag-login gamit ang number mo, tapos gumawa ng bagong app doon para makuha ang api_id at api_hash. Kopyahin mo ang dalawang iyon sa ligtas na lugar.
Sa terminal, i-install ang library. Pagkatapos, patakbuhin mo ang pinakamaliit na script na nagpi-print lang ng pangalan mo. Iyon lang muna. Kapag gumana ito, detalye na lang ang lahat ng susunod.
pip install telethon
Isang handler lang, at i-print lahat ng nakikita niya. Huwag mo munang isulat ang parteng nagpapadala. Patakbuhin mo ito sa buong araw habang normal kang gumagamit ng Telegram.
Makikita mo kung ano talaga ang laman ng mga dumadaan, at magugulat ka kung gaano kaingay ang account mo. Dito mo idagdag ang tsek ng chat, habang wala pa siyang kayang sirain.
Ipadala mo muna lahat sa Saved Messages, yung sarili mong chat sa sarili mo. Sa code, "me" lang ang ilalagay mo bilang padadalhan. Walang mapapahiya doon.
Subukan mo doon ang pagpapadala, pag-edit, at pagbura, pati na yung mga pangit na kaso: mag-edit ng message na wala na, magpadala ng text na may weird na character, at sadyain mong maabot ang limit para makita mo mismo kung ano ang mangyayari.
Palitan mo ang padadalhan ng totoong chat ID, na nakalagay sa config file at hindi nakasulat sa gitna ng code. Panatilihing maliit ang parteng nagpapadala: isang function na nagpapadala, isa na nag-e-edit, at pareho silang tinatanong kung saan ipapadala.
Lahat ng nagdedesisyon kung ano ang laman ng message, ilagay mo sa hiwalay na function na kaya mong subukan kahit walang internet. Doon nagtatago ang halos lahat ng bug.
May bukas siyang koneksyon, kaya hindi ito cron job. Kailangan niya ng maliit na server na laging bukas, o container na kusang nagre-restart kapag namatay.
Ilagay mo ang session file sa labas, tapos i-mount mo lang kapag tumatakbo. Huwag mong isasama sa image. At i-log mo ang bawat reconnect at bawat flood wait, kasi dalawang linyang iyon ang magsasabi sa iyo na may mali bago pa magsabi ang Telegram.
Magpost sa group, tapos makita kung sino ang nakabasa na at sino ang hinihintay pa, nasa loob mismo ng message. Ito ang madalas na hinahanap ng mga gumagawa nito.
Kung bot ito, maglalagay ka ng button sa ilalim tapos bibilangin mo ang mga pindot. Hindi mo iyon kayang gawin dito. Kaya reaction ang gagamitin ng message. Mag-tatap sila ng reaction na alam na nilang gamitin, mapapansin ito ng script, magbibilang siya ulit, tapos babaguhin niya ang sarili niyang message. Parehong resulta, mas kaunti pa ang nakasabit sa screen.
Ang mahalaga dito ay ang render. Binibigyan mo siya ng listahan kung sino ang nakabasa, at text ang isinasagot niya. Walang internet, walang Telegram. Kaya mo itong subukan mag-isa, at doon mismo nagtatago ang halos lahat ng mali sa ganitong feature.
# announce.py
import os
from telethon import TelegramClient
# Galing sa environment, hindi nakasulat dito, para walang
# masamang aksidente kapag na-share mo ang code.
API_ID = int(os.environ["TG_API_ID"])
API_HASH = os.environ["TG_API_HASH"]
GROUP = int(os.environ["TG_GROUP_ID"]) # -100... kapag supergroup
# Sino ang hinihintay. Kunin mo ang mga ID sa Hakbang 1.
ROSTER = {
5205736813: "Jeff",
286255193: "Glenn",
935778918: "Yoyot",
}
client = TelegramClient(os.environ["TG_SESSION"], API_ID, API_HASH)
def render(body, acked):
"""Malinis na function. State ang papasok, text ang lalabas."""
nakabasa = [n for uid, n in ROSTER.items() if uid in acked]
hinihintay = [n for uid, n in ROSTER.items() if uid not in acked]
linya = [body, "", f"Nakabasa {len(nakabasa)}/{len(ROSTER)}"]
linya += [f" {n}" for n in nakabasa] or [" wala pa"]
if hinihintay:
linya += ["", "Hinihintay pa"] + [f" {n}" for n in hinihintay]
else:
linya += ["", "Kumpleto na."]
return "\n".join(linya)
async def post(body):
msg = await client.send_message(GROUP, render(body, acked={}))
return msg.id # itago mo ito. ito ang susi sa lahat sa baba
Hindi maganda ang dating ng reaction sa Telethon. Wala siyang madaling handler, kaya raw update ang sasaluhin natin. Hindi rin maaasahan kung sino ang sinasabi ng update na nag-react, kaya ituring mo na lang itong tapik sa balikat: may nagbago, bilangin mo ulit.
# watch.py
from telethon import events
from telethon.tl.types import UpdateMessageReactions
TRACKED = set() # mga message id na atin
@client.on(events.Raw(types=[UpdateMessageReactions]))
async def on_reaction(update):
# Tsek muna, palagi. Buong account mo ang nakikita nito.
if update.msg_id not in TRACKED:
return
await refresh(update.msg_id)
# Pansinin: msg_id ang pangalan dito, hindi message_id.
# Ganito talaga sa raw types. Kapag may hindi ka sigurado,
# tingnan mo muna sa tl.telethon.dev bago mo isulat.
Bilangin ulit mula sa umpisa, huwag mong dagdagan ang luma. Ang bilang na dinadagdagan ay nalilito kapag sabay-sabay ang nag-tap. Ang bilang na kinukuha ulit mula sa Telegram, hindi. At ang FloodWaitError na nakikita mo dito, hindi iyon palamuti.
# refresh.py
import asyncio
from telethon.errors import FloodWaitError, MessageNotModifiedError
from telethon.tl.functions.messages import GetMessageReactionsListRequest
BODIES = {} # msg_id -> orihinal na text
async def refresh(msg_id):
try:
res = await client(GetMessageReactionsListRequest(
peer=GROUP, id=msg_id, limit=100,
))
except FloodWaitError as e:
# Matulog nang eksakto sa hinihingi niya. Huwag uulitin agad.
await asyncio.sleep(e.seconds)
return
acked = {}
for r in res.reactions:
uid = getattr(r.peer_id, "user_id", None)
if uid is not None:
acked.setdefault(uid, r.date) # unang tap ang bibilangin
try:
await client.edit_message(GROUP, msg_id, render(BODIES[msg_id], acked))
except MessageNotModifiedError:
pass # dalawang beses nag-tap. wala namang bago
except FloodWaitError as e:
await asyncio.sleep(e.seconds)
Isang program lang ito na laging bukas. Ang run_until_disconnected ang naghihintay. Walang polling, walang cron. Ito rin ang pinakamadalas na pagkakamali ng bago: nakakalimutan ang linyang ito, kaya lumalabas na walang nangyayari kahit tama naman ang code.
# main.py
import asyncio
async def main():
await client.start() # hihingi ng code sa unang takbo lang
body = "Alis tayo bukas ng 6am. Mag-react kapag nabasa mo na."
msg_id = await post(body)
BODIES[msg_id] = body
TRACKED.add(msg_id)
print("naipadala", msg_id)
await client.run_until_disconnected() # dito siya maghihintay
if __name__ == "__main__":
asyncio.run(main())
# Nasa memory lang ang TRACKED at BODIES dito para madaling
# basahin. Sa totoong gamit, ilagay mo sa SQLite para hindi
# mawala ang lahat kapag nag-restart.
Nakasulat ito base sa kasalukuyang dokumentasyon ng Telethon at MTProto, at hindi pa ito napapatakbo sa totoong account. Ituring mong hugis ng solusyon, hindi tapos na produkto. Ang pag-verify nito ang mismong dahilan kung bakit may Hakbang 0 hanggang 2. Kapag may pangalan na nagbago, ang tl.telethon.dev ang masusunod, hindi ang page na ito.
Magaling siya sa kalahati ng trabahong ito, at hindi maaasahan sa kabilang kalahati. Ang malaman kung alin ang alin, iyon na halos ang buong diskarte.
Magaling siya dito: ang gawing gumaganang code ang sinasabi mong "kapag nangyari ang ganito, gusto ko ganito". Pati na ang mga nakakainip na parte tulad ng paghihintay at pag-uulit. Pati na ang lohika kung ano ang isusulat sa message, na doon naman talaga nagtatago ang mga bug.
Dito ka niya masasaktan: ang eksaktong pangalan ng mga bahagi ng MTProto.
Isusulat niyang update.message_id kahit msg_id pala talaga, o gagamit
siya ng function na wala naman. At kumpiyansa pa siya habang ginagawa niya. Napakalaki ng
library at hindi mahuhulaan ang mga pangalan, kaya hindi ito matatapos ng "mag-ingat ka ha".
Ang solusyon: bigyan mo siya ng reference, hindi lang ng utos. Nasa tl.telethon.dev ang bawat function at bawat type. Sabihin mo sa kanya na buksan muna ang page bago siya magsulat, at pabasahin mo sa kanya pabalik ang mga pangalan. Isang utos lang iyon, pero doon mawawala ang halos lahat ng sayang na oras.
Gusto kong gumawa ng script na tatakbo sa sarili kong Telegram
account gamit ang Telethon. Hindi bot, ako mismo.
Ang gusto kong mangyari:
[isulat mo dito, halimbawa: "kapag nagpost ako ng announcement sa
group namin, gusto kong makita kung sino na ang nakabasa"]
Hindi ako programmer, kaya:
- Ipaliwanag mo sa simpleng salita kung ano ang ginagawa ng bawat file
- Sabihin mo kung ano mismo ang ita-type ko sa terminal
- Sabihin mo kung ano ang dapat kong makita kapag tama
- Kapag may error, ipaliwanag mo muna bago mo ayusin
Simulan natin sa Hakbang 0: patunayan lang na naka-connect ako at
mapa-print ang pangalan ko. Huwag muna tayong magpadala kahit kanino.
Tutulungan mo akong gumawa ng Telethon script na tatakbo sa personal
kong Telegram account. Hindi ito bot. Lahat ng ipapadala nito ay
lalabas na galing sa akin.
Mahigpit na patakaran sa lahat ng code na isusulat mo dito:
1. Huwag kang magpapadala, mag-e-edit, magbubura o magfo-forward sa
kahit anong chat maliban sa "me" (Saved Messages), maliban na lang
kung may binigay akong chat ID sa mismong mensaheng humihingi.
2. Bawat handler, magsisimula sa pagtsek ng chat o message ID, at
agad na titigil kapag hindi tugma, bago pa ang kahit anong logic.
3. Balutin mo ng FloodWaitError handler ang bawat tawag na pwedeng
umabot sa limit, at matulog ng e.seconds. Huwag uulitin agad,
huwag mo ring tatahimikin.
4. Huwag mong ipi-print, ilo-log, o ipapakita ang laman ng session
file, ang api_hash, o ang login code.
5. Bawal ang inline keyboard sa user account. Kapag ang hinihingi ko
ay kailangan ng button, sabihin mong hindi ito kaya, huwag kang
magsusulat ng reply_markup.
6. Bago ka gumamit ng raw type o Request class, buksan mo muna ang
page nito sa tl.telethon.dev at ibalik mo sa akin ang eksaktong
pangalan ng mga attribute. Huwag kang manghuhula, at huwag mong
kukunin sa Bot API dahil magkaiba ang pangalan doon.
7. Ilagay mo sa hiwalay na malilinis na function ang pagbuo ng text
ng message: state ang papasok, string ang lalabas, walang tawag
sa internet, para matest ito offline.
# Telegram automation, personal account
Telethon sa totoong user account. Walang bot dito. Lahat ng
ipapadala ng repo na ito, lalabas sa chat na ako ang nagsabi.
## Hindi pwedeng labagin
- Ang test na padala ay sa Saved Messages ("me"). Ang totoong chat
ID ay galing sa config, at pagkatapos lang ma-test ang render.
- Ang session file ay katumbas ng password ko. Hindi ico-commit,
hindi ilo-log, hindi isasama sa kahit anong image.
- Bawat handler, tsek muna ng chat o message ID bago ang lahat.
- Ang FloodWaitError ay sinasagot ng pagtulog ng e.seconds. Hindi
inuulit agad.
- Walang inline keyboard dito. Reaction at reply lang.
## Ayos ng mga file
config.py api_id, api_hash, chat ids galing sa env. Walang literal.
client.py Paggawa at pagbukas ng client lang.
handlers/ Isang file kada feature. Tsek muna, saka gagalaw.
render.py Malilinis na function. State papasok, text lalabas.
store.py SQLite. Para hindi mawala ang message ids kapag nag-restart.
## Paano ko titsekin ang bago
Patakbuhin muna sa Saved Messages. Ilipat lang sa totoong group
kapag may test na ang render.py sa lahat ng pwedeng lumabas.
## Reference
Raw types at requests: tl.telethon.dev. Doon tingnan ang pangalan
bago isulat. Hindi pareho ang pangalan sa Bot API.
Ipagawa mo muna kay Claude ang function na bumubuo ng text, kasama ang test nito, bago pa may humipo sa Telegram. Matatapos mo ang parteng nagdedesisyon kung ano ang babasahin ng tao, nasubukan na lahat, tumatakbo sa isang segundo, walang account na kasama. Ang matitira ay padala na lang, at ang padala ay gumagana o may error, walang gitna.
Totoo ang panganib pero hindi ito pantay-pantay. Nakadepende ito sa ugali mo, hindi sa gamit mo.
Kapag nakuha ito ng iba, nakuha na nila ang account mo. Hindi ka masasagip ng 2FA kasi nakalampas na doon ang session. Ilagay mo sa labas ng project folder, chmod 600 kung Mac o Linux, at huwag mong isasama sa backup na naka-share. Kapag naghinala kang nakuha ito: buksan ang Telegram, Settings, Devices, tanggalin mo ang session na iyon, tapos mag-login ka ulit.
Ang account na kaka-join lang last week tapos biglang nagpadala ng automated na message, iyan mismo ang hinahanap ng anti-spam. Kung bago ang account, hayaan mo muna itong kumilos na parang tao nang matagal-tagal bago mo automate-in. Ibang-iba ang trato sa account na may taon-taon nang normal na kasaysayan.
Matulog ka ng buong bilang ng segundo na binigay niya. Kapag umaabot na ng oras-oras ang hinihintay, patayin mo muna at tingnan mong mabuti kung ano ang ginagawa niya, kasi sinasabi na sa iyo ng Telegram na mukha na itong masamang klase ng automated. Normal lang ang ilang segundo kapag sabay-sabay ang padala.
Ang pagbabasa ng group na kasapi ka na, at pagpost ng ilang message kada araw sa bilis ng tao, hindi iyon ang hinahabol ng anti-spam. Tumataas nang matarik ang panganib kapag nagmessage ka sa hindi mo kilala, sumali ka sa maraming group nang sabay, kinukuha mo ang listahan ng members, o dumami ang padala. Manatili ka sa mga usapang kasali ka na, at convenience lang ito, hindi operasyon.
Tungkol naman sa patakaran: ang API terms ng Telegram ay nakasulat para sa mga gumagawa ng client app, at hindi nito sinasabi nang diretso kung pwede bang i-automate ang sarili mong account. Kaya walang malinis na masasabing oo o hindi. Sa totoong buhay, ang ugali ang binabantayan, hindi ang gamit. Walang naghahanap ng Telethon. Ang hinahanap nila, mukhang spam.
Ito ang apat na madalas na sumalubong sa nagsisimula. Ipakita mo kay Claude ang eksaktong error, pero mas mabuti kung alam mo kung ano ang ibig sabihin.
run_until_disconnected(), natatapos agad ang program bago pa man dumating ang kahit anong message. Mukhang tahimik lang ang script, patay na pala.Halos lahat ng script na tumatakbo sa personal account, itong sampung linya lang, iba-ibang ayos.
Dalawang reference ang bahala sa lahat ng iba. Ang docs.telethon.dev ang madaling parte: ang mga client method, ang mga event, ang mga karaniwang halimbawa. Ang tl.telethon.dev naman ang listahan ng bawat raw MTProto type at request, at ito ang bubuksan mo sa sandaling lumabas ka sa mga madaling method.