How to download incoming image marked as spoiler with telethon? - python

I'm trying to create a client able to forward and store all the media sent to him via telegram. Everything works fine with all media types, the problem occurs when the client receives a media marked as spoiler. The media is usually stored in the event.media attribute, but when this happens the media type is MessageMediaUnsupported, so there is no way to extract the actual media file. I'm running version 1.26.1 of telethon, and the author told me I should be able to do what i want. What am I missing?
This is the code I'm using:
from telethon import TelegramClient
async def newMessageHandler(client,event):
print(type(event.media)) #this prints "MessageMediaUnsupported" when receiving a spoiler media
client=TelegramClient("username","api_id","api_hash")
client.start(phone="phone_number")
#client.on(events.NewMessage())
async def handler(event):
asyncio.create_task(newMessageHandler(client,event))
asyncio.get_event_loop().run_forever()

Related

Is it possible to check if a session has been created?

I was trying to check if a new session has been created using the telethon library.
My first idea was to get the warning message from Telegram (New access: [...]), so when I get that kind of message, I know that another device has connected to my account.
I couldn't get that message, so I tried to get it another way:
chat = client.get_entity(777000) # Telegram chat id
print(chat)
for message in client.iter_messages(chat):
print(message.text)
(This is not the full code.)
The only message I was able to retrieve was the confirmation code, but only with that I can't do anything.
Another idea was to continuously receive the list of active sessions (using GetAuthorizationsRequest()) and, if that list changed, it means that a new device has connected to my account. But is it convenient to continuously send requests to Telegram servers?
I searched everywhere but couldn't find a good solution to my problem.
Any help is appreciated.
With the help of Lonami, I was able to solve my problem.
With client.iter_messages(chat), I could only view messages, while the "message" I was looking for was an UpdateServiceNotification, so I used events.Raw to get all types of updates.
Here is the code:
from telethon.sync import TelegramClient, events
from telethon.tl.types import UpdateServiceNotification
api_id = 123456
api_hash = "42132142c132145ej"
with TelegramClient('anon', api_id, api_hash) as client:
#client.on(events.Raw(func = lambda e: type(e) == UpdateServiceNotification))
async def handler(event):
print("New Login!")
client.run_until_disconnected()

Microsoft Bot Emulator showing "sending failed. Retry". VSCode shows KeyError: 'HTTP_CONTEXT_TYPE'

I am new to Microsoft Bot Framework, I am learning it through a youtube video https://youtu.be/ynG6Muox81o and making my bot on python3 on Ubuntu.
The Microsoft Bot Emulator says "sending failed. Retry".
Visual Studio Code shows KeyError: 'HTTP_CONTEXT_TYPE'.
I did everything right, my bot is connected to http://localhost:3978/, and bot emulator is connected to http://localhost:3978/api/messages/.
Many people on stackoverflow who had the same issue faced it due to windows firewall, but mine is ubuntu and i did check if it was enabled but its not.
app.py
from flask import Flask, request, Response
from botbuilder.schema import Activity
from botbuilder.core import BotFrameworkAdapter,BotFrameworkAdapterSettings
import asyncio
from echobot import EchoBot
app = Flask(__name__)
loop = asyncio.get_event_loop()
botadaptersettings=BotFrameworkAdapterSettings("","")
botadapter = BotFrameworkAdapter(botadaptersettings)
ebot = EchoBot()
#POST is the message
#app.route("/api/messages",methods=["POST"])
def messages():
#checking if HTTP file format is JSON or not
if "application/json" in request.headers["context-type"]:
#reading the JSON message
jsonmessage = request.json
else:
#unsupported media type 415
return Response(status=415)
activity = Activity().deserialize(jsonmessage)
async def turn_call(turn_context):
await ebot.on_turn(turn_context)
task = loop.create_task(botadapter.process_activity(activity,"",turn_call))
loop.run_until_complete(task)
if __name__ == '__main__':
app.run('localhost',3978)
echobot.py
from botbuilder.core import TurnContext
class EchoBot:
async def on_turn(self,turn_context:TurnContext):
await turn_context.send_activity(turn_context.activity.text)
I cant seem to understand the issue and how to fix it. it would be really helpfull if someone could help me fix this as i am really interested in building bots.
I have uploaded my Bot Project on gitlab https://gitlab.com/pdmnbhrawal/myechobot01.
This is a simple typo. You've written "context-type" instead of "content-type." The YouTube tutorial you linked to tells you to write a line like this:
if "application/json" in request.headers["content-type"]:
In order to avoid this kind of typo, you can download the source code that the video links to directly instead of trying to rewrite it yourself.
You can troubleshoot this kind of error yourself by noticing in the stack trace that it tells you what line of code is throwing the error. When it says KeyError: 'HTTP_CONTEXT_TYPE' that should indicate to you that you've entered the wrong key and you should check for a typo. You can also try using a debugger and stepping through your code.
There are a few other problems with the bot that you may notice. It doesn't handle conversation update activities correctly because it doesn't account for the incoming activity having no text. It also doesn't return an HTTP response from the api/messages endpoint. You might want to fix those problems later, but your bot will run despite them.

