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) log.info("Open msg: %s", msg.msg)
if msg.is_text: if msg.is_text:
text = msg["content"]["text"]["text"] text = msg["content"]["text"]["text"]
with NamedTemporaryFile("w") as f: with NamedTemporaryFile("w", suffix=".txt") as f:
f.write(text) f.write(text)
f.flush() f.flush()
with suspend(self.view) as s: with suspend(self.view) as s:
s.call(["less", f.name]) s.run(f.name)
return return
path = msg.local_path path = msg.local_path
if path: if path:
# handle with mimetype and mailcap
# if multiple entries in mailcap, open fzf to choose
with suspend(self.view) as s: with suspend(self.view) as s:
log.info("Opening file: %s", path) log.info("Opening file: %s", path)
s.call(["open", path]) s.run(path)
def handle_msgs(self) -> str: def handle_msgs(self) -> str:
# set width to 0.25, move window to left # set width to 0.25, move window to left
@ -200,12 +198,24 @@ class Controller:
@handle_exception @handle_exception
def update_new_msg(self, update): def update_new_msg(self, update):
chat_id = update["message"]["chat_id"] msg = update["message"]
self.model.msgs.add_message(chat_id, update["message"]) chat_id = msg["chat_id"]
self.model.msgs.add_message(chat_id, msg)
self.refresh_msgs() self.refresh_msgs()
if not update.get("disable_notification"):
if update["message"]["content"] == "text": # notify
notify(update["message"]["content"]["text"]["text"]) 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 @handle_exception
def update_chat_last_msg(self, update): def update_chat_last_msg(self, update):
@ -218,7 +228,7 @@ class Controller:
# though need to make sure that creatinng index is atomic operation # though need to make sure that creatinng index is atomic operation
# requires locks for read, until index and chats will be the same # requires locks for read, until index and chats will be the same
for i, chat in enumerate(self.model.chats.chats): 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 self.model.current_chat = i
break break
self.refresh_chats() self.refresh_chats()

View file

@ -1,6 +1,5 @@
import logging import logging
import logging.handlers import logging.handlers
import os
import threading import threading
from curses import wrapper, window from curses import wrapper, window
from functools import partial from functools import partial
@ -10,23 +9,10 @@ from telegram.client import Telegram
from tg.controllers import Controller from tg.controllers import Controller
from tg.models import Model from tg.models import Model
from tg.views import View 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__) 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: def run(tg: Telegram, stdscr: window) -> None:
@ -61,16 +47,17 @@ class TelegramApi(Telegram):
def main(): def main():
cfg = config.get_cfg()["DEFAULT"]
utils.setup_log(cfg.get("level", "DEBUG"))
log.debug("#" * 64) log.debug("#" * 64)
tg = TelegramApi( tg = TelegramApi(
api_id=API_ID, api_id=cfg["api_id"],
api_hash=API_HASH, api_hash=cfg["api_hash"],
phone=PHONE, phone=cfg["login"],
database_encryption_key="changeme1234", database_encryption_key=cfg["enc_key"],
files_directory=os.path.expanduser("~/.cache/tg/"), files_directory=cfg.get("files", config.DEFAULT_FILES),
tdlib_verbosity=0, tdlib_verbosity=cfg.get("tdlib_verbosity", 0),
# TODO: add in config library_path=cfg.get("library_path"),
library_path="/usr/local/Cellar/tdlib/1.6.0/lib/libtdjson.dylib",
) )
tg.login() tg.login()
wrapper(partial(run, tg)) wrapper(partial(run, tg))

View file

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

View file

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