2025年4月13日 星期日

Python 學習筆記 : 用 Telegram Bot 取代 LINE Notify (八)

本篇旨在將前一篇用 HTTP API 傳送 mp3 音訊的程式碼改成用 Bot 物件來實作. 

本系列之前的文章參考 :


我將 Telegram Bot API 權杖 (token) 與聊天室識別碼 (chat_id) 都存放在環境變數檔 .env 裡面, 利用 dotenv 套件載入後再用 os 模組讀取出來放在 token 與 chat_id 變數裡 : 

>>> from dotenv import load_dotenv   
>>> load_dotenv()    
True 
>>> import os    
>>> token=os.environ.get('TELEGRAM_TOKEN')   
>>> chat_id=os.environ.get('TELEGRAM_ID')   

# load_secrets_py
from dotenv import load_dotenv  
import os  

load_dotenv()    
token=os.environ.get('TELEGRAM_TOKEN')   
chat_id=os.environ.get('TELEGRAM_ID') 

參考 :


Telegram 支援傳送 mp3/m4a 音訊格式, 可在 App 上直接播放. 


11. 利用 Bot 物件傳送音訊 :     

新版 (v20+) 的 python-telegram-bot 套件使用非同步架構, 函式只要有呼叫 Bot 物件之方法都要用 async 修飾, 且要用 await 去呼叫 Bot 物件方法. 關於 Bot 物件用法參考本系列第二篇測試 :



(1). 傳送網路音訊 :   

使用 Bot 物件傳送單一網路影片的程式碼如下 :

# telegram_send_web_audio_bot.py
import asyncio
from telegram import Bot

async def telegram_web_audio(token, chat_id, audio_url, caption=None, parse_mode='Markdown'):
    bot=Bot(token=token)
    try:
        await bot.send_audio(
            chat_id=chat_id,
            audio=audio_url,
            caption=caption,
            parse_mode=parse_mode
            )
        print("Audio message sent successfully.")
        return True
    except Exception as e:
        print(f'Telegram API Error: {e}')
        return False

if __name__ == '__main__':
    token='YOUR TOKEN'
    chat_id='YOUR CHAT ID'
    audio_url='https://yaohuang1966.github.io/media/glorious_days_clip.mp3'
    caption='🎵 一起聽聽這首歌吧'
    asyncio.run(telegram_web_audio(token, chat_id, audio_url, caption))

測試結果如下 :

>>> audio_url='https://yaohuang1966.github.io/media/glorious_days_clip.mp3'   
>>> caption='🎵 一起聽聽這首歌吧'     
>>> asyncio.run(telegram_web_audio(token, chat_id, audio_url, caption))     
Message(audio=Audio(duration=11, file_id='CQACAgQAAxkDAAPGZ_tZsQl1KAm0JUvrQVV8HbuAvBEAAkcIAAJJWt1TD1EgCp7QdWk2BA', file_name='glorious_days_clip.mp3', file_size=176877, file_unique_id='AgADRwgAAkla3VM', mime_type='audio/mpeg'), caption='🎵 一起聽聽這首歌吧', channel_chat_created=False, chat=Chat(first_name='<我的名字>', id=<聊天室ID>, type=<ChatType.PRIVATE>, username='<我的 username>'), date=datetime.datetime(2025, 4, 13, 9, 15, 11, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='twstock', id=7938146214, is_bot=True, username='twstock168_bot'), group_chat_created=False, message_id=211, supergroup_chat_created=False)
Audio message sent successfully.
True

查看 App 有收到這首歌 :




使用 Bot 物件傳送多個音訊時須使用 InputMediaAudio 類別來打包這些音訊, 程式碼如下 :

# telegram_send_web_audios_bot.py
import asyncio
from telegram import Bot, InputMediaAudio

async def telegram_web_audios(token, chat_id, media_list, caption_list, parse_mode='Markdown'):
    bot=Bot(token=token)
    media_group=[]
    for url, caption in zip(media_list, caption_list):
        media_group.append(InputMediaAudio(
            media=url,
            caption=caption,
            parse_mode=parse_mode
            )
        )
    try:
        await bot.send_media_group(chat_id=chat_id, media=media_group)
        print('Audio group sent successfully.')
        return True
    except Exception as e:
        print(f'Telegram API Error: {e}')
        return False