SlackClient Python RTM not capturing messages

I want to write a simple slack bot, which responds a given string to # mentions, however I am not able to make the official documentation code to work.
I gave all OAuth permission to the bot and have the following code:
from slack import RTMClient
#RTMClient.run_on(event="message")
def gravity_bot(**payload):
data = payload['data']
print(data.get('text'))
try:
rtm_client = RTMClient(
token="my_token_auth_code",
connect_method='rtm.start'
)
print("Bot is up and running!")
rtm_client.start()
except Exception as err:
print(err)
I think the connection is established, as the "Bot is up and running" message appears, however on the slack channel to bot seems to be offline, also I am not able to get any response in the terminal, not for direct messages, not for channel messages even after inviting the bot to given channels.
Sorry couldn't let this one go.. I figured it out and here are the steps:
Create a "Classic" app in Slack (this is the only way to get the appropriate scopes), just click this link: https://api.slack.com/apps?new_classic_app=1
From the "Add features and functionality" tab click on "bots":
Click the "Add Legacy Bot User" button (this will add the "rtm.stream" scope that you need, but that you cannot add manually)
From the basic information page, install your app in a workspace
From the OAuth & Permissions page, copy the "Bot User OAuth Access Token" (the bottom one)
Run the following code (slightly modified version of the code in the docs)
from slack_sdk.rtm import RTMClient
# This event runs when the connection is established and shows some connection info
#RTMClient.run_on(event="open")
def show_start(**payload):
print(payload)
#RTMClient.run_on(event="message")
def say_hello(**payload):
print(payload)
data = payload['data']
web_client = payload['web_client']
if 'Hello' in data['text']:
channel_id = data['channel']
thread_ts = data['ts']
user = data['user']
web_client.chat_postMessage(
channel=channel_id,
text=f"Hi <#{user}>!",
thread_ts=thread_ts
)
if __name__ == "__main__":
slack_token = "<YOUR TOKEN HERE>"
rtm_client = RTMClient(token=slack_token)
rtm_client.start()
Previous answer:
Hmm, this is tricky one... According to the docs this only works for "classic" Slack apps, so that might be the first pointer. It explicitly says that you should not upgrade your app. Furthermore, you'll need to set the right permissions (god knows which ones) by selecting the "bot" scope.
Honestly, I haven't been able to get this running. Looks like Slack is getting rid of this connection method, so you might have more luck looking into the "Events API". I know it's not the ideal solution because its not as real-time, but it looks better documented and it will stay around for a while. Another approach could be polling. Its not sexy but it works...
My guess is that your problem is that there is not a valid connection, but there is no proper error handling in the Slack library. The message is printed before you actually connect, so that doesn't indicate anything.

How to convert tdata to telethon session?

