Add config file

Add mailcap support to open files
Fix setting invalid current_msg when new comes
This commit is contained in:
Paul Nameless 2020-05-06 21:20:45 +08:00
parent c7d535fdd7
commit b20fc378de
5 changed files with 102 additions and 45 deletions

32
tg/config.py Normal file
View file

@ -0,0 +1,32 @@
import os
import configparser
import mailcap
import mimetypes
DEFAULT_CONFIG = os.path.expanduser("~/.config/tg/tg.conf")
DEFAULT_FILES = os.path.expanduser("~/.cache/tg/")
def get_cfg(config=DEFAULT_CONFIG):
cfg = configparser.ConfigParser()
cfg.read(config)
return cfg
def save_cfg(cfg, config=DEFAULT_CONFIG):
config_dir = os.path.dirname(config)
if not os.path.isdir(config_dir):
os.makedirs(config_dir)
with open(config, "w") as f:
cfg.write(f)
def get_file_handler(file_name, default=None):
mtype, _ = mimetypes.guess_type(file_name)
if not mtype:
return default
caps = mailcap.getcaps()
handler, view = mailcap.findmatch(caps, mtype, filename=file_name)
if not handler:
return None
return handler

View file

@ -54,20 +54,18 @@ class Controller:
log.info("Open msg: %s", msg.msg)
if msg.is_text:
text = msg["content"]["text"]["text"]
with NamedTemporaryFile("w") as f:
with NamedTemporaryFile("w", suffix=".txt") as f:
f.write(text)
f.flush()
with suspend(self.view) as s:
s.call(["less", f.name])
s.run(f.name)
return
path = msg.local_path
if path:
# handle with mimetype and mailcap
# if multiple entries in mailcap, open fzf to choose
with suspend(self.view) as s:
log.info("Opening file: %s", path)
s.call(["open", path])
s.run(path)
def handle_msgs(self) -> str:
# set width to 0.25, move window to left
@ -200,12 +198,24 @@ class Controller:
@handle_exception
def update_new_msg(self, update):
chat_id = update["message"]["chat_id"]
self.model.msgs.add_message(chat_id, update["message"])
msg = update["message"]
chat_id = msg["chat_id"]
self.model.msgs.add_message(chat_id, msg)
self.refresh_msgs()
if not update.get("disable_notification"):
if update["message"]["content"] == "text":
notify(update["message"]["content"]["text"]["text"])
# notify
user_id = msg["sender_user_id"]
if msg["sender_user_id"] == self.model.get_me()["id"]:
return
user = self.model.users.get_user(user_id)
name = "{} {}".format(user["first_name"], user["last_name"])
_type = msg["content"]["@type"]
if _type == "messageText":
text = msg["content"]["text"]["text"]
else:
text = MsgProxy.types.get(_type, "")
notify(text, title=name)
@handle_exception
def update_chat_last_msg(self, update):
@ -218,7 +228,7 @@ class Controller:
# though need to make sure that creatinng index is atomic operation
# requires locks for read, until index and chats will be the same
for i, chat in enumerate(self.model.chats.chats):
if chat['id'] == current_chat_id:
if chat["id"] == current_chat_id:
self.model.current_chat = i
break
self.refresh_chats()

View file

