From 22f175966a4776c6e546d4664d017b06d18b0651 Mon Sep 17 00:00:00 2001 From: Alex55 Date: Wed, 25 Jun 2025 14:08:37 +0300 Subject: [PATCH] first commit --- .gitignore | 7 ++ .python-version | 1 + README.md | 1 + __pycache__/config.cpython-312.pyc | Bin 0 -> 419 bytes envprimer | 2 + main.py | 53 ++++++++++++++ pyproject.toml | 10 +++ utils/__pycache__/config.cpython-312.pyc | Bin 0 -> 425 bytes .../__pycache__/logging_setup.cpython-312.pyc | Bin 0 -> 2216 bytes utils/config.py | 10 +++ utils/logging_setup.py | 40 +++++++++++ uv.lock | 67 ++++++++++++++++++ 12 files changed, 191 insertions(+) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 README.md create mode 100644 __pycache__/config.cpython-312.pyc create mode 100644 envprimer create mode 100644 main.py create mode 100644 pyproject.toml create mode 100644 utils/__pycache__/config.cpython-312.pyc create mode 100644 utils/__pycache__/logging_setup.cpython-312.pyc create mode 100644 utils/config.py create mode 100644 utils/logging_setup.py create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f40304a --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/.venv +/logs +# Игнорируем файлы логов +*.log +.env +/tests +session.session \ No newline at end of file diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/README.md b/README.md new file mode 100644 index 0000000..50bdfd5 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Пример как следить когда пользователи были в онлайн) \ No newline at end of file diff --git a/__pycache__/config.cpython-312.pyc b/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ed0bd0e6cb27dc5a47413f9de345f65b0a081b0 GIT binary patch literal 419 zcmX@j%ge<81pBW=XFLSbk3k$5V1_b2mjM~m8B!Qh7;_kM8KW2(L2RZRrYI&RhE&GY zP-Tn^Kps;T8%#TbPGMfn2;oJs;8eo`SHqgZn!=XO6vbA_q{;pgq*0Uc7I#j5VoH2U zeo1Oxncpoo#{kcGPnTO9Alkz**y9#^S!O|MQAx=yj)0>4+}vD4BTe>OY!LNDAfMb~ z$}hgfmYxbS;1*kAL1uhr$}J8Mosn3aaZ8{iu?Q#`Us{}6l$V&BTD+3sGsx;+s`?rE zxvBa|Ii;!k<@rU~`bGvururr6#TnU&`pNluX_@JI1(mlrY;yBcN^?@}iUfhWK;A93 z1ri^a85tSxGRWO#;JnGe-NO5UgMmx9L#SV}Q*wgEWlos}wj10c9Y+0@ot6`#E^{k1 Va6Ax^ol$i`SnDE#KoLLC1OS38XW9S& literal 0 HcmV?d00001 diff --git a/envprimer b/envprimer new file mode 100644 index 0000000..f4fbfdd --- /dev/null +++ b/envprimer @@ -0,0 +1,2 @@ +API_ID= +API_HASH= \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..a3b1876 --- /dev/null +++ b/main.py @@ -0,0 +1,53 @@ +import asyncio +from datetime import datetime, timezone, timedelta +from telethon import TelegramClient +from telethon.tl.types import UserStatusOnline, UserStatusOffline + +import utils.config + +from utils.logging_setup import configure_global_logging + +logger = configure_global_logging() +config = utils.config + +# Список пользователей, которых отслеживаем + + +async def check_status(client, username): + try: + entity = await client.get_entity(username) + user_id = entity.id + username = entity.username or '' + user = await client.get_entity(user_id) + status = user.status + + # 1. Получаем тип статуса + status_type = type(status).__name__ + + logger.info(f"\nСледим за: {username} (ID: {user_id})") + + if status_type == 'UserStatusOffline': + was_online_utc = status.was_online + kiev_time = was_online_utc.astimezone(timezone(timedelta(hours=3))) + year, month, day = kiev_time.year, kiev_time.month, kiev_time.day + hour, minute, second = kiev_time.hour, kiev_time.minute, kiev_time.second + + logger.info(f"Статус: {status_type}") + logger.info(f"Последний онлайн (Киев): {year}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}") + + elif status_type == 'UserStatusOnline': + logger.info(f"Статус: {status_type} — Сейчас онлайн") + + else: + logger.info(f"Статус: {status_type} — Время скрыто или неизвестно") + + except Exception as e: + logger.info(f"⚠️ Ошибка при проверке {username}: {e}") + +async def main(): + async with TelegramClient('session', config.api_id, config.api_hash) as client: + tasks = [check_status(client, username) for username in config.target_usernames] + await asyncio.gather(*tasks) + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a7b61ba --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "tgshka" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "python-dotenv>=1.1.1", + "telethon>=1.40.0", +] diff --git a/utils/__pycache__/config.cpython-312.pyc b/utils/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f953cefa10feb571153a1ec96e029f9d31b31aa GIT binary patch literal 425 zcmX@j%ge<81pBW=XFLSbk3k$5V1_b2mjM~m8B!Qh7;_kM8KW2(L2RZRrYI&RhE&GY zP-Tn^Kps;T8%#TbPGMfn2;oJs;8eo`SHqgZn!=XO6vbA_q{;pgq*0Uc7I#j5VoH2U zeo1Oxncpoo#{kcGPnTO9Alkz**y9#^S!O|MQAx=yj)0>4+}vD4BTe>OY!LNDAfMb~ z$}hgfmYxbS;1*kAL1uhr$}J8Mosn3aaZ8{iu?Q#`Us{}6l$V&BTD+3sGsx;++WHy! zxvBa|Ii;!k<@rU~`bGvururr6#TnU&`lThAImP3Ri~w>WHa^HWN5QtgTa zfqFrnF17^{AD9^#8SgU4-Dcpt$-v#h`+QIC5RsixbwOC`B7;B?KhOjKK0<0h literal 0 HcmV?d00001 diff --git a/utils/__pycache__/logging_setup.cpython-312.pyc b/utils/__pycache__/logging_setup.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b009bdb524891f9b56a299e0cc0ec886cf3ba7db GIT binary patch literal 2216 zcmb_d-D?|15Z^nkPOC4wb}cNsu_6a6w$j*2oF;{~l%}R`Lv5!dfr3Ig&bqU{PCE7O z)LO9&E*P3TC8ZBGv=5>6OK=|YfAqzNMNe!SFw`%3GuTgk>g?&RQcX%Ibl`SocV=g2 zW@mr*OEelnKtKI@w-ECq^aq=G1apUubzoaaMlz?OEaSY&RroB=G1;g3DmaTd#G{Xq zj5m?&S5V3E>h5>huCF6x1z7-#zJF@jOb*Co1gs9HV`$%%$y)@w7h1{GGE`0fq% z1Uu7N6Tqu60K*1q_s1TtJy_c=SpDbs$oXRy>{1$2B8n^^QKTVJtY~swWpYFmzpP7Y zN25o<_6gG2CFl`0Fu%^gZrupLu!)X&&Oh0)Vd{Gk2-L_x&NCnsKlpS3yC@9#7G zO@Are)p$~q^DH<77OV`XXxE(^2WG#gYN96J^gYF13$F`J;g#Nn61%2T)Du5z(NiS* zz34m+Q3|ElDKnUw!`_+~Z+Az}8FA05%RT$`Kr`^l90LDS4uSug1KiCU-IzV8DRi^^ z7mGmGqNffo=@qXIFROvc+TEej8Bgl+?g>plK!LDy2i|_5Ch1DmG$>J4i-sv`Wt|-g z8d8x~KWvzaLBq>Zu3WFpY4xgk?@DS)GIC}Ski$scO-;e`Rva8L-bqcV#i~-((()I{ z>11lEq8Nsh2fK8?&fXdoI)_nzr7Rb98gK!G2J?!!0AQl%lmM74C|@Zm4HqQC#Y{tI zPm@MKH?Qdx$pjFj!5&ePH?rs_awI`FgTQ~09n7h7^CX~SWB8#8; zRp-bcq%1BwIY&A=+wr18;8EV`OVEoAGPr4L3qFpk6GcdR`~4i!x!3-q3y;q z^~A@=L-!*`0t&`#GG>vnZKXvf+GNNk;}#j;nY7PcvCduDd#kvAuGAuBN0YEf;>Wcg z)>~xyaCF=r%~+$E{n5+!``cvLCP|AVAIDl`(wR+IWMb!YJ9W)UUE6zG-A`3or0QrK z|8M?0-6EF`NS{qcEHbiv(b?zCGA(l9L_q$Cjbj#$?c-q^CoP=Z8MenSTjQ5ocoy>7 zSahI09n{%Nqp!IYoN=$g?G@;2v!E82-Nx(f4t!&2{-#rKoncw`XF|z)o!`#;`Yb3I z>>F2MIP!5E_Z#YajxIe%@e|B*laD61X1<#_K_DK5P~Vw$XyD<+2N&CY!|j2=li*oy H&~f`0LwC@& literal 0 HcmV?d00001 diff --git a/utils/config.py b/utils/config.py new file mode 100644 index 0000000..0c275ba --- /dev/null +++ b/utils/config.py @@ -0,0 +1,10 @@ +from dotenv import load_dotenv +import os +load_dotenv() + + +# db_host = os.getenv('DB_HOST') +api_id = os.getenv('API_ID') # замени на свой +api_hash = os.getenv('API_HASH') + +target_usernames = ['vipertt', 'Prommm12'] \ No newline at end of file diff --git a/utils/logging_setup.py b/utils/logging_setup.py new file mode 100644 index 0000000..93aae2d --- /dev/null +++ b/utils/logging_setup.py @@ -0,0 +1,40 @@ +import logging +from logging.handlers import RotatingFileHandler +from pathlib import Path + +class MyAppFilter(logging.Filter): + def filter(self, record): + return record.name == "my_app" + +def configure_global_logging( + log_file="logs/app.log", + level=logging.INFO, + max_bytes=5_000_000, + backup_count=3 +): + log_file_path = Path(log_file) + log_file_path.parent.mkdir(parents=True, exist_ok=True) + + logger = logging.getLogger("my_app") + logger.setLevel(level) + + if not logger.hasHandlers(): + file_handler = RotatingFileHandler( + log_file, maxBytes=max_bytes, backupCount=backup_count + ) + file_handler.setLevel(level) + file_handler.setFormatter(logging.Formatter("%(asctime)s [%(filename)s:%(lineno)d] - %(message)s")) + file_handler.addFilter(MyAppFilter()) + + console_handler = logging.StreamHandler() + console_handler.setLevel(level) + console_handler.setFormatter(logging.Formatter("%(asctime)s [%(filename)s:%(lineno)d] - %(message)s")) + console_handler.addFilter(MyAppFilter()) + + logger.addHandler(file_handler) + logger.addHandler(console_handler) + + # Отключаем все другие логгеры + logging.getLogger().setLevel(logging.CRITICAL) + + return logger diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..5690fed --- /dev/null +++ b/uv.lock @@ -0,0 +1,67 @@ +version = 1 +revision = 2 +requires-python = ">=3.12" + +[[package]] +name = "pyaes" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/66/2c17bae31c906613795711fc78045c285048168919ace2220daa372c7d72/pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f", size = 28536, upload-time = "2017-09-20T21:17:54.23Z" } + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + +[[package]] +name = "telethon" +version = "1.40.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyaes" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/af/9b7111e3f63fffe8e55b7ceb8bda023173e2052f420b6debcb25fd2fbc15/telethon-1.40.0.tar.gz", hash = "sha256:40e83326877a2e68b754d4b6d0d1ca5ac924110045b039e02660f2d67add97db", size = 646723, upload-time = "2025-04-21T09:12:10.506Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/5a/c5370edb3215d19a6e858f4169b8eec725ba55f9d39df0f557508048c037/Telethon-1.40.0-py3-none-any.whl", hash = "sha256:146fd4cb2a7afa66bc67f9c2167756096a37b930f65711a3e7399ec9874dcfa7", size = 722013, upload-time = "2025-04-21T09:12:08.399Z" }, +] + +[[package]] +name = "tgshka" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "python-dotenv" }, + { name = "telethon" }, +] + +[package.metadata] +requires-dist = [ + { name = "python-dotenv", specifier = ">=1.1.1" }, + { name = "telethon", specifier = ">=1.40.0" }, +]