I need to convert telegram data to telethon session.
How can i do this?
I tried to find a solution, spent three days, but I didn’t find anything
It's been nearly two years, but there's now a Python library called opentele created to do this.
Assuming you already have Python knowledge, please follow the steps below.
First you need to install opentele from PyPi:
pip install opentele
Preparing:
You need to have a tdata folder that is already authorized (have at least one logged-in account).
The default path to tdata folder on Windows is located at %appdata%\Telegram Desktop\tdata.
Create a python (.py) file and import these things:
from opentele.td import TDesktop
from opentele.tl import TelegramClient
from opentele.api import API, UseCurrentSession, CreateNewSession
import asyncio
And you also need to put the main code inside an async function:
async def main():
# PUT EXAMPLE CODE HERE
asyncio.run(main())
Initialize TDesktop from tdata folder
Load the tdata folder into a TDesktop object:
# Load TDesktop client from tdata folder
tdataFolder = r"C:\Users\<username>\AppData\Roaming\Telegram Desktop\tdata"
tdesk = TDesktop(tdataFolder)
# Check if we have loaded any accounts
assert tdesk.isLoaded()
Converting TDesktop to TelegramClient
There are two ways you can do this, either by using the current session or creating (login to) a new session.
Use the current session:
# flag=UseCurrentSession
#
# Convert TDesktop to Telethon using the current session.
client = await tdesk.ToTelethon(session="telethon.session", flag=UseCurrentSession)
Create a new session:
# flag=CreateNewSession
#
# Convert TDesktop to Telethon by creating a new session.
# CreateNewSession will use the current session (in tdata folder) to authorize a new session using QR Login.
# If 2FA is enabled for this account, you must specify the password via the password argument.
# This is of course slower than UseCurrentSession.
client = await tdesk.ToTelethon(session="telethon.session", flag=CreateNewSession)
Connect and print all logged-in sessions.
# Connect and print all logged-in sessions of this client.
# Telethon will save the session to telethon.session on creation.
await client.connect()
await client.PrintSessions()
Final result example
from opentele.td import TDesktop
from opentele.tl import TelegramClient
from opentele.api import API, UseCurrentSession
import asyncio
async def main():
# Load TDesktop client from tdata folder
tdataFolder = r"C:\Users\<username>\AppData\Roaming\Telegram Desktop\tdata"
tdesk = TDesktop(tdataFolder)
# Check if we have loaded any accounts
assert tdesk.isLoaded()
# flag=UseCurrentSession
#
# Convert TDesktop to Telethon using the current session.
client = await tdesk.ToTelethon(session="telethon.session", flag=UseCurrentSession)
# Connect and print all logged-in sessions of this client.
# Telethon will save the session to telethon.session on creation.
await client.connect()
await client.PrintSessions()
asyncio.run(main())
The result
The session will be saved to telethon.session file.
You can use this telethon.session with telethon, or use it directly with opentele - which is recommended because you don't need your own API_ID and API_HASH, the library by default will use Official Telegram API.
Remark
opentele is a very well documented library, you can find its documentation here.
It can also convert telethon sessions back to tdata and it's usable with Telegram Desktop.
Warning
According to its docs, you must continue using the associated API which you've had used to create that session whenever connecting to the server, or else you're at risk of losing that account.

Browser cancels HLS Stream while VLC accepts it

I recorded a HSL stream by writing the MPEG-TS streams contents into GridFS filesystem.
i'm now trying to serve this content back to the browser using aiohttps SessionResponse which fails for different reasons.
async def get_video(request):
stream_response = StreamResponse()
stream_response.headers['Content-Type'] = 'video/mp2t'
stream_response.headers['Cache-Control'] = 'no-cache'
stream_response.headers['Connection'] = 'keep-alive'
await stream_response.prepare(request)
fd = GridFS()
video_stream = await fd(video_id)
while True:
try:
chunk = await video_stream.readchunk()
if not chunk:
break
stream_response.write(chunk)
except CancelledError as e:
# fails here in safari or with diff content-type also in chrome
break
await stream_response.write_eof()
return stream_response
When trying to access the url using safari i get the player ui presented but nothing plays while the server throws a CancelledError exception trying to write on the already closed SessionResponse
Opening the URL in Chrome results in downloading the video file. This file works when playing it back in VLC. Even playing the URL inside VLC using "Network Source" works.
I also tried serving a static m3u playlist in front of this direct url like this but without luck (VLC also works using the playlist instread of direct stream):
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="medium",NAME="Medium",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=992000,RESOLUTION=852x480,CODECS="avc1.66.31,mp4a.40.2",VIDEO="medium"
http://localhost:8080/videos/{video_id}
I'm not sure how do debug this any further and would appreciate any help (or ask in comments if i'm unclear). What am i missing that the files don't get played back in browser when accessing them directly? Also embedding my resource url into a html video tag didn't help (obviously, since browser do the same when accessing a video directly)
Some more informations about the video content and the raw http resonses i'm sending:
Video Informations VLC
Direct Video Stream HTTP Response (start)
M3U Playlist HTTP Response
I have no experience with HLS personally but even vast overview of RFC draft displays that you breaks the protocol.
It's not about sending video chunks all together in single endless response but about sending multiple http responses utilizing the same socket connection by keep-alive usage.
Client sends request for new data portions providing protocol-specific EXT* flags and server should respond properly. At very beginning client asks for playlist, server should answer with proper data.
Communication protocol is complex enough, sorry.
I cannot just fix a couple lines in your snippet to make it work.

Categories