if __name__ == '__main__':
    token='YOUR TOKEN'
    chat_id='YOUR CHAT ID'
    audio_urls=[
        'https://yaohuang1966.github.io/media/glorious_days_clip.mp3',
        'https://yaohuang1966.github.io/media/your_answer_clip.mp3'
        ]
    captions=['光輝歲月', '你的答案']
    asyncio.run(telegram_web_audios(token, chat_id, audio_urls, captions))

測試結果如下 :

>>> audio_urls=[
    'https://yaohuang1966.github.io/media/glorious_days_clip.mp3',
    'https://yaohuang1966.github.io/media/your_answer_clip.mp3'
    ]   
>>> captions=['光輝歲月', '你的答案']    
>>> asyncio.run(telegram_web_audios(token, chat_id, audio_urls, captions))   
(Message(audio=Audio(duration=11, file_id='CQACAgQAAxkDAAPGZ_tZsQl1KAm0JUvrQVV8HbuAvBEAAkcIAAJJWt1TD1EgCp7QdWk2BA', file_name='glorious_days_clip.mp3', file_size=176877, file_unique_id='AgADRwgAAkla3VM', mime_type='audio/mpeg'), caption='光輝歲月', channel_chat_created=False, chat=Chat(first_name='<我的名字>', id=<聊天室ID>, type=<ChatType.PRIVATE>, username='<我的 username>'), date=datetime.datetime(2025, 4, 13, 13, 1, 1, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='twstock', id=7938146214, is_bot=True, username='twstock168_bot'), group_chat_created=False, media_group_id='13956394088384405', message_id=220, supergroup_chat_created=False), Message(audio=Audio(duration=22, file_id='CQACAgQAAxkDAAPHZ_tbuy8Iwqm0xeFtD-r7m4crAVoAApoHAAK7nN1T6wcAAe_BDvXyNgQ', file_name='your_answer_clip.mp3', file_size=665844, file_unique_id='AgADmgcAAruc3VM', mime_type='audio/mpeg', performer='黃霄雲', title='你的答案'), caption='你的答案', channel_chat_created=False, chat=Chat(first_name='<我的名字>', id=<聊天室ID>, type=<ChatType.PRIVATE>, username='yhhuang1966'), date=datetime.datetime(2025, 4, 13, 13, 1, 1, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='twstock', id=7938146214, is_bot=True, username='twstock168_bot'), group_chat_created=False, media_group_id='13956394088384405', message_id=221, supergroup_chat_created=False))

查看 App 有收到這兩首歌 :




(2). 傳送本機音訊 :   

傳送本機音訊也是呼叫 Bot 物件的 send_audio() 方法, 但要先用 open() 開啟 mp3 檔, 將檔案參考傳給 audio 參數即可 : 

# telegram_send_local_audio_bot.py
import asyncio
from telegram import Bot

async def telegram_local_audio(token, chat_id, audio_path, caption=None, parse_mode='Markdown'):
    bot=Bot(token=token)
    try:
        with open(audio_path, 'rb') as audio_file:
            await bot.send_audio(
                chat_id=chat_id,
                audio=audio_file,
                caption=caption,
                parse_mode=parse_mode
                )
        print("Audio message sent successfully.")
        return True
    except Exception as e:
        print(f'Telegram API Error: {e}')
        return False

