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 FROM alpine:3
ENV MUSL_LOCPATH="/usr/share/i18n/locales/musl"
ENTRYPOINT ["python", "/srv/e-paper/main.py"] ENTRYPOINT ["python", "/srv/e-paper/main.py"]
WORKDIR /srv/e-paper WORKDIR /srv/e-paper
VOLUME /data 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-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 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 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: if NEXT_STOP_Y + occuped_space + mod.height > 580 or mod.height > 260:
image.paste(mod, (0, 640-mod.height), mod) image.paste(mod, (0, 640-mod.height), mod)
elif mod.height < 100: elif mod.height < 100:

View File

@ -1,12 +1,16 @@
import os import os
import os.path
import logging import logging
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
import sys
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
class Config: class Config:
def __init__(self, cache_timeout, max_cache_timeout, cals_file_list=".cals"): 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.cache_timeout = cache_timeout
self.max_cache_timeout = max_cache_timeout self.max_cache_timeout = max_cache_timeout
@ -94,7 +98,8 @@ class RuleModule:
class AlertsModule: class AlertsModule:
def __init__(self, alerts=[], ignore_module=[]): def __init__(self, config, alerts=[], ignore_module=[]):
self._config = config
self.icon_size = 50 self.icon_size = 50
self.alerts = alerts self.alerts = alerts
self.ignore_module = ignore_module 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)) image.paste(icon_img, (int(self.icon_size / 2 - font_size*self.icon_size/32), align))
else: else:
color_img = Image.new('RGB', (self.icon_size, self.icon_size), "#fff") 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) image.paste(color_img, (0, align - 5), icon_img)
if "title" in alert: if "title" in alert:

View File

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

View File

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

View File

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