@ -1,6 +1,5 @@
import logging
import logging.handlers
import os
import threading
from curses import wrapper, window
from functools import partial
@ -10,23 +9,10 @@ from telegram.client import Telegram
from tg.controllers import Controller
from tg.models import Model
from tg.views import View
from tg import config, utils
logging.basicConfig(
level=os.getenv("LOG_LEVEL", "DEBUG"),
format="%(asctime)s %(levelname)s %(message)s",
handlers=[
logging.handlers.RotatingFileHandler(
"./tg.log", backupCount=1, maxBytes=1024 * 256
),
],
)
log = logging.getLogger(__name__)
API_ID = os.getenv("API_ID")
API_HASH = os.getenv("API_HASH")
PHONE = os.getenv("PHONE")
if PHONE is None:
raise Exception("Environment variables did not provided")
def run(tg: Telegram, stdscr: window) -> None:
@ -61,16 +47,17 @@ class TelegramApi(Telegram):
def main():
cfg = config.get_cfg()["DEFAULT"]
utils.setup_log(cfg.get("level", "DEBUG"))
log.debug("#" * 64)
tg = TelegramApi(
api_id=API_ID,
api_hash=API_HASH,
phone=PHONE,
database_encryption_key="changeme1234",
files_directory=os.path.expanduser("~/.cache/tg/"),
tdlib_verbosity=0,
# TODO: add in config
library_path="/usr/local/Cellar/tdlib/1.6.0/lib/libtdjson.dylib",
api_id=cfg["api_id"],
api_hash=cfg["api_hash"],
phone=cfg["login"],
database_encryption_key=cfg["enc_key"],
files_directory=cfg.get("files", config.DEFAULT_FILES),
tdlib_verbosity=cfg.get("tdlib_verbosity", 0),
library_path=cfg.get("library_path"),
)
tg.login()
wrapper(partial(run, tg))

View file

@ -38,6 +38,7 @@ class Model:
if chat_id is None:
return {}
current_msg = self.msgs.current_msgs[chat_id]
log.info("current-msg: %s", current_msg)
return self.msgs.msgs[chat_id][current_msg]
def jump_bottom(self):
@ -228,6 +229,11 @@ class MsgModel:
log.info(f"adding {msg_id=} {message}")
self.msgs[chat_id].append(message)
msg_set.add(msg_id)
self.msgs[chat_id] = sorted(
self.msgs[chat_id], key=lambda d: d["id"], reverse=True
)
return True
def add_messages(self, chat_id: int, messages: Any) -> bool:
@ -276,7 +282,7 @@ class MsgModel:
messages = self._fetch_msgs_until_limit(chat_id, offset, limit)
self.add_messages(chat_id, messages)
return sorted(self.msgs[chat_id], key=lambda d: d["id"])[::-1][
return sorted(self.msgs[chat_id], key=lambda d: d["id"], reverse=True)[
offset:limit
]

View file

@ -4,6 +4,7 @@ from typing import Optional
import subprocess
from functools import wraps
import curses
from tg import config
log = logging.getLogger(__name__)
@ -15,17 +16,32 @@ def num(value: str, default: Optional[int] = None) -> Optional[int]:
return default
def notify(msg, subtitle="New message", title="Telegram"):
msg = "-message {!r}".format(msg)
subtitle = "-subtitle {!r}".format(subtitle)
title = "-title {!r}".format(title)
sound = "-sound default"
icon_path = os.path.join(os.path.dirname(__file__), "tg.png")
icon = f"-appIcon {icon_path}"
cmd = "/usr/local/bin/terminal-notifier"
def setup_log(level="DEBUG"):
logging.basicConfig(
level=level,
format="%(asctime)s %(levelname)s %(message)s",
handlers=[
logging.handlers.RotatingFileHandler(
"./tg.log", backupCount=1, maxBytes=1024 * 1024
),
],
)
log.debug("####: %s", f"{cmd} {icon} {sound} {title} {subtitle} {msg}")
os.system(f"{cmd} {icon} {sound} {title} {subtitle} {msg}")
def notify(
msg,
subtitle="",
title="tg",
cmd=config.get_cfg()["DEFAULT"].get("notify_cmd"),
):
if not cmd:
return
icon_path = os.path.join(os.path.dirname(__file__), "tg.png")
notify_cmd = cmd.format(
icon_path=icon_path, title=title, subtitle=subtitle, msg=msg
)
log.info("notify-cmd: %s", notify_cmd)
os.system(notify_cmd)
def handle_exception(fun):
@ -46,6 +62,12 @@ class suspend:
def call(self, *args, **kwargs):
subprocess.call(*args, **kwargs)
def run(self, file_path):
cmd = config.get_file_handler(file_path)
if not cmd:
return
subprocess.call(cmd, shell=True)
def __enter__(self):
curses.endwin()
return self