if __name__ == '__main__':
    token='YOUR TOKEN'
    chat_id='YOUR CHAT ID'
    audio_path='your_answer_clip.mp3'
    caption='🎵 一起來聽你的答案'
    asyncio.run(telegram_local_audio(token, chat_id, audio_path, caption

測試結果如下 : 

>>> audio_path='your_answer_clip.mp3'   
>>> caption='🎵 一起來聽你的答案'   
>>> asyncio.run(telegram_local_audio(token, chat_id, audio_path, caption))    
Message(audio=Audio(duration=22, file_id='CQACAgUAAxkDAAPeZ_u7puXuDAXCL8unhK5IRvr4KMUAArwYAAIU-uBXLrY47umaGaU2BA', file_name='your_answer_clip.mp3', file_size=665844, file_unique_id='AgADvBgAAhT64Fc', mime_type='audio/mpeg', performer='黃霄雲', title='你的答案'), caption='🎵 一起來聽你的答案', channel_chat_created=False, chat=Chat(first_name='<我的名字>', id=<聊天室ID>, type=<ChatType.PRIVATE>, username='<我的 username>'), date=datetime.datetime(2025, 4, 13, 13, 27, 2, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='twstock', id=7938146214, is_bot=True, username='twstock168_bot'), group_chat_created=False, message_id=222, supergroup_chat_created=False)
Audio message sent successfully.
True

查看 App 有收到這首歌 :




傳送本機多個音訊, 與上面傳送多個網路音訊一樣要用 InputMediaVideo 類別來將各音訊檔打包, 差別只是要先開啟音訊檔, 再將檔案參考打包成 InputMediaAudio 物件串列, 然後於 呼叫 Bot 物件的 send_media_group() 方法時把它傳給 media 參數即可. 完整程式碼如下 : 

# telegram_send_local_audios_bot.py
import asyncio
from telegram import Bot, InputMediaAudio

async def telegram_local_audios(token, chat_id, audio_paths, captions, parse_mode='Markdown'):
    bot=Bot(token=token)
    media=[]  # 儲存用 InputMediaAudio 打包後的音訊
    files=[open(path, 'rb') for path in audio_paths] # 儲存所有開啟的音訊檔案
    try:        
        for i, f in enumerate(files):  # 建立 InputMediaAudio 物件串列
            caption=captions[i] if i < len(captions) else None
            media.append(InputMediaAudio(media=f, caption=caption, parse_mode=parse_mode))
        await bot.send_media_group(chat_id=chat_id, media=media)
        print('Audio group message sent successfully.')
        return True
    except Exception as e:
        print(f'Telegram API Error: {e}')
        return False
    finally:
        for f in files:
            f.close()

if __name__ == '__main__':
    token='YOUR TOKEN'
    chat_id='YOUR CHAT ID'
    audio_paths=['glorious_days_clip.mp3', 'your_answer_clip.mp3']
    captions=['🎵 光輝歲月', '🎶 你的答案']
    asyncio.run(telegram_local_audios(token, chat_id, audio_paths, captions))

測試結果如下 : 

>>> audio_paths=['glorious_days_clip.mp3', 'your_answer_clip.mp3']  
>>> captions=['🎵 光輝歲月', '🎶 你的答案']   
>>> asyncio.run(telegram_local_audios(token, chat_id, audio_paths, captions))     
(Message(audio=Audio(duration=11, file_id='CQACAgUAAxUHZ_vd96HtCw6rZqYGWC8G55JmDtsAAhUZAAIU-uBXfuyPNXaOhAABNgQ', file_name='glorious_days_clip.mp3', file_size=179078, file_unique_id='AgADFRkAAhT64Fc', mime_type='audio/mpeg', performer='Beyond', title='光輝歲月'), caption='🎵 光輝歲月', channel_chat_created=False, chat=Chat(first_name='<我的名字>', id=<聊天室ID>, type=<ChatType.PRIVATE>, username='<我的 username>'), date=datetime.datetime(2025, 4, 13, 15, 53, 27, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='twstock', id=7938146214, is_bot=True, username='twstock168_bot'), group_chat_created=False, media_group_id='13956476862917125', message_id=225, supergroup_chat_created=False), Message(audio=Audio(duration=22, file_id='CQACAgUAAxUHZ_vd91l_mZCQvrteW59nE_FxdxsAAhYZAAIU-uBXMPTgePwhh3c2BA', file_name='your_answer_clip.mp3', file_size=665844, file_unique_id='AgADFhkAAhT64Fc', mime_type='audio/mpeg', performer='黃霄雲', title='你的答案'), caption='🎶 你的答案', channel_chat_created=False, chat=Chat(first_name='<我的名字>', id=<聊天室ID>, type=<ChatType.PRIVATE>, username='<我的 username>'), date=datetime.datetime(2025, 4, 13, 15, 53, 27, tzinfo=datetime.timezone.utc), delete_chat_photo=False, from_user=User(first_name='twstock', id=7938146214, is_bot=True, username='twstock168_bot'), group_chat_created=False, media_group_id='13956476862917125', message_id=226, supergroup_chat_created=False))
Audio group message sent successfully.
True

查看 App 有收到這兩首歌 :




因為我已經用 MP3Tag 軟體更改光輝歲月的 ID3 Tag, 所以這次會顯示曲名與歌手了. 

沒有留言 :