寫了一個Telegram Bot:自動化分享高質量內容
平時我們讀到優秀的資源例如文章,視訊或者電子書等等,總是會忍不住收藏起來,但是如果我們能分享出來給所有人看到,那會不會 更好呢?
所以我做了一個Telegram Bot,平時我只要把閱讀到的不錯的連結分享給我的bot,然後選擇性的新增一些我自己的評語(或者叫推薦 理由)。然後會有另外一個頁面來動態的渲染所有我分享的連結和評語。
歡迎直接訪問:ofollow,noindex" target="_blank">https://share.jiajunhuang.com
Bot程式碼
首先你要去Telegram上和BotFather聊天,其實就是輸入一些命令,來建立一個你自己的Bot,它會下發給你一個Token。然後參考https://core.telegram.org/bots/api 開始開發。當然,為了方便省事兒,我是直接用的一個Python封裝好的包來做的。Bot的核心程式碼 如下:
import gevent.monkey gevent.monkey.patch_all()# noqa import logging logging.basicConfig(level=logging.INFO)# noqa from telegram.ext import Updater, CommandHandler, MessageHandler, Filters from telegram import MessageEntity from models import get_session, URLShare from config import config AUTHORS_FILTER = Filters.user(username="@jiajunhuang") def report_error(func): def wrapper(bot, update, *args, **kwargs): try: return func(bot, update, *args, **kwargs) except Exception as e: logging.exception("failed to handle message from telegram") bot.send_message(chat_id=update.message.chat_id, text="出錯啦:" + str(e)) return wrapper def save_url(url): with get_session() as s: url_share = URLShare(url=url) s.add(url_share) s.flush() return url_share.id def save_comment(comment): with get_session() as s: share = s.query(URLShare).order_by(URLShare.id.desc()).first() if share: share.comment = comment s.add(share) return "mapped with url: " + share.url return "not found" def update_comment(share_id, comment): with get_session() as s: share = s.query(URLShare).filter(URLShare.id == share_id).first() if share: share.comment = comment s.add(share) return "mapped with url: " + share.url return "not found" @report_error def comment_handler(bot, update, args): if len(args) == 0: text = "Usage: /comment <your comments>" else: text = save_comment("".join(args)) bot.send_message(chat_id=update.message.chat_id, text=text) @report_error def update_comment_handler(bot, update, args): if len(args) == 0: text = "Usage: /update <id> <new comments>" else: text = update_comment(int(args[0]), "".join(args[1:])) bot.send_message(chat_id=update.message.chat_id, text=text) @report_error def url_share_handler(bot, update): bot.send_message(chat_id=update.message.chat_id, text="save with id: {}".format(save_url(update.message.text))) if __name__ == "__main__": updater = Updater(token=config.TGBOTTOKEN) dispatcher = updater.dispatcher dispatcher.add_handler( CommandHandler( 'comment', comment_handler, pass_args=True, filters=AUTHORS_FILTER, ) ) dispatcher.add_handler( CommandHandler( 'update', update_comment_handler, pass_args=True, filters=AUTHORS_FILTER, ), ) dispatcher.add_handler(MessageHandler( Filters.text & ( Filters.entity(MessageEntity.URL) | Filters.entity(MessageEntity.TEXT_LINK) ) & AUTHORS_FILTER, url_share_handler, )) updater.start_polling()
models定義如下:
import datetime import contextlib from sqlalchemy import create_engine, Column, DateTime, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from config import config engine = create_engine(config.SQLALCHEMY_DB_URI, echo=config.SQLALCHEMY_ECHO) Session = sessionmaker(bind=engine) Base = declarative_base() class BaseMixin: id = Column(Integer, primary_key=True, autoincrement=True) created_at = Column(DateTime, nullable=False, default=datetime.datetime.now) updated_at = Column(DateTime, nullable=False, default=datetime.datetime.now, onupdate=datetime.datetime.now) deleted_at = Column(DateTime, nullable=True, index=True) @contextlib.contextmanager def get_session(): s = Session() try: yield s s.commit() except Exception: s.rollback() raise finally: s.close() class URLShare(Base, BaseMixin): __tablename__ = "url_share" url = Column(String(1024), nullable=False) comment = Column(String(512))
~~當然上面的程式碼裡config.py
裡的內容我就不貼出來了,畢竟為了簡單方便,我直接吧token和資料庫URL寫到了程式碼裡,在實際
工作上,這是不好
的習慣,請不要學,謝謝。~~ 有網友提醒說其實把config.py
的涉密內容刪掉就可以了,也對:
class Config: def __init__(self): self.SQLALCHEMY_DB_URI = "sqlite:////tmp/tgbot.db"# 舉個例子,這樣。還是要修改成具體你的SQLite檔案的路徑 self.SQLALCHEMY_ECHO = False self.TGBOTTOKEN = "你從BotFather那裡申請來的token" config = Config()
在第一次使用之前,需要初始化資料庫schema,如果不想生成migration的話,就配置好config.py
之後儲存一個gen.py
:
from models import Base, engine Base.metadata.create_all(engine)
執行一下就可以了。
資料庫用的是SQLite。為啥不用MySQL或者PG?答:為啥要用大炮打蚊子?而且,SQLite沒有你想象中的那麼弱。
當然要支援RSS
雖然是一個簡單到不行的網頁,但是為了自動化方便,那也是要支援RSS的!
訪問https://share.jiajunhuang.com/rss 獲取feed。有了RSS,你可以選擇在IFTTT上增加有新的訂閱時就給你傳送一條訊息,這樣 當我有新的分享時,你就可以自動收到推送啦 :)