Closed zmoog closed 1 year ago
A complete Telegram Bot API reference is available at https://core.telegram.org/bots/api
For the sendMessage
method there are several formatting options:
The Bot API supports basic formatting for messages. You can use bold, italic, underlined, strikethrough, and spoiler text, as well as inline links and pre-formatted code in your bots' messages. Telegram clients will render them accordingly. You can specify text entities directly, or use markdown-style or HTML-style formatting.
The sendMessage
method has a parse_mode
that currently supports two options:
MarkdownV2
HTML
The markdown mode is pretty strict and throws 400s very easily. The HTML one instead seems pretty tolerant.
Is the markdown code block format supported? Let's give it a try!
$ cat msg.md
> This are the last week stats:
>
> ```
> Time Entries
>
> tags Duration
> ─────────────────────────
> type:goal 19:53
> type:meeting 9:00
> type:sync 7:44
> type:support 6:12
> ─────────────────────────
> Total 42:50
>
> ```
>
Sending the file content using the --parse-mode MarkdownV2
option:
$ tgm message send --chat-id 161035319 --parse-mode MarkdownV2 --text $msg
message-id: 698
And this is the final result in the Telegram web client:
Pretty basic but readable.
Unfortunately, with longer messages the result is not great:
I need custom formatting of text to fit the Telegram constraints.
Thinking about getting JSON documents and format them as needed using something link this https://pypi.org/project/jinja-cli/
$ cat example.j2
{% for entry in entries %}
- {{ entry.description }}{% endfor %}
$ tgl --format json entries --project-id 178435728 list | jq > example.json
$ cat example.json
cat example.json
{
"entries": [
{
"id": 2843982475,
"workspace_id": 1815018,
"user_id": 2621333,
"project_id": 178435728,
"task_id": null,
"billable": false,
"at": "2023-02-13T22:58:17+00:00",
"description": "Azure SDK upgrade: review",
"start": "2023-02-13T22:53:16+00:00",
"stop": "2023-02-13T22:58:17+00:00",
"duration": 301,
"tags": [
"type:support"
]
},
....
$ jinja -d example.json -f json example.j2
- Azure SDK upgrade: review
- ESF: research how to enable telemetry
- azure2: follow up to the questions
- azure2: follow up to the questions
- azure2: Add an entry to the Weekly Update
- Maurizio / Davide
- azure2: Add an entry to the Weekly Update
- Azure SDK upgrade: review
- azure2: Add an entry to the Weekly Update
- Azure SDK upgrade: review
- sync
- ESF: add sending tests
- azure2: send email
- sync
- Tamara / Maurizio (Cloud Monitoring Tours S1E4)
- sync
I used a dict
with an entries
key instead of a list
to make it easier for jinja-cli.
jinja-cli assumes data is a dict
.
If I want to use this tool I have to give it a dict
.
Another example with a patched version of toggl-track CLI that adds a --json-root
option to wrap the result list in a dict:
$ tgl --format json --json-root entries entries --project-id 178435728 list | jinja -d - -f json example.j2
- Observability Demo Day
- sync
- Cloud Monitoring - Weekly
- ESF: prepare presentation
- ESF: collecting sample logs
- ESF: collecting sample logs
- sync
- ESF: prepare presentation
- ESF: collecting sample logs
- ESF: collecting sample logs
Next steps:
--json-root
option and release a new versionWith this changes, I would be able to write something similar:
$ tgl --format json \
--json-root entries entries \
--project-id 178435728 list | \
jinja -d - -f json example.j2 | \
tgm message send --chat-id 123 --parse-mode MarkdownV2
Doing some research on stdin at zmoog/public-notes#3
I am starting to thing that we should add a new --text-file
option to read text content from a file, and use the stdin stream as a special case, something like what is described at https://stackoverflow.com/questions/59829848/supply-either-stdin-or-a-file-pathname-option-to-python-click-cli-script
import click
import sys
@click.group()
def cli():
pass
@cli.command()
@click.option('--compose-file',
help='compose file to work with',
type=click.File('r'),
default=sys.stdin)
def secret_hash_ini(compose_file):
with compose_file:
data = compose_file.read()
print(data)
if __name__ == '__main__':
cli()
I like this approach, it's quite flexible.
Here's one take on this that allows three different input sources:
--text
--text-file
text_file.read()
will wait until the user has typed the message and hit CTRL + D
@message.command(name="send")
@click.option(
"--text",
help="Text to send. If not provided, text will be read from a file or stdin.",
default=None,
)
@click.option(
"--text-file",
help="Text file to read from. If not provided, stdin will be used.",
type=click.File("r"),
default=click.get_text_stream("stdin"),
)
@click.option(
"--chat-id",
required=True,
)
@click.option(
'--parse-mode',
type=click.Choice(
['HTML', 'MarkdownV2'],
case_sensitive=False
),
default=None,
)
@click.pass_context
def send(ctx: click.Context, text: str, text_file: typing.TextIO, chat_id: str, parse_mode: str):
"""Send a text message to a chat."""
client = telegram.Client.from_envorinment(verbose=ctx.obj["verbose"])
if text:
message_text = text
elif text_file and text_file.readable():
message_text = text_file.read()
else:
raise Exception("No text or text file provided")
resp = client.send(message_text, chat_id, parse_mode=parse_mode)
message_id = resp.get("result", {}).get("message_id", "No message id found")
click.echo(f"message-id: {message_id}")
Here's and example:
Posting text-base information to Telegram does not work great. I want to learn what message formats are currently supported by Telegram and its APIs.