[CORE] improved code, formatting and fixed some bugs

- Added a better `.gitignore`
- Formatted the `do` script better, made it better in general
- Improved instalation and upgrading instructons
- Removed arrow key support
- Imrproved `README.md` formatting
- Improved the runtime (`__main__.py`) script, improved formatting,
  handling of arguments and added docstrings
- Renamed `colors` to `colours`
- Added type hints to the config file and improved how it handles some
  things
- Improved chat action strings (e.g `uploading video` -> `is uploading a video`)
- Made `COPY_CMD` deprecated, using `pyperclip` instead
- Changed dependency for stability from dynamic to exact
  (`python-telegram>=....` to `python-telegram==....`)

Signed-off-by: Ari Archer <truncateddinosour@gmail.com>
This commit is contained in:
Ari Archer 2022-01-01 03:21:24 +02:00
parent b22d3100dc
commit 9bfc08f357
Signed by untrusted user who does not match committer: ari
GPG key ID: A50D5B4B599AF8A2
15 changed files with 320 additions and 232 deletions

156
.gitignore vendored
View file

@ -1,14 +1,156 @@
.mypy_cache/
venv/
__pycache__
.env
dist
# Random
*.log*
Makefile
*monkeytype.sqlite3
# Editors
.idea/
.vim/
*monkeytype.sqlite3
.vscode/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
arigram.egg-info/
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/

View file

