-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d1b210b
Showing
41 changed files
with
1,929 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.vscode | ||
__pycache__ | ||
|
||
# testing logos | ||
custom_logos |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# build requirements | ||
FROM python:3.10.5-slim-bullseye AS builder | ||
|
||
RUN apt-get -y update && \ | ||
apt-get -y install --no-install-recommends \ | ||
build-essential | ||
|
||
ENV PATH=/root/.local/bin:$PATH | ||
COPY tilefy/requirements.txt /requirements.txt | ||
RUN pip install --upgrade pip && pip install --user -r requirements.txt | ||
|
||
|
||
# load in main image | ||
FROM python:3.10.5-slim-bullseye as tilefy | ||
ARG INSTALL_DEBUG | ||
ENV PYTHONUNBUFFERED 1 | ||
|
||
# copy build requirements | ||
COPY --from=builder /root/.local /root/.local | ||
ENV PATH=/root/.local/bin:$PATH | ||
|
||
RUN apt-get clean && apt-get -y update && \ | ||
apt-get -y install --no-install-recommends \ | ||
ttf-bitstream-vera fonts-liberation && \ | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
# install debug tools for testing environment | ||
RUN if [ "$INSTALL_DEBUG" ] ; then \ | ||
apt-get -y update && apt-get -y install --no-install-recommends \ | ||
vim htop bmon net-tools iputils-ping procps \ | ||
&& pip install --user ipython \ | ||
; fi | ||
|
||
RUN mkdir /data | ||
RUN mkdir /app | ||
|
||
COPY tilefy /app | ||
WORKDIR /app | ||
|
||
RUN chmod +x ./start.sh | ||
|
||
VOLUME /data | ||
CMD ["./start.sh"] |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
![Tilefy](assets/tilefy-banner.jpg?raw=true "Tilefy Banner") | ||
|
||
<center><h1>Create beautiful tiles for your project</h1></center> | ||
|
||
## Table of contents | ||
- [Core functionality](#core-functionality) | ||
- [Screenshots](#screenshots) | ||
- [Installation](#installation) | ||
- [Configuration](#configuration) | ||
- [API requests](#api-requests) | ||
- [Plugins](#plugins) | ||
- [Donate](#donate) | ||
|
||
## Core functionality | ||
- Dynamically create and recreate PNG tiles | ||
- Showcase any project stats accessible over a public API | ||
- Customize to your liking with your branding and color scheme | ||
- Embed your tiles anywhere you can embed a image | ||
- Self Hosted with Docker | ||
|
||
## Screenshots | ||
![home screenshot](assets/screenshot.png?raw=true "Tilefy Home Page") | ||
|
||
## Installation | ||
Take a look at the example `docker-compose.yml` file provided. Tilefy depends on two containers: | ||
|
||
### Tilefy | ||
Main Python application to create and serve your tiles, built with Flask. | ||
- Serves the interface on port `8000` | ||
- Needs a volume at **/data** to store your tiles, custom fonts and logos and your **tiles.yml** config file. | ||
- Set your Redis connection with the environment variables `REDIS_HOST` and `REDIS_PORT`. | ||
- Set the environment variable `TILEFY_HOST` to your full url from where you are hosting this application. Needed to build links and templates to embed your tiles. Don't add a trailing `/`. | ||
- Set your timezone with the `TZ` environment variable to configure the scheduler, defaults to *UTC*. | ||
|
||
### Redis JSON | ||
Functions as a cache and holds the scheduler data storage and history. | ||
- Needs a volume at **/data** to store your configurations permanently. | ||
|
||
## Configuration | ||
Create a yml config file where you have mounted your `/data/tiles.yml` folder. Take a look at the provided `tiles.example.yml` for the basic syntax. *tiles* is the top level key, list your tiles below. The main key of the tile is your slug and will become your url, so use no spaces or special characters. | ||
|
||
### tile_name | ||
Give your tile a unique human readable name. | ||
|
||
### background_color, font_color | ||
Hex color code for background and font, make sure to add the *""* to escape the *#* symbol. | ||
|
||
### width, height | ||
Size of the tile in pixels. | ||
|
||
### logos | ||
List of logos, get a list of pre installed logos: | ||
```bash | ||
docker exec -it tilefy ls logos | ||
``` | ||
Add the pre installed logos by providing the file name. Contribute by adding additional commonly used logos. | ||
|
||
Provide your custom logos by adding them to `/data/logos/`, in PNG file format with transparent background. Add your custom logos by providing a relative path like `logos/file-name.png`. | ||
|
||
### font: optional | ||
Font defaults to *Vera.ttf*. Use a pre installed font from the *liberation* or *ttf-bitstream-vera* packages by providing the relative path from the truetype folder. | ||
List available pre installed fonts: | ||
```bash | ||
docker exec -it tilefy ls /usr/share/fonts/truetype/liberation | ||
docker exec -it tilefy ls /usr/share/fonts/truetype/ttf-bitstream-vera | ||
``` | ||
|
||
Provide your custom font by adding them to `/data/fonts`, in TTF format only and add them with their relative path like `fonts/font-name.ttf`. | ||
|
||
### humanize: optional | ||
Defaults to `true` for all numbers. Shorten long numbers in to a more human readable string, like *14502* to *14.5K*. | ||
|
||
### recreate: optional | ||
Recreate tiles periodically, provide your custom schedule as a cron tab or use `on_demand` to recreate the tile for every request. Defaults to `0 0 * * *` aka every day at midnight. Be aware of any rate limiting and API quotas you might face with a too frequent schedule. | ||
Note: | ||
- There is automatically a random jitter for cron tab of 15 secs to avoid parallel requests for a lot of tiles. | ||
- There is a failsafe in place to block recreating tiles faster than every 60 seconds. | ||
|
||
## API requests | ||
Get values from a public API by providing the url and key_map. | ||
|
||
### url | ||
JSON API endpoint. If you can, filter and reduce the API response size by requesting only the required fields. | ||
|
||
### key_map | ||
Navigate the JSON object to find your desired value. Each item in the list navigates one level deeper, a `string` accesses a key and a `int` accesses an index in an array. | ||
|
||
*Example 1* | ||
```json | ||
{ | ||
"pull_count": 269912, | ||
"star_count": 11, | ||
} | ||
``` | ||
To for example access the *pull_count* key in the top level of the response: | ||
```yml | ||
key_map: | ||
- pull_count | ||
``` | ||
*Example 2* | ||
```json | ||
{ | ||
"results": [ | ||
{ | ||
"status": "success", | ||
"last_run": "timestamp", | ||
} | ||
] | ||
} | ||
``` | ||
|
||
To for example access the *status* key in the first dictionary of the results list: | ||
```yml | ||
key_map: | ||
- results | ||
- 0 | ||
- status | ||
``` | ||
## Plugins | ||
For all values not accessible over a JSON API endpoint, this will need a dedicated solution by for example scraping the website. This is inherently less reliable as websites change more frequently than APIs. | ||
### Chrome extension users | ||
Get the amount of active chrome extension users. | ||
```yml | ||
plugin: | ||
name: chrome-extension-users | ||
id: jjnkmicfnfojkkgobdfeieblocadmcie | ||
``` | ||
Please contribute and open feature requests to add more. | ||
## Donate | ||
The best donation to **Tilefy** is your time, contribute in any way you can to improve this project. | ||
Second best way to support the development is to provide for caffeinated beverages: | ||
* [Paypal.me](https://paypal.me/bbilly1) for a one time coffee | ||
* [Paypal Subscription](https://www.paypal.com/webapps/billing/plans/subscribe?plan_id=P-03770005GR991451KMFGVPMQ) for a monthly coffee | ||
* [ko-fi.com](https://ko-fi.com/bbilly1) for an alternative platform |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#!/bin/bash | ||
# deploy app | ||
|
||
test_host="tilefy.local" | ||
|
||
function rebuild_test { | ||
echo "rebuild testing environment" | ||
rsync -a --progress --delete-after \ | ||
--exclude ".git" \ | ||
--exclude ".gitignore" \ | ||
--exclude "**/cache" \ | ||
--exclude "**/__pycache__/" \ | ||
--exclude "db.sqlite3" \ | ||
. -e ssh "$test_host":tilefy | ||
|
||
rsync --progress --ignore-existing docker-compose.yml -e ssh "$test_host":docker | ||
rsync --progress tiles.example.yml -e ssh "$test_host":docker/volume/tilefy/data/tiles.yml | ||
|
||
ssh "$test_host" "docker buildx build --build-arg INSTALL_DEBUG=1 -t bbilly1/tilefy tilefy --load" | ||
ssh "$test_host" 'docker compose -f docker/docker-compose.yml up -d --build' | ||
} | ||
|
||
function validate { | ||
|
||
if [[ $1 ]]; then | ||
check_path="$1" | ||
else | ||
check_path="." | ||
fi | ||
|
||
echo "run validate on $check_path" | ||
|
||
echo "running black" | ||
black --diff --color --check -l 79 "$check_path" | ||
echo "running codespell" | ||
codespell --skip="./.git" "$check_path" | ||
echo "running flake8" | ||
flake8 "$check_path" --count --max-complexity=10 --max-line-length=79 \ | ||
--show-source --statistics | ||
echo "running isort" | ||
isort --check-only --diff --profile black -l 79 "$check_path" | ||
printf " \n> all validations passed\n" | ||
|
||
} | ||
|
||
function docker_publish { | ||
|
||
# check things | ||
if [[ $(git branch --show-current) != 'master' ]]; then | ||
echo 'you are not on master, dummy!' | ||
return | ||
fi | ||
|
||
if [[ $(systemctl is-active docker) != 'active' ]]; then | ||
echo "starting docker" | ||
sudo systemctl start docker | ||
fi | ||
echo "latest tags:" | ||
git tag | tail -n 5 | sort -r | ||
|
||
printf "\ncreate new version:\n" | ||
read -r VERSION | ||
|
||
echo "build and push $VERSION?" | ||
read -rn 1 | ||
|
||
# start build | ||
sudo docker buildx build \ | ||
--platform linux/amd64,linux/arm64 \ | ||
-t bbilly1/tilefy \ | ||
-t bbilly1/tilefy:"$VERSION" --push . | ||
|
||
# create release tag | ||
echo "commits since last version:" | ||
git log "$(git describe --tags --abbrev=0)"..HEAD --oneline | ||
git tag -a "$VERSION" -m "new release version $VERSION" | ||
git push origin "$VERSION" | ||
|
||
} | ||
|
||
|
||
if [[ $1 == "test" ]]; then | ||
rebuild_test | ||
elif [[ $1 == "validate" ]]; then | ||
# check package versions in requirements.txt for updates | ||
python version_check.py | ||
validate "$2" | ||
elif [[ $1 == "docker" ]]; then | ||
docker_publish | ||
else | ||
echo "valid options are: test | docker " | ||
fi | ||
|
||
## | ||
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
version: '3.3' | ||
|
||
services: | ||
tilefy: | ||
container_name: tilefy | ||
restart: always | ||
image: bbilly1/tilefy | ||
volumes: | ||
- ./volume/tilefy/data:/data | ||
ports: | ||
- 8000:8000 | ||
environment: | ||
- TZ=America/New_York | ||
- TILEFY_HOST=http://tilefy.local | ||
- REDIS_HOST=tilefy-redis | ||
- REDIS_PORT=6379 | ||
tilefy-redis: | ||
image: redislabs/rejson | ||
container_name: tilefy-redis | ||
restart: always | ||
expose: | ||
- "6379" | ||
volumes: | ||
- ./volume/tilefy/redis:/data |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
APScheduler==3.9.1 | ||
beautifulsoup4==4.11.1 | ||
flask==2.1.2 | ||
Pillow==9.1.1 | ||
PyYAML==6.0 | ||
redis==4.3.3 | ||
requests==2.28.0 | ||
uwsgi==2.0.20 |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
"""make api call to get variable text""" | ||
|
||
import requests | ||
from src.plugins.chrome_extension import ChromeExtension | ||
|
||
|
||
def humanize(number): | ||
"""humanize number to string""" | ||
|
||
break_points = [ | ||
(999999999, "B"), | ||
(999999, "M"), | ||
(999, "K"), | ||
] | ||
|
||
for break_point in break_points: | ||
break_nr, break_str = break_point | ||
if number > break_nr: | ||
return f"{round(number / (break_nr + 1), 1)}{break_str}" | ||
|
||
return str(number) | ||
|
||
|
||
class Api: | ||
"""make request and parse""" | ||
|
||
def __init__(self, tile_config): | ||
self.tile_config = tile_config | ||
|
||
def get_text(self): | ||
"""run all""" | ||
if "plugin" in self.tile_config: | ||
key_match = self.plugin() | ||
else: | ||
key_match = self.url() | ||
|
||
to_humanize = self.tile_config.get("humanize", True) | ||
if not to_humanize or isinstance(key_match, str): | ||
return str(key_match) | ||
|
||
return humanize(key_match) | ||
|
||
def url(self): | ||
"""make call using url from tile_config""" | ||
response = self.make_request() | ||
key_match = self.walk_response(response) | ||
if not key_match: | ||
print(f"failed to result with key_map: {response}") | ||
raise ValueError | ||
|
||
return key_match | ||
|
||
def make_request(self): | ||
"""make request""" | ||
url = self.tile_config["url"] | ||
response = requests.get(url, timeout=1) | ||
if not response.ok: | ||
print(f"failed to make request: {url}") | ||
raise ValueError | ||
|
||
return response.json() | ||
|
||
def walk_response(self, response): | ||
"""walk response dict for key""" | ||
for item in self.tile_config["key_map"]: | ||
response = response[item] | ||
|
||
return response | ||
|
||
def plugin(self): | ||
"""make request with pugin""" | ||
plugin_name = self.tile_config["plugin"]["name"] | ||
item_id = self.tile_config["plugin"]["id"] | ||
if plugin_name == "chrome-extension-users": | ||
users = ChromeExtension(item_id).get() | ||
return users | ||
|
||
raise ValueError("missing plugin") |
Empty file.
Oops, something went wrong.