Initial commit
This commit is contained in:
		
							
								
								
									
										163
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
# pdm
 | 
			
		||||
#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
 | 
			
		||||
#pdm.lock
 | 
			
		||||
#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
 | 
			
		||||
#   in version control.
 | 
			
		||||
#   https://pdm.fming.dev/#use-with-ide
 | 
			
		||||
.pdm.toml
 | 
			
		||||
 | 
			
		||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
 | 
			
		||||
__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/
 | 
			
		||||
 | 
			
		||||
# PyCharm
 | 
			
		||||
#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
 | 
			
		||||
#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
 | 
			
		||||
#  and can be added to the global gitignore or merged into this file.  For a more nuclear
 | 
			
		||||
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
 | 
			
		||||
#.idea/
 | 
			
		||||
 | 
			
		||||
# Application
 | 
			
		||||
config.ini
 | 
			
		||||
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2022 niku
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
# contrib-scribe
 | 
			
		||||
Your contribution heatmap is a canvas for creativity.
 | 
			
		||||
 | 
			
		||||
## Prerequisites
 | 
			
		||||
- systemd
 | 
			
		||||
- python (>=3.10)
 | 
			
		||||
- git
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
```sh
 | 
			
		||||
# Start
 | 
			
		||||
./scripts/install.sh
 | 
			
		||||
 | 
			
		||||
# Stop
 | 
			
		||||
./scripts/uninstall.sh
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										4
									
								
								config.ini.sample
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								config.ini.sample
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
[contrib_scribe]
 | 
			
		||||
repo_path = ~/path/to/repo
 | 
			
		||||
message = hi there
 | 
			
		||||
commit_count = 3
 | 
			
		||||
							
								
								
									
										342
									
								
								contrib_scribe.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										342
									
								
								contrib_scribe.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,342 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
import base64
 | 
			
		||||
import configparser
 | 
			
		||||
import typing
 | 
			
		||||
import sys
 | 
			
		||||
import pathlib
 | 
			
		||||
from datetime import date, timedelta
 | 
			
		||||
import subprocess as sub
 | 
			
		||||
import appdirs
 | 
			
		||||
 | 
			
		||||
CharRepr = typing.List[typing.List[typing.Literal[0] | typing.Literal[1]]]
 | 
			
		||||
 | 
			
		||||
CHAR_SPACING = 1
 | 
			
		||||
FONT_MAP: typing.Mapping[str, CharRepr] = {
 | 
			
		||||
    "A": [
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 1, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "B": [
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "C": [
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "D": [
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "E": [
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "F": [
 | 
			
		||||
        [1, 1, 1, 1],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 1, 1, 1],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "G": [
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 1, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [0, 1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "H": [
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 1, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "I": [
 | 
			
		||||
        [1],
 | 
			
		||||
        [1],
 | 
			
		||||
        [1],
 | 
			
		||||
        [1],
 | 
			
		||||
        [1],
 | 
			
		||||
        [1],
 | 
			
		||||
        [1],
 | 
			
		||||
    ],
 | 
			
		||||
    "J": [
 | 
			
		||||
        [0, 0, 1],
 | 
			
		||||
        [0, 0, 1],
 | 
			
		||||
        [0, 0, 1],
 | 
			
		||||
        [0, 0, 1],
 | 
			
		||||
        [0, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "K": [
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 1, 0],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "L": [
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 0, 0],
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "M": [
 | 
			
		||||
        [0, 1, 0, 1, 0],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "N": [
 | 
			
		||||
        [1, 1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1, 1],
 | 
			
		||||
        [1, 0, 0, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "O": [
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "P": [
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "Q": [
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 1, 1],
 | 
			
		||||
        [0, 1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "R": [
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "S": [
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
        [0, 0, 0, 1],
 | 
			
		||||
        [1, 0, 0, 1],
 | 
			
		||||
        [0, 1, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "T": [
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "U": [
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "V": [
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "W": [
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [1, 0, 1, 0, 1],
 | 
			
		||||
        [0, 1, 0, 1, 0],
 | 
			
		||||
    ],
 | 
			
		||||
    "X": [
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [0, 1, 0],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "Y": [
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 0, 1],
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
        [0, 0, 1],
 | 
			
		||||
        [0, 0, 1],
 | 
			
		||||
        [1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    "Z": [
 | 
			
		||||
        [1, 1, 1, 1],
 | 
			
		||||
        [0, 0, 0, 1],
 | 
			
		||||
        [0, 0, 1, 0],
 | 
			
		||||
        [0, 1, 0, 0],
 | 
			
		||||
        [0, 1, 0, 0],
 | 
			
		||||
        [1, 0, 0, 0],
 | 
			
		||||
        [1, 1, 1, 1],
 | 
			
		||||
    ],
 | 
			
		||||
    " ": [
 | 
			
		||||
        [0, 0],
 | 
			
		||||
        [0, 0],
 | 
			
		||||
        [0, 0],
 | 
			
		||||
        [0, 0],
 | 
			
		||||
        [0, 0],
 | 
			
		||||
        [0, 0],
 | 
			
		||||
        [0, 0],
 | 
			
		||||
    ],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def message_to_matrix(message: str) -> CharRepr:
 | 
			
		||||
    matrix: CharRepr = [[] for _ in range(7)]
 | 
			
		||||
 | 
			
		||||
    for char in message:
 | 
			
		||||
        crepr = FONT_MAP.get(char)
 | 
			
		||||
        if not crepr:
 | 
			
		||||
            raise ValueError(f'No repr for "{char}" found in font mapping.')
 | 
			
		||||
        for i in range(7):
 | 
			
		||||
            matrix[i].extend(crepr[i])
 | 
			
		||||
            matrix[i].extend([0] * CHAR_SPACING)
 | 
			
		||||
 | 
			
		||||
    return matrix
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def print_char_matrix(matrix: CharRepr):
 | 
			
		||||
    fill = {0: " ", 1: "█"}
 | 
			
		||||
    for row in matrix:
 | 
			
		||||
        print("".join(fill[char] for char in row))
 | 
			
		||||
 | 
			
		||||
    print(f"\nWidth: {len(matrix[0])}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_config(path: str) -> typing.Mapping[str, str]:
 | 
			
		||||
    parser = configparser.ConfigParser()
 | 
			
		||||
    parser.read(path)
 | 
			
		||||
    return parser["contrib_scribe"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_state(path: pathlib.Path) -> date:
 | 
			
		||||
    if not path.exists():
 | 
			
		||||
        state = date.today()
 | 
			
		||||
        if (weekday := state.weekday()) != 6:
 | 
			
		||||
            state += timedelta(days=6 - weekday)
 | 
			
		||||
        with path.open("w") as fp:
 | 
			
		||||
            fp.write(str(state))
 | 
			
		||||
        return state
 | 
			
		||||
 | 
			
		||||
    with path.open("r") as fp:
 | 
			
		||||
        return date.fromisoformat(fp.read())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main(args: typing.Sequence[str]) -> int:
 | 
			
		||||
    if len(args) < 1:
 | 
			
		||||
        print("Usage: contrib_scribe.py <config.ini>", file=sys.stderr)
 | 
			
		||||
        return 1
 | 
			
		||||
 | 
			
		||||
    cfg = parse_config(args[0])
 | 
			
		||||
    cfg_id = base64.b32encode(bytearray(args[0], "ascii")).decode("utf-8")
 | 
			
		||||
 | 
			
		||||
    data_dir = appdirs.user_data_dir("contrib-scribe")
 | 
			
		||||
    data_path = pathlib.Path(data_dir)
 | 
			
		||||
    data_path.mkdir(parents=True, exist_ok=True)
 | 
			
		||||
 | 
			
		||||
    state_path = data_path / cfg_id
 | 
			
		||||
    start_date = parse_state(state_path)
 | 
			
		||||
 | 
			
		||||
    message = cfg["message"].upper()
 | 
			
		||||
    matrix = message_to_matrix(message)
 | 
			
		||||
 | 
			
		||||
    print_char_matrix(matrix)
 | 
			
		||||
 | 
			
		||||
    day_diff = (date.today() - start_date).days
 | 
			
		||||
    row, column = day_diff % 7, day_diff // 7
 | 
			
		||||
    if matrix[row][column] == 0:
 | 
			
		||||
        print("No commit's to do today!")
 | 
			
		||||
        return 0
 | 
			
		||||
 | 
			
		||||
    file_path = pathlib.Path(cfg["repo_path"]) / "test"
 | 
			
		||||
    commit_count = int(cfg["commit_count"])
 | 
			
		||||
    for i in range(commit_count):
 | 
			
		||||
        file_path.write_text(str(i))
 | 
			
		||||
        commands = [["git", "add", "."], ["git", "commit", "-m", str(i)]]
 | 
			
		||||
        for command in commands:
 | 
			
		||||
            sub.call(command, cwd=file_path.parent)
 | 
			
		||||
 | 
			
		||||
    sub.call(["git", "push"], cwd=file_path.parent)
 | 
			
		||||
    print("Did daily commit")
 | 
			
		||||
    return 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    raise SystemExit(main(sys.argv[1:]))
 | 
			
		||||
							
								
								
									
										6
									
								
								contrib_scribe_test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								contrib_scribe_test.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import contrib_scribe
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_font_size():
 | 
			
		||||
    for char, crepr in contrib_scribe.FONT.items():
 | 
			
		||||
        assert len(crepr) == 7, f'"{char}" is taller than 7 pixels'
 | 
			
		||||
							
								
								
									
										1
									
								
								requirements-dev.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								requirements-dev.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
pytest
 | 
			
		||||
							
								
								
									
										1
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
appdirs
 | 
			
		||||
							
								
								
									
										26
									
								
								scripts/install.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								scripts/install.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Sets up the necessary systemd timer & service. 
 | 
			
		||||
 | 
			
		||||
service_name=contrib-writer
 | 
			
		||||
 | 
			
		||||
sudo tee /usr/lib/systemd/user/$service_name.service &>/dev/null <<EOF
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Your contribution heatmap is a canvas for creativity.
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=$(pwd)/contrib_scribe.py $(pwd)/config.ini 
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
sudo tee /usr/lib/systemd/user/$service_name.timer &>/dev/null <<EOF
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Your contribution heatmap is a canvas for creativity.
 | 
			
		||||
 | 
			
		||||
[Timer]
 | 
			
		||||
OnCalendar=daily
 | 
			
		||||
Persistent=true
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=timers.target
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
systemctl enable --user contrib-writer.timer --now
 | 
			
		||||
							
								
								
									
										10
									
								
								scripts/uninstall.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								scripts/uninstall.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
# Deletes related created systemd timer & service. 
 | 
			
		||||
 | 
			
		||||
service_name=contrib-writer
 | 
			
		||||
 | 
			
		||||
systemctl disable --user $service_name.timer
 | 
			
		||||
systemctl stop --user $service_name.timer
 | 
			
		||||
 | 
			
		||||
sudo rm /usr/lib/systemd/user/$service_name.service
 | 
			
		||||
sudo rm /usr/lib/systemd/user/$service_name.timer
 | 
			
		||||
		Reference in New Issue
	
	Block a user