@ -36,6 +36,7 @@ A fork of [tg](https://github.com/paul-nameless/tg) -- a hackable telegram TUI c
- [ ] profile pictures
- [ ] message/chat archiving
- [ ] better error reporting
- [ ] joining of groups and channels based on t.me links and @s
## Requirements
@ -81,8 +82,7 @@ mkdir -p ~/.local/src
cd ~/.local/src
git clone https://github.com/TruncatedDinosour/arigram.git
cd arigram
pip install --upgrade --user -r requirements.txt
pip install --upgrade --user .
./do local
```
And add this to `~/.bashrc` or whatever POSIX complient shell you use:
@ -111,10 +111,16 @@ This option is recommended:
```sh
cd ~/.local/src/arigram
git reset --hard # This discards every change you made
git reset --hard # This discards every change you made locally
git pull
pip install --upgrade --user -r requirements.txt
pip install --upgrade --user .
./do upgrade
```
or if you want to keep local changes
```sh
cd ~/.local/src/arigram
./do local
```
## Configuration
@ -126,6 +132,7 @@ Config file should be stored at `~/.config/arigram/config.py`. This is simple py
```python
# should start with + (plus) and contain country code
PHONE = "[phone number in international format]"
# For enable `PHONE = "+1234567890"`
```
### Advanced configuration:
@ -301,9 +308,7 @@ text/*; vim "%s"
## Keybindings
vi like keybindings are used in the project. Can be used commands like `4j` - 4 lines down.
For navigation arrow keys also can be used.
ViM like keybindings are used in the project. Can be used commands like `4j` - 4 lines down.
### Chats:
@ -329,12 +334,14 @@ For navigation arrow keys also can be used.
- `G`: move to the last msg (at the bottom)
- `D`: download file
- `l`: if video, pics or audio then open app specified in mailcap file, for example:
```ini
# Images
image/png; qView "%s"
audio/*; mpv "%s"
```
if text, open in `less` (to view multiline msgs)
```ini
# Images
image/png; qView "%s"
audio/*; mpv "%s"
```
If text, open in `less` (to view multiline msgs)
- `e`: edit current msg
- `<space>`: select msg and jump one msg down (use for deletion or forwarding)
- `<ctrl+space>`: same as space but jumps one msg up

View file

@ -1,7 +0,0 @@
- [] local passwords:
```
- You need to save authorization keys on the disk.
- So you can take the local passcode, derive an encryption key from this passcode and use this key to encrypt the authorization keys before saving. So when you start the app you can't decrypt the keys (and start using the API) without providing a correct local passcode for that. You can also save some hash (like SHA256) of the original keys along so that you can check whether you've decrypted the correct keys or just garbage because of an incorrect passcode.
```

View file

@ -1,10 +1,12 @@
import logging.handlers
import signal
import sys
import threading
from curses import window, wrapper # type: ignore
from functools import partial
from types import FrameType
import arigram
from arigram import config, update_handlers, utils
from arigram.controllers import Controller
from arigram.models import Model
@ -22,7 +24,7 @@ def run(tg: Tdlib, stdscr: window) -> None:
del sig, frame
log.info("Interrupt signal is handled and ignored on purpose.")
signal.signal(signal.SIGINT, interrupt_signal_handler)
signal.signal(signal.SIGINT, interrupt_signal_handler) # type: ignore
model = Model(tg)
status_view = StatusView(stdscr)
@ -46,19 +48,24 @@ def run(tg: Tdlib, stdscr: window) -> None:
def parse_args() -> None:
import sys
"""Parse CLI arguments"""
if len(sys.argv) > 1 and sys.argv[1] in ("-v", "--version"):
import arigram
if len(sys.argv) < 2:
return
if sys.argv[1] in ("-v", "--version"):
print("Terminal Telegram client")
print("Version:", arigram.__version__)
exit(0)
sys.exit()
def main() -> None:
"""Main function"""
parse_args()
utils.cleanup_cache()
tg = Tdlib(
config.EXTRA_TDLIB_HEADEARS,
api_id=config.API_ID,

View file

@ -26,7 +26,7 @@ invisible = curses.A_INVIS
dim = curses.A_DIM
def get_color(fg: int, bg: int) -> int:
def get_colour(fg: int, bg: int) -> int:
"""Returns the curses color pair for the given fg/bg combination."""
key = (fg, bg)

View file

@ -6,87 +6,75 @@ import mailcap
import os
import platform
import runpy
from typing import Any, Dict, Optional
from typing import Any, Dict, List, Optional, Tuple
_os_name = platform.system()
_linux = "Linux"
_global_mailcap = mailcap.getcaps()
CONFIG_DIR = os.path.expanduser("~/.config/arigram/")
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.py")
FILES_DIR = os.path.expanduser("~/.cache/arigram/")
DRAFTS_FILE = os.path.join(FILES_DIR, "drafts.json")
CONFIG_DIR: str = os.path.expanduser("~/.config/arigram/")
CONFIG_FILE: str = os.path.join(CONFIG_DIR, "config.py")
FILES_DIR: str = os.path.expanduser("~/.cache/arigram/")
DRAFTS_FILE: str = os.path.join(FILES_DIR, "drafts.json")
MAILCAP_FILE: Optional[str] = None
LOG_LEVEL = "INFO"
LOG_PATH = os.path.expanduser("~/.local/share/arigram/")
LOG_LEVEL: str = "INFO"
LOG_PATH: str = os.path.expanduser("~/.local/share/arigram/")
API_ID = "559815"
API_HASH = "fd121358f59d764c57c55871aa0807ca"
API_ID: str = "559815"
API_HASH: str = "fd121358f59d764c57c55871aa0807ca"
PHONE = None
ENC_KEY = ""
PHONE: Optional[str] = None
ENC_KEY: str = ""
TDLIB_PATH = None
TDLIB_VERBOSITY = 0
TDLIB_PATH: Optional[str] = None
TDLIB_VERBOSITY: int = 0
MAX_DOWNLOAD_SIZE = "10MB"
MAX_DOWNLOAD_SIZE: str = "10MB"
NOTIFY_FUNCTION = None
NOTIFY_FUNCTION: Optional[Any] = None
VIEW_TEXT_CMD = "less"
FZF = "fzf"
VIEW_TEXT_CMD: str = "less"
if _os_name == _linux:
# for more info see https://trac.ffmpeg.org/wiki/Capture/ALSA
VOICE_RECORD_CMD = (
"ffmpeg -f alsa -i hw:0 -c:a libopus -b:a 32k {file_path}"
)
else:
VOICE_RECORD_CMD = (
"ffmpeg -f avfoundation -i ':0' -c:a libopus -b:a 32k {file_path}"
)
# for more info see https://trac.ffmpeg.org/wiki/Capture/ALSA
VOICE_RECORD_CMD: str = (
"ffmpeg -f alsa -i hw:0 -c:a libopus -b:a 32k {file_path}"
if _os_name == _linux
else "ffmpeg -f avfoundation -i ':0' -c:a libopus -b:a 32k {file_path}"
)
EDITOR = os.environ.get("EDITOR", "vim")
EDITOR: str = os.environ.get("EDITOR", "vim")
_, __MAILCAP_EDITOR = mailcap.findmatch(_global_mailcap, "text/markdown")
if __MAILCAP_EDITOR:
EDITOR = str(__MAILCAP_EDITOR["view"]).split(" ", 1)[0]
LONG_MSG_CMD = f"{EDITOR} '{{file_path}}'"
LONG_MSG_CMD: str = f"{EDITOR} '{{file_path}}'"
if _os_name == _linux:
DEFAULT_OPEN = "xdg-open {file_path}"
else:
DEFAULT_OPEN = "open {file_path}"
if _os_name == _linux:
if os.environ.get("WAYLAND_DISPLAY"):
COPY_CMD = "wl-copy"
else:
COPY_CMD = "xclip -selection cliboard"
else:
COPY_CMD = "pbcopy"
DEFAULT_OPEN: str = (
"xdg-open {file_path}" if _os_name == _linux else "open {file_path}"
)
CHAT_FLAGS: Dict[str, str] = {}
MSG_FLAGS: Dict[str, str] = {}
ICON_PATH = os.path.join(os.path.dirname(__file__), "resources", "arigram.png")
ICON_PATH: str = os.path.join(
os.path.dirname(__file__), "resources", "arigram.png"
)
URL_VIEW = None
URL_VIEW: Optional[str] = None
USERS_COLORS = tuple(range(2, 16))
USERS_COLOURS: Tuple[int, ...] = tuple(range(2, 16))
KEEP_MEDIA = 7
KEEP_MEDIA: int = 7
FILE_PICKER_CMD = None
FILE_PICKER_CMD: Optional[str] = None
DOWNLOAD_DIR = os.path.expanduser("~/Downloads/")
DOWNLOAD_DIR: str = os.path.expanduser("~/Downloads/")
EXTRA_FILE_CHOOSER_PATHS = ["..", "/", "~"]
EXTRA_FILE_CHOOSER_PATHS: List[str] = ["..", "/", "~"]
CUSTOM_KEYBINDS: Dict[str, Dict[str, Any]] = {}

View file

@ -196,7 +196,7 @@ class Controller:
def quit(self) -> str:
return "QUIT"
@bind(msg_handler, ["h", "^D"])
@bind(msg_handler, ["h"])
def back(self) -> str:
return "BACK"
@ -276,7 +276,7 @@ class Controller:
if self.model.jump_bottom():
self.render_msgs()
@bind(msg_handler, ["j", "^B", "^N"], repeat_factor=True)
@bind(msg_handler, ["j"], repeat_factor=True)
def next_msg(self, repeat_factor: int = 1) -> None:
if self.model.next_msg(repeat_factor):
self.render_msgs()
@ -285,7 +285,7 @@ class Controller:
def jump_10_msgs_down(self) -> None:
self.next_msg(10)
@bind(msg_handler, ["k", "^C", "^P"], repeat_factor=True)
@bind(msg_handler, ["k"], repeat_factor=True)
def prev_msg(self, repeat_factor: int = 1) -> Optional[bool]:
if self.model.prev_msg(repeat_factor):
self.render_msgs()
@ -327,7 +327,7 @@ class Controller:
f.write(insert_replied_msg(msg))
f.seek(0)
s.call(config.LONG_MSG_CMD.format(file_path=shlex.quote(f.name)))
with open(f.name) as f:
with open(f.name) as f: # type: ignore
if replied_msg := strip_replied_msg(f.read().strip()):
self.model.view_all_msgs()
self.tg.reply_message(chat_id, reply_to_msg, replied_msg)
@ -397,7 +397,7 @@ class Controller:
) as s:
self.tg.send_chat_action(chat_id, ChatAction.chatActionTyping)
s.call(config.LONG_MSG_CMD.format(file_path=shlex.quote(f.name)))
with open(f.name) as f:
with open(f.name) as f: # type: ignore
if msg := f.read().strip():
self.model.send_message(text=msg)
self.present_info("Message sent")
@ -442,7 +442,7 @@ class Controller:
else:
s.call(config.FILE_PICKER_CMD.format(file_path=f.name)) # type: ignore
with open(f.name) as f:
with open(f.name) as f: # type: ignore
file_path = f.read().strip()
with suspend(self.view) as s:
@ -617,7 +617,7 @@ class Controller:
)
return self._open_msg(msg, cmd)
@bind(msg_handler, ["l", "^J"])
@bind(msg_handler, ["l"])
def open_current_msg(self) -> None:
"""Open msg or file with cmd in mailcap"""
msg = MsgProxy(self.model.current_msg)
@ -656,7 +656,7 @@ class Controller:
f.write(msg.text_content)
f.flush()
s.call(f"{config.EDITOR} {f.name}")
with open(f.name) as f:
with open(f.name) as f: # type: ignore
if text := f.read().strip():
self.model.edit_message(text=text)
self.present_info("Message edited")
@ -668,18 +668,20 @@ class Controller:
int(cols / 2),
max(len(user.name) for user in users),
)
users_out = "\n".join(
users_out = [
f"{user.id}\t{user.name:<{limit}} | {user.status}"
for user in sorted(users, key=lambda user: user.order)
)
cmd = config.FZF + " -n 2"
if is_multiple:
cmd += " -m"
]
fzf_flags = "-n 2"
with NamedTemporaryFile("r+") as tmp, suspend(self.view) as s:
s.run_with_input(f"{cmd} > {tmp.name}", users_out)
with open(tmp.name) as f:
return [int(line.split()[0]) for line in f.readlines()]
if is_multiple:
fzf_flags += " -m"
with suspend(self.view):
return [
int(uid.split()[0].strip())
for uid in pyfzf.FzfPrompt().prompt(users_out, fzf_flags)
]
@bind(chat_handler, ["ns"])
def new_secret(self) -> None:
@ -789,7 +791,7 @@ class Controller:
def view_contacts(self) -> None:
self._get_user_ids()
@bind(chat_handler, ["l", "^J", "^E"])
@bind(chat_handler, ["l"])
def handle_msgs(self) -> Optional[str]:
rc = self.handle(msg_handler, 0.2)
if rc == "QUIT":
@ -802,13 +804,13 @@ class Controller:
if self.model.first_chat():
self.render()
@bind(chat_handler, ["j", "^B", "^N"], repeat_factor=True)
@bind(chat_handler, ["j"], repeat_factor=True)
@bind(msg_handler, ["]"])
def next_chat(self, repeat_factor: int = 1) -> None:
if self.model.next_chat(repeat_factor):
self.render()
@bind(chat_handler, ["k", "^C", "^P"], repeat_factor=True)
@bind(chat_handler, ["k"], repeat_factor=True)
@bind(msg_handler, ["["])
def prev_chat(self, repeat_factor: int = 1) -> None:
if self.model.prev_chat(repeat_factor):

View file

@ -5,19 +5,20 @@ from telegram.client import AsyncResult, Telegram
class ChatAction(Enum):
chatActionTyping = "typing"
chatActionTyping = "is typing"
chatActionCancel = "cancel"
chatActionRecordingVideo = "recording video"
chatActionUploadingVideo = "uploading video"
chatActionRecordingVoiceNote = "recording voice"
chatActionUploadingVoiceNote = "uploading voice"
chatActionUploadingPhoto = "uploading photo"
chatActionUploadingDocument = "uploading document"
chatActionChoosingLocation = "choosing location"
chatActionChoosingContact = "choosing contact"
chatActionStartPlayingGame = "start playing game"
chatActionRecordingVideoNote = "recording video"
chatActionUploadingVideoNote = "uploading video"
chatActionRecordingVideo = "is recording a video"
chatActionUploadingVideo = "is uploading a video"
chatActionRecordingVoiceNote = "is recording a voice message"
chatActionUploadingVoiceNote = "is uploading a voice message"
chatActionUploadingPhoto = "is uploading a photo"
chatActionUploadingDocument = "is uploading a document"
chatActionChoosingLocation = "is choosing a location"
chatActionChoosingContact = "is choosing a contact"
chatActionStartPlayingGame = "started playing a game"
chatActionRecordingVideoNote = "is recording a video"
chatActionUploadingVideoNote = "is uploading a video"
chatActionChoosingSticker = "is choosing a sticker"
class ChatType(Enum):

View file

@ -21,6 +21,8 @@ from subprocess import CompletedProcess
from types import TracebackType
from typing import Any, Callable, Dict, Optional, Tuple, Type
from pyperclip import copy as copy_clipboard
from arigram import config
log = logging.getLogger(__name__)
@ -237,9 +239,7 @@ def truncate_to_len(string: str, width: int) -> str:
def copy_to_clipboard(text: str) -> None:
subprocess.run(
config.COPY_CMD, universal_newlines=True, input=text, shell=True
)
copy_clipboard(text)
class suspend:
@ -333,11 +333,11 @@ def pretty_ts(ts: int) -> str:
@lru_cache(maxsize=256)
def get_color_by_str(user: str) -> int:
def get_colour_by_str(user: str) -> int:
index = int(hashlib.sha1(user.encode()).hexdigest(), 16) % len(
config.USERS_COLORS
config.USERS_COLOURS
)
return config.USERS_COLORS[index]
return config.USERS_COLOURS[index]
def cleanup_cache() -> None:

View file

@ -6,10 +6,10 @@ from typing import Any, Dict, List, Optional, Tuple, Union, cast
from _curses import window # type: ignore
from arigram import config
from arigram.colors import (
from arigram.colours import (
bold,
cyan,
get_color,
get_colour,
magenta,
reverse,
white,
@ -19,7 +19,7 @@ from arigram.models import Model, UserModel
from arigram.msg import MsgProxy
from arigram.tdlib import ChatType, get_chat_type, is_group
from arigram.utils import (
get_color_by_str,
get_colour_by_str,
num,
string_len_dwc,
truncate_to_len,
@ -75,7 +75,7 @@ class View:
curses.start_color()
curses.use_default_colors()
# init white color first to initialize colors correctly
get_color(white, -1)
get_colour(white, -1)
self.stdscr = stdscr
self.chats = chat_view
@ -189,13 +189,13 @@ class ChatView:
self.win.resize(self.h, self.w)
def _msg_color(self, is_selected: bool = False) -> int:
color = get_color(white, -1)
color = get_colour(white, -1)
if is_selected:
return color | reverse
return color
def _unread_color(self, is_selected: bool = False) -> int:
color = get_color(magenta, -1)
color = get_colour(magenta, -1)
if is_selected:
return color | reverse
return color
@ -204,9 +204,9 @@ class ChatView:
self, is_selected: bool, title: str, user: Optional[str]
) -> Tuple[int, ...]:
attrs = (
get_color(cyan, -1),
get_color(get_color_by_str(title), -1),
get_color(get_color_by_str(user or ""), -1),
get_colour(cyan, -1),
get_colour(get_colour_by_str(title), -1),
get_colour(get_colour_by_str(user or ""), -1),
self._msg_color(is_selected),
)
if is_selected:
@ -222,7 +222,7 @@ class ChatView:
self.win.vline(0, width, line, self.h)
self.win.addstr(
0, 0, title.center(width)[:width], get_color(cyan, -1) | bold
0, 0, title.center(width)[:width], get_colour(cyan, -1) | bold
)
for i, chat in enumerate(chats, 1):
@ -571,7 +571,7 @@ class MsgView:
column += string_len_dwc(elem)
self.win.addstr(
0, 0, self._msg_title(chat), get_color(cyan, -1) | bold
0, 0, self._msg_title(chat), get_colour(cyan, -1) | bold
)
self._refresh()
@ -604,10 +604,10 @@ class MsgView:
def _msg_attributes(self, is_selected: bool, user: str) -> Tuple[int, ...]:
attrs = (
get_color(cyan, -1),
get_color(get_color_by_str(user), -1),
get_color(yellow, -1),
get_color(white, -1),
get_colour(cyan, -1),
get_colour(get_colour_by_str(user), -1),
get_colour(yellow, -1),
get_colour(white, -1),
)
if is_selected:

87
do
View file

@ -1,35 +1,31 @@
#!/bin/bash
#!/usr/bin/env bash
set -e
set -xe
SRC=$(dirname $0)
main() {
SRC="$(dirname "$0")"
cd "$SRC"
cd $SRC
ARG=${1:-""}
case $ARG in
build)
python3 -m pip install --upgrade setuptools wheel
python3 setup.py sdist bdist_wheel
python3 -m pip install --upgrade twine
python3 -m twine upload --repository testpypi dist/*
;;
ARG=${1:-""}
case $ARG in
review)
gh pr create -f
;;
push)
isort arigram/*.py
black arigram
black .
python3 -m poetry check
python3 -m poetry lock
git diff > /tmp/arigram.diff
$0 check
$0 local
git diff >/tmp/arigram.diff
git add -A
git commit -S
git commit -sa
git push -u origin main
;;
@ -41,58 +37,23 @@ case $ARG in
python3 -m pip install --user --upgrade .
;;
release)
CURRENT_VERSION=$(cat arigram/__init__.py | grep version | cut -d '"' -f 2)
echo Current version $CURRENT_VERSION
NEW_VERSION=$(echo $CURRENT_VERSION | awk -F. '{print $1 "." $2+1 "." $3}')
echo New version $NEW_VERSION
sed -i '' "s|$CURRENT_VERSION|$NEW_VERSION|g" arigram/__init__.py
poetry version $NEW_VERSION
git add -u arigram/__init__.py pyproject.toml
git commit -m "Release v$NEW_VERSION"
git tag v$NEW_VERSION
poetry build
poetry publish -u $(pass show i/pypi | grep username | cut -d ' ' -f 2 | tr -d '\n') -p $(pass show i/pypi | head -n 1 | tr -d '\n')
git log --pretty=format:"%cn: %s" v$CURRENT_VERSION...v$NEW_VERSION | grep -v -e "Merge" | grep -v "Release"| awk '!x[$0]++' > changelog.md
git push origin master --tags
gh release create v$NEW_VERSION -F changelog.md
rm changelog.md
;;
release-brew)
CURRENT_VERSION=$(cat arigram/__init__.py | grep version | cut -d '"' -f 2)
echo Current version $CURRENT_VERSION
URL="https://github.com/TruncatedDinosour/arigram/archive/refs/tags/v$CURRENT_VERSION.tar.gz"
echo $URL
wget $URL -O /tmp/arigram.tar.gz
HASH=$(sha256sum /tmp/arigram.tar.gz | cut -d ' ' -f 1)
rm /tmp/arigram.tar.gz
cd /opt/homebrew/Library/Taps/TruncatedDinosour/dino-bar
sed -i '' "6s|.*| url \"https://github.com/TruncatedDinosour/arigram/archive/refs/tags/v$CURRENT_VERSION.tar.gz\"|" arigram.rb
sed -i '' "7s|.*| sha256 \"$HASH\"|" arigram.rb
brew audit --new arigram
brew uninstall arigram || true
brew install arigram
brew test arigram
git add -u arigram.rb
git commit -m "Release arigram.rb v$CURRENT_VERSION"
git push origin master
upgrade)
git reset --hard
git pull
$0 local
;;
check)
black .
isort arigram/*.py
sh check.sh
chmod a+rx ./check.sh
./check.sh
;;
*)
python3 -m arigram
;;
esac
esac
}
main "$@"

49
poetry.lock generated
View file

@ -115,14 +115,14 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]]
name = "plumbum"
version = "1.7.1"
version = "1.7.2"
description = "Plumbum: shell combinators library"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[package.dependencies]
pypiwin32 = {version = "*", markers = "platform_system == \"Windows\" and platform_python_implementation != \"PyPy\""}
pywin32 = {version = "*", markers = "platform_system == \"Windows\" and platform_python_implementation != \"PyPy\""}
[package.extras]
dev = ["paramiko", "psutil", "pytest", "pytest-cov", "pytest-mock", "pytest-timeout"]
@ -164,17 +164,6 @@ category = "main"
optional = false
python-versions = "*"
[[package]]
name = "pypiwin32"
version = "223"
description = ""
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
pywin32 = ">=223"
[[package]]
name = "python-telegram"
version = "0.15.0"
@ -185,7 +174,7 @@ python-versions = "*"
[[package]]
name = "pywin32"
version = "302"
version = "303"
description = "Python for Window Extensions"
category = "main"
optional = false
@ -226,7 +215,7 @@ python-versions = ">=3.6"
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "061484270c70aa1136531e656408afb105e5d532473e9a642961595878ecbde9"
content-hash = "d09bad5856588aa83f522a7573c118d8f930c23020657822ec409d2d9da274b9"
[metadata.files]
appdirs = [
@ -289,8 +278,8 @@ pathspec = [
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
]
plumbum = [
{file = "plumbum-1.7.1-py2.py3-none-any.whl", hash = "sha256:e97229fdf218698b4e9e939355f4d20d20bf57f8a02710f81f92442e2b2db038"},
{file = "plumbum-1.7.1.tar.gz", hash = "sha256:3c0ac8c4ee57b2adddc82909d3c738a62ef5f77faf24ec7cb6f0a117e1679740"},
{file = "plumbum-1.7.2-py2.py3-none-any.whl", hash = "sha256:0bbf431e31da988405de2fb36c3226f09c0c9cdf69c8480f8997f4b94b7370a1"},
{file = "plumbum-1.7.2.tar.gz", hash = "sha256:0d1bf908076bbd0484d16412479cb97d6843069ee19f99e267e11dd980040523"},
]
pycodestyle = [
{file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
@ -307,24 +296,22 @@ pyfzf = [
pyperclip = [
{file = "pyperclip-1.8.2.tar.gz", hash = "sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57"},
]
pypiwin32 = [
{file = "pypiwin32-223-py3-none-any.whl", hash = "sha256:67adf399debc1d5d14dffc1ab5acacb800da569754fafdc576b2a039485aa775"},
{file = "pypiwin32-223.tar.gz", hash = "sha256:71be40c1fbd28594214ecaecb58e7aa8b708eabfa0125c8a109ebd51edbd776a"},
]
python-telegram = [
{file = "python-telegram-0.15.0.tar.gz", hash = "sha256:35ad8d22256061ec4a6c4aa3379f217e4831c057424cbed9ec3dd61212f8c170"},
]
pywin32 = [
{file = "pywin32-302-cp310-cp310-win32.whl", hash = "sha256:251b7a9367355ccd1a4cd69cd8dd24bd57b29ad83edb2957cfa30f7ed9941efa"},
{file = "pywin32-302-cp310-cp310-win_amd64.whl", hash = "sha256:79cf7e6ddaaf1cd47a9e50cc74b5d770801a9db6594464137b1b86aa91edafcc"},
{file = "pywin32-302-cp36-cp36m-win32.whl", hash = "sha256:fe21c2fb332d03dac29de070f191bdbf14095167f8f2165fdc57db59b1ecc006"},
{file = "pywin32-302-cp36-cp36m-win_amd64.whl", hash = "sha256:d3761ab4e8c5c2dbc156e2c9ccf38dd51f936dc77e58deb940ffbc4b82a30528"},
{file = "pywin32-302-cp37-cp37m-win32.whl", hash = "sha256:48dd4e348f1ee9538dd4440bf201ea8c110ea6d9f3a5010d79452e9fa80480d9"},
{file = "pywin32-302-cp37-cp37m-win_amd64.whl", hash = "sha256:496df89f10c054c9285cc99f9d509e243f4e14ec8dfc6d78c9f0bf147a893ab1"},
{file = "pywin32-302-cp38-cp38-win32.whl", hash = "sha256:e372e477d938a49266136bff78279ed14445e00718b6c75543334351bf535259"},
{file = "pywin32-302-cp38-cp38-win_amd64.whl", hash = "sha256:543552e66936378bd2d673c5a0a3d9903dba0b0a87235ef0c584f058ceef5872"},
{file = "pywin32-302-cp39-cp39-win32.whl", hash = "sha256:2393c1a40dc4497fd6161b76801b8acd727c5610167762b7c3e9fd058ef4a6ab"},
{file = "pywin32-302-cp39-cp39-win_amd64.whl", hash = "sha256:af5aea18167a31efcacc9f98a2ca932c6b6a6d91ebe31f007509e293dea12580"},
{file = "pywin32-303-cp310-cp310-win32.whl", hash = "sha256:6fed4af057039f309263fd3285d7b8042d41507343cd5fa781d98fcc5b90e8bb"},
{file = "pywin32-303-cp310-cp310-win_amd64.whl", hash = "sha256:51cb52c5ec6709f96c3f26e7795b0bf169ee0d8395b2c1d7eb2c029a5008ed51"},
{file = "pywin32-303-cp311-cp311-win32.whl", hash = "sha256:d9b5d87ca944eb3aa4cd45516203ead4b37ab06b8b777c54aedc35975dec0dee"},
{file = "pywin32-303-cp311-cp311-win_amd64.whl", hash = "sha256:fcf44032f5b14fcda86028cdf49b6ebdaea091230eb0a757282aa656e4732439"},
{file = "pywin32-303-cp36-cp36m-win32.whl", hash = "sha256:aad484d52ec58008ca36bd4ad14a71d7dd0a99db1a4ca71072213f63bf49c7d9"},
{file = "pywin32-303-cp36-cp36m-win_amd64.whl", hash = "sha256:2a09632916b6bb231ba49983fe989f2f625cea237219530e81a69239cd0c4559"},
{file = "pywin32-303-cp37-cp37m-win32.whl", hash = "sha256:b1675d82bcf6dbc96363fca747bac8bff6f6e4a447a4287ac652aa4b9adc796e"},
{file = "pywin32-303-cp37-cp37m-win_amd64.whl", hash = "sha256:c268040769b48a13367221fced6d4232ed52f044ffafeda247bd9d2c6bdc29ca"},
{file = "pywin32-303-cp38-cp38-win32.whl", hash = "sha256:5f9ec054f5a46a0f4dfd72af2ce1372f3d5a6e4052af20b858aa7df2df7d355b"},
{file = "pywin32-303-cp38-cp38-win_amd64.whl", hash = "sha256:793bf74fce164bcffd9d57bb13c2c15d56e43c9542a7b9687b4fccf8f8a41aba"},
{file = "pywin32-303-cp39-cp39-win32.whl", hash = "sha256:7d3271c98434617a11921c5ccf74615794d97b079e22ed7773790822735cc352"},
{file = "pywin32-303-cp39-cp39-win_amd64.whl", hash = "sha256:79cbb862c11b9af19bcb682891c1b91942ec2ff7de8151e2aea2e175899cda34"},
]
regex = [
{file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"},

View file

@ -11,7 +11,7 @@ repository = "https://github.com/TruncatedDinosour/arigram"
[tool.poetry.dependencies]
python = "^3.8"
python-telegram = "^0.15.0^"
python-telegram = "0.15.0"
pyfzf = "^0.2.2"
pyperclip = "^1.8.2"

View file

@ -1,4 +1,4 @@
python-telegram>=0.15.0
python-telegram==0.15.0
pyfzf>=0.2.2
pyperclip>=1.8.2

View file

@ -24,7 +24,7 @@ setup(
entry_points={"console_scripts": ["arigram = arigram.__main__:main"]},
python_requires=">=3.8",
install_requires=[
"python-telegram>=0.15.0",
"python-telegram==0.15.0",
"pyfzf>=0.2.2",
"pyperclip>=1.8.2",
],