From 00c8aa847d7079c3e8502135817de0553e2ce413 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Mon, 7 Jan 2019 15:48:25 +0100 Subject: [PATCH] Tidy examples and update licenses --- LICENSE | 2 +- telethon_examples/LICENSE | 116 ++++++++++++++++++++++++++ telethon_examples/README.md | 120 +++++++++++++++++++++++++++ telethon_examples/README.txt | 15 ---- telethon_examples/print_messages.py | 52 ++++++++++++ telethon_examples/print_updates.py | 35 ++++---- telethon_examples/replier.py | 111 +++++++++++++------------ telethon_examples/screenshot-gui.jpg | Bin 0 -> 26010 bytes 8 files changed, 366 insertions(+), 85 deletions(-) create mode 100644 telethon_examples/LICENSE create mode 100644 telethon_examples/README.md delete mode 100644 telethon_examples/README.txt create mode 100644 telethon_examples/print_messages.py create mode 100644 telethon_examples/screenshot-gui.jpg diff --git a/LICENSE b/LICENSE index 39baeff7..7a430dd1 100755 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016 LonamiWebs +Copyright (c) 2016-2019 LonamiWebs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/telethon_examples/LICENSE b/telethon_examples/LICENSE new file mode 100644 index 00000000..670154e3 --- /dev/null +++ b/telethon_examples/LICENSE @@ -0,0 +1,116 @@ +CC0 1.0 Universal + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see + diff --git a/telethon_examples/README.md b/telethon_examples/README.md new file mode 100644 index 00000000..acab382d --- /dev/null +++ b/telethon_examples/README.md @@ -0,0 +1,120 @@ +# Examples + +This folder contains several single-file examples using [Telethon]. + +## Requisites + +You should have the `telethon` library installed with `pip`. +Run `python3 -m pip install --upgrade telethon --user` if you don't +have it installed yet (this is the most portable way to install it). + +Examples assume you have the following environment variables defined: + +* `TG_API_ID`, this is your API ID from https://my.telegram.org. +* `TG_API_HASH`, this is your API hash from https://my.telegram.org. +* `TG_TOKEN`, this is your bot token from [@BotFather] for bot examples. +* `TG_SESSION`, this is the name of the `*.session` file to use. + +You can ignore any of these, and the scripts will prompt you to enter them. + +## Downloading Examples + +You may download all and run any example with by typing in a terminal: +```sh +git clone https://github.com/LonamiWebs/Telethon.git +cd Telethon +cd telethon_examples +python3 gui.py +``` + +You can also right-click the title of any example and use "Save Link As…" to +download only a particular example. + +All examples are licensed under the [CC0 License], so you can use +them as the base for your own code without worrying about copyright. + +## Available Examples + +### [`print_updates.py`] + +* Usable as a: **user and bot**. +* Difficulty: **easy**. + +Trivial example that just prints all the updates Telegram originally +sends. Your terminal should support UTF-8, or Python may fail to print +some characters on screen. + +### [`print_messages.py`] + +* Usable as a: **user and bot**. +* Difficulty: **easy**. + +This example uses the different `@client.on` syntax to register event +handlers, and uses the `pattern=` variable to filter only some messages. + +There are a lot other things you can do, but you should refer to the +documentation of [`events.NewMessage`] since this is only a simple example. + +### [`replier.py`] + +* Usable as a: **user and bot**. +* Difficulty: **easy**. + +This example showcases a third way to add event handlers (using decorators +but without the client; you should use the one you prefer) and will also +reply to some messages with different reactions, or to your commands. + +It also shows how to enable `logging`, which you should always do, but was +not really needed for the previous two trivial examples. + +### [`assistant.py`] + +* Usable as a: **bot**. +* Difficulty: **medium**. + +This example is the actual bot account [@TelethonianBot] running in the +[official Telethon's chat] to help people out. The file is a bit big and +assumes some [`asyncio`] knowledge, but otherwise is easy to follow. + +### [`interactive_telegram_client.py`] + +* Usable as a: **user and bot**. +* Difficulty: **medium**. + +Interactive terminal client that you can use to list your dialogs, +send messages, delete them, and download media. The code is a bit +long which may make it harder to follow, and requires saving some +state in order for downloads to work later. + +### [`gui.py`] + +* Usable as a: **user and bot**. +* Difficulty: **high**. + +This is a simple GUI written with [`tkinter`] which becomes more complicated +when there's a need to use [`asyncio`] (although it's only a bit of additional +setup). The code to deal with the interface and the commands the GUI supports +also complicate the code further and require knowledge and careful reading. + +This example is the actual bot account [@TelethonianBot] running in the +[official Telethon's chat] to help people out. The file is a bit big and +assumes some [`asyncio`] knowledge, but otherwise is easy to follow. + +![Screenshot of the tkinter GUI][tkinter GUI] + + +[Telethon]: https://github.com/LonamiWebs/Telethon +[CC0 License]: https://github.com/LonamiWebs/Telethon/blob/master/telethon_examples/LICENSE +[@BotFather]: https://t.me/BotFather +[`assistant.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/assistant.py +[`gui.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/gui.py +[`interactive_telegram_client.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/interactive_telegram_client.py +[`print_messages.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/print_messages.py +[`print_updates.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/print_updates.py +[`replier.py`]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/replier.py +[@TelethonianBot]: https://t.me/TelethonianBot +[official Telethon's chat]: https://t.me/TelethonChat +[`asyncio`]: https://docs.python.org/3/library/asyncio.html +[`tkinter`]: https://docs.python.org/3/library/tkinter.html +[tkinter GUI]: https://raw.githubusercontent.com/LonamiWebs/Telethon/master/telethon_examples/screenshot-gui.jpg +[`events.NewMessage`]: https://telethon.readthedocs.io/en/stable/telethon.events.html#telethon.events.newmessage.NewMessage diff --git a/telethon_examples/README.txt b/telethon_examples/README.txt deleted file mode 100644 index 73af9702..00000000 --- a/telethon_examples/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -You should be able to run these files with python3 filename.py after -installing Telethon (`pip3 install .` on the root of the project if you -haven't installed it yet and you downloaded the repository). - -Most of these examples assume you have the following variables defined -in your environment: - - TG_API_ID, this is the api ID of your Telegram application. - TG_API_HASH, similarly, this is the api hash. - TG_TOKEN, for bot examples, this should be the bot token. - TG_SESSION, this is the session file name to be (re)used. - -See https://superuser.com/q/284342 to learn how to define them. -It's more convenient to define them, but if you forget to do so, -the scripts will ask you to enter the variables when ran. diff --git a/telethon_examples/print_messages.py b/telethon_examples/print_messages.py new file mode 100644 index 00000000..21aafc59 --- /dev/null +++ b/telethon_examples/print_messages.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# A simple script to print some messages. +import os +import sys +import time + +from telethon import TelegramClient, events, utils + + +def get_env(name, message, cast=str): + if name in os.environ: + return os.environ[name] + while True: + value = input(message) + try: + return cast(value) + except ValueError as e: + print(e, file=sys.stderr) + time.sleep(1) + + +session = os.environ.get('TG_SESSION', 'printer') +api_id = get_env('TG_API_ID', 'Enter your API ID: ', int) +api_hash = get_env('TG_API_HASH', 'Enter your API hash: ') +proxy = None # https://github.com/Anorov/PySocks + +# Create and start the client so we can make requests (we don't here) +client = TelegramClient(session, api_id, api_hash, proxy=proxy).start() + + +# `pattern` is a regex, see https://docs.python.org/3/library/re.html +# Use https://regexone.com/ if you want a more interactive way of learning. +# +# "(?i)" makes it case-insensitive, and | separates "options". +@client.on(events.NewMessage(pattern=r'(?i).*\b(hello|hi)\b')) +async def handler(event): + sender = await event.get_sender() + name = utils.get_display_name(sender) + print(name, 'said', event.text, '!') + +try: + print('(Press Ctrl+C to stop this)') + client.run_until_disconnected() +finally: + client.disconnect() + +# Note: We used try/finally to show it can be done this way, but using: +# +# with client: +# client.run_until_disconnected() +# +# is almost always a better idea. diff --git a/telethon_examples/print_updates.py b/telethon_examples/print_updates.py index a93992ca..48ade9d4 100755 --- a/telethon_examples/print_updates.py +++ b/telethon_examples/print_updates.py @@ -1,12 +1,16 @@ #!/usr/bin/env python3 -# A simple script to print all updates received +# A simple script to print all updates received. +# Import modules to access environment, sleep, write to stderr import os import sys import time +# Import the client from telethon import TelegramClient +# This is a helper method to access environment variables or +# prompt the user to type them in the terminal if missing. def get_env(name, message, cast=str): if name in os.environ: return os.environ[name] @@ -19,28 +23,23 @@ def get_env(name, message, cast=str): time.sleep(1) -client = TelegramClient( - os.environ.get('TG_SESSION', 'printer'), - get_env('TG_API_ID', 'Enter your API ID: ', int), - get_env('TG_API_HASH', 'Enter your API hash: '), - proxy=None -) +# Define some variables so the code reads easier +session = os.environ.get('TG_SESSION', 'printer') +api_id = get_env('TG_API_ID', 'Enter your API ID: ', int) +api_hash = get_env('TG_API_HASH', 'Enter your API hash: ') +proxy = None # https://github.com/Anorov/PySocks -async def update_handler(update): +# This is our update handler. It is called when a new update arrives. +async def handler(update): print(update) -client.add_event_handler(update_handler) +# Use the client in a `with` block. It calls `start/disconnect` automatically. +with TelegramClient(session, api_id, api_hash, proxy=proxy) as client: + # Register the update handler so that it gets called + client.add_event_handler(handler) -'''You could also have used the @client.on(...) syntax: -from telethon import events - -@client.on(events.Raw) -async def update_handler(update): - print(update) -''' - -with client.start(): + # Run the client until Ctrl+C is pressed, or the client disconnects print('(Press Ctrl+C to stop this)') client.run_until_disconnected() diff --git a/telethon_examples/replier.py b/telethon_examples/replier.py index 3f109abd..f11c39b4 100755 --- a/telethon_examples/replier.py +++ b/telethon_examples/replier.py @@ -6,26 +6,17 @@ This script assumes that you have certain files on the working directory, such as "xfiles.m4a" or "anytime.png" for some of the automated replies. """ import os -import re import sys import time from collections import defaultdict -from datetime import datetime, timedelta from telethon import TelegramClient, events -"""Uncomment this for debugging import logging -logging.basicConfig(level=logging.DEBUG) -logging.debug('dbg') -logging.info('info') -""" +logging.basicConfig(level=logging.WARNING) -REACTS = {'emacs': 'Needs more vim', - 'chrome': 'Needs more Firefox'} - -# A list of dates of reactions we've sent, so we can keep track of floods -recent_reacts = defaultdict(list) +# "When did we last react?" dictionary, 0.0 by default +recent_reacts = defaultdict(float) def get_env(name, message, cast=str): @@ -40,6 +31,60 @@ def get_env(name, message, cast=str): time.sleep(1) +def can_react(chat_id): + # Get the time when we last sent a reaction (or 0) + last = recent_reacts[chat_id] + + # Get the current time + now = time.time() + + # If 10 minutes as seconds have passed, we can react + if now - last < 10 * 60: + # Make sure we updated the last reaction time + recent_reacts[chat_id] = now + return True + else: + return False + + +# Register `events.NewMessage` before defining the client. +# Once you have a client, `add_event_handler` will use this event. +@events.register(events.NewMessage) +async def handler(event): + # There are better ways to do this, but this is simple. + # If the message is not outgoing (i.e. someone else sent it) + if not event.out: + if 'emacs' in event.raw_text: + if can_react(event.chat_id): + await event.reply('> emacs\nneeds more vim') + + elif 'vim' in event.raw_text: + if can_react(event.chat_id): + await event.reply('> vim\nneeds more emacs') + + elif 'chrome' in event.raw_text: + if can_react(event.chat_id): + await event.reply('> chrome\nneeds more firefox') + + # Reply always responds as a reply. We can respond without replying too + if 'shrug' in event.raw_text: + if can_react(event.chat_id): + await event.respond(r'¯\_(ツ)_/¯') + + # We can also use client methods from here + client = event.client + + # If we sent the message, we are replying to someone, + # and we said "save pic" in the message + if event.out and event.reply_to_msg_id and 'save pic' in event.raw_text: + reply_msg = await event.get_reply_message() + replied_to_user = await reply_msg.get_input_sender() + + message = await event.reply('Downloading your profile photo...') + file = await client.download_profile_photo(replied_to_user) + await message.edit('I saved your photo in {}'.format(file)) + + client = TelegramClient( os.environ.get('TG_SESSION', 'replier'), get_env('TG_API_ID', 'Enter your API ID: ', int), @@ -47,45 +92,9 @@ client = TelegramClient( proxy=None ) +with client: + # This remembers the events.NewMessage we registered before + client.add_event_handler(handler) -@client.on(events.NewMessage) -async def my_handler(event: events.NewMessage.Event): - global recent_reacts - - # Through event.raw_text we access the text of messages without format - words = re.split('\W+', event.raw_text) - - # Try to match some reaction - for trigger, response in REACTS.items(): - if len(recent_reacts[event.chat_id]) > 3: - # Silently ignore triggers if we've recently sent 3 reactions - break - - if trigger in words: - # Remove recent replies older than 10 minutes - recent_reacts[event.chat_id] = [ - a for a in recent_reacts[event.chat_id] if - datetime.now() - a < timedelta(minutes=10) - ] - # Send a reaction as a reply (otherwise, event.respond()) - await event.reply(response) - # Add this reaction to the list of recent actions - recent_reacts[event.chat_id].append(datetime.now()) - - # Automatically send relevant media when we say certain things - # When invoking requests, get_input_entity needs to be called manually - if event.out: - chat = await event.get_input_chat() - if event.raw_text.lower() == 'x files theme': - await client.send_file(chat, 'xfiles.m4a', - reply_to=event.message.id, voice_note=True) - if event.raw_text.lower() == 'anytime': - await client.send_file(chat, 'anytime.png', - reply_to=event.message.id) - if '.shrug' in event.text: - await event.edit(event.text.replace('.shrug', r'¯\_(ツ)_/¯')) - - -with client.start(): print('(Press Ctrl+C to stop this)') client.run_until_disconnected() diff --git a/telethon_examples/screenshot-gui.jpg b/telethon_examples/screenshot-gui.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4da34b0ac8b027123b8183c8a06aaa7889ebf44e GIT binary patch literal 26010 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 T*@Qh!)Bx!}$yJEdu4exOJ`PiR literal 0 HcmV?d00001