Compare commits

..

2 Commits

Author SHA1 Message Date
1cae3824b2 Search icons and fonts near the script
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-29 13:04:31 +02:00
62fc7eb2f0 Fix locales 2023-08-29 13:04:25 +02:00
6 changed files with 35 additions and 21 deletions

View File

@ -1,11 +1,13 @@
FROM alpine:3
ENV MUSL_LOCPATH="/usr/share/i18n/locales/musl"
ENTRYPOINT ["python", "/srv/e-paper/main.py"]
WORKDIR /srv/e-paper
VOLUME /data
RUN apk add --no-cache python3 py3-cairosvg py3-pillow py3-pip py3-pygal tzdata && pip install --upgrade icalendar
RUN apk add --no-cache musl-locales musl-locales-lang python3 py3-cairosvg py3-pillow py3-pip py3-pygal tzdata && pip install --upgrade icalendar
ADD https://github.com/adobe-fonts/source-sans/raw/release/OTF/SourceSans3-Bold.otf /usr/share/fonts/source-sans/SourceSans3-Bold.otf
ADD https://github.com/adobe-fonts/source-sans/raw/release/OTF/SourceSans3-It.otf /usr/share/fonts/source-sans/SourceSans3-It.otf

View File

@ -165,7 +165,7 @@ def main(only_on_coming_evt=False, ignore_module=[], force_coming_event=True, ex
from modules import AlertsModule
mod, more_alerts = AlertsModule(alerts, ignore_module).draw_module(config, 480, min(317, 640 - NEXT_STOP_Y - occuped_space))
mod, more_alerts = AlertsModule(config, alerts, ignore_module).draw_module(config, 480, min(317, 640 - NEXT_STOP_Y - occuped_space))
if NEXT_STOP_Y + occuped_space + mod.height > 580 or mod.height > 260:
image.paste(mod, (0, 640-mod.height), mod)
elif mod.height < 100:

View File

@ -1,12 +1,16 @@
import os
import os.path
import logging
from tempfile import NamedTemporaryFile
import sys
from PIL import Image, ImageDraw, ImageFont
class Config:
def __init__(self, cache_timeout, max_cache_timeout, cals_file_list=".cals"):
self.icons_dir = os.path.join(os.path.dirname(sys.argv[0]), "icons")
self.fonts_dir = os.path.join(os.path.dirname(sys.argv[0]), "fonts")
self.cache_timeout = cache_timeout
self.max_cache_timeout = max_cache_timeout
@ -94,7 +98,8 @@ class RuleModule:
class AlertsModule:
def __init__(self, alerts=[], ignore_module=[]):
def __init__(self, config, alerts=[], ignore_module=[]):
self._config = config
self.icon_size = 50
self.alerts = alerts
self.ignore_module = ignore_module
@ -106,7 +111,7 @@ class AlertsModule:
image.paste(icon_img, (int(self.icon_size / 2 - font_size*self.icon_size/32), align))
else:
color_img = Image.new('RGB', (self.icon_size, self.icon_size), "#fff")
icon_img = Image.open("icons/" + alert["icon"]).resize((self.icon_size, self.icon_size))
icon_img = Image.open(os.path.join(self._config.icons_dir, alert["icon"])).resize((self.icon_size, self.icon_size))
image.paste(color_img, (0, align - 5), icon_img)
if "title" in alert:

View File

@ -3,6 +3,7 @@ import hashlib
import json
import logging
import os
import os.path
import re
import urllib.parse
import urllib.request
@ -33,8 +34,8 @@ def whenStr(date, now):
class IDFMAPI:
fnt_R_path = "./fonts/Parisine-Regular.ttf"
fnt_RB_path = "./fonts/Parisine-Bold.ttf"
fnt_R_path = "Parisine-Regular.ttf"
fnt_RB_path = "Parisine-Bold.ttf"
lines = {
"metros": {
@ -80,6 +81,9 @@ class IDFMAPI:
def __init__(self, config, apikey=None):
self.fnt_R_path = os.path.join(config.fonts_dir, IDFMAPI.fnt_R_path)
self.fnt_RB_path = os.path.join(config.fonts_dir, IDFMAPI.fnt_RB_path)
self.baseurl = "https://prim.iledefrance-mobilites.fr/marketplace"
self.apikey = apikey or os.environ["TOKEN_IDFM"]
@ -197,12 +201,12 @@ class IDFMAPI:
return None
def get_line_icon(mode, line, size, fill="gray"):
def get_line_icon(config, mode, line, size, fill="gray"):
width = int(size * 1.38) if mode == "buses" or mode == "tramways" else size
image = Image.new('RGBA', (width, size), '#fff0')
draw = ImageDraw.Draw(image)
fnt_icon = ImageFont.truetype(IDFMAPI.fnt_RB_path, size-3)
fnt_icon = ImageFont.truetype(os.path.join(config.fonts_dir, IDFMAPI.fnt_RB_path), size-3)
if mode == "M" or mode == "metros":
draw.ellipse((0, 0, width, size), fill=fill)
@ -241,10 +245,10 @@ class RATPWeatherModule:
image = Image.new('RGB', (size, size), '#000')
white = Image.new('RGB', (int(size / 2), int(size / 2)), '#fff')
mode_icon = Image.open("icons/" + mode + ".png").resize((int(size/2), int(size/2)))
mode_icon = Image.open(os.path.join(config.icons_dir, mode + ".png")).resize((int(size/2), int(size/2)))
image.paste(white, (-5,0), mode_icon)
line_icon = IDFMAPI.get_line_icon(mode, line, int(size/2), fill="white")
line_icon = IDFMAPI.get_line_icon(config, mode, line, int(size/2), fill="white")
image.paste(line_icon, (int(size/2) - 5,0), line_icon)
return image
@ -314,7 +318,7 @@ class RATPWeatherModule:
align_x = 0
# display mode icon
icon = Image.open("icons/" + mode + ".png").resize((line_height, line_height))
icon = Image.open(os.path.join(config.icons_dir, mode + ".png")).resize((line_height, line_height))
image.paste(icon, (align_x,align_y), icon)
align_x += line_height + 10
@ -342,7 +346,7 @@ class RATPWeatherModule:
elif len(states) > 0:
fill = "gray"
icon = IDFMAPI.get_line_icon(mode, line, line_height, fill=fill)
icon = IDFMAPI.get_line_icon(config, mode, line, line_height, fill=fill)
image.paste(icon, (align_x, align_y), icon)
align_x += icon.width + 5
@ -363,8 +367,8 @@ class RATPNextStopModule:
alerts = []
fnt_R = ImageFont.truetype(IDFMAPI.fnt_R_path, line_height)
fnt_B = ImageFont.truetype(IDFMAPI.fnt_RB_path, line_height)
fnt_R = ImageFont.truetype(os.path.join(config.fonts_dir, IDFMAPI.fnt_R_path), line_height)
fnt_B = ImageFont.truetype(os.path.join(config.fonts_dir, IDFMAPI.fnt_RB_path), line_height)
align = 0
@ -381,7 +385,7 @@ class RATPNextStopModule:
prep[s["destination"]] = []
prep[s["destination"]].append(s)
icon = IDFMAPI.get_line_icon(mode, line, int(line_height*(1.5 if len(prep.keys()) > 1 else 1)))
icon = IDFMAPI.get_line_icon(config, mode, line, int(line_height*(1.5 if len(prep.keys()) > 1 else 1)))
image.paste(icon, (0, align), icon)
max_dest = 64

View File

@ -3,6 +3,7 @@ import base64
import json
import logging
import os
import os.path
import urllib.error
import urllib.parse
import urllib.request
@ -18,13 +19,14 @@ class SNCFAPI:
self.baseurl = "https://www.sncf.com/api/iv"
self.auth = base64.b64encode(b"admin:$2y$10$QvxWSS4f5DIFSkAmuBoV9OJG3M2bhec9d3F2.YnULBMtpzKAq2KS.").decode()
self._config = config
self._cached_file = ".sncf-%d-%s.cache"
self.cache_timeout = config.cache_timeout
self.max_cache_timeout = config.max_cache_timeout
def get_icon(size):
height = int(size * 0.531)
img = Image.open("icons/sncf.png").resize((size, height))
img = Image.open(os.path.join(self._config.icons_dir, "sncf.png")).resize((size, height))
r,g,b,a = img.split()
rgb_image = Image.merge('RGB', (r,g,b))
inverted_image = ImageOps.invert(rgb_image)

View File

@ -2,6 +2,7 @@ from datetime import datetime, timezone, timedelta
import io
import itertools
import math
import os.path
from PIL import Image, ImageDraw, ImageFont
@ -121,7 +122,7 @@ class WeatherJumboCurrentModule:
# current
curweather = WeatherAPI().get_currently()
icon = Image.open("icons/" + WeatherAPI.get_icon(curweather["condition"]["code"], night=not curweather["is_day"], current=True)).resize((height, height))
icon = Image.open(os.path.join(config.icons_dir, WeatherAPI.get_icon(curweather["condition"]["code"], night=not curweather["is_day"], current=True))).resize((height, height))
image.paste(icon, (int(width*self.middle_align - height), 0), icon)
draw.text(
@ -158,7 +159,7 @@ class WeatherMoonPhaseModule:
def draw_module(self, config, width, height):
image = Image.new('RGBA', (width, height), '#fff0')
icon = Image.open("icons/" + WeatherAPI().get_moon_icon()).resize((height, height))
icon = Image.open(os.path.join(config.icons_dir, WeatherAPI().get_moon_icon())).resize((height, height))
image.paste(icon, (0,0), icon)
return image
@ -183,7 +184,7 @@ class WeatherSunModule:
for icon, info in infos.items():
if info == "":
continue
icon = Image.open("icons/wi-" + icon + ".png").resize((height, height))
icon = Image.open(os.path.join(config.icons_dir, "wi-" + icon + ".png")).resize((height, height))
image.paste(icon, (align,0), icon)
align += height + 2
draw.text(
@ -237,7 +238,7 @@ class WeatherRainModule:
image = Image.open(io.BytesIO(gauge.render_to_png()))
if icon_path:
icon = Image.open("icons/" + icon_path).resize((int(height/1.25), int(height/1.25)))
icon = Image.open(os.path.join(config.icons_dir, icon_path)).resize((int(height/1.25), int(height/1.25)))
image.paste(icon, (int(width/2-height/2.5), int(height-height/1.25)), icon)
return image
@ -321,7 +322,7 @@ class WeeklyWeatherModule:
i = 1
for day in weekweather[self.first_day:self.first_day+self.limit_futur]:
icon = Image.open("icons/" + WeatherAPI.get_icon(day["condition"]["code"])).resize((day_size, day_size))
icon = Image.open(os.path.join(config.icons_dir, WeatherAPI.get_icon(day["condition"]["code"]))).resize((day_size, day_size))
image.paste(icon, (0, i * day_size), icon)
draw.text(