Compare commits

..

No commits in common. "042df5efc2922e576058b926dd1392035443792b" and "4575584b9d670dc75b5649589284d81955a1e2a3" have entirely different histories.

6 changed files with 12 additions and 200 deletions

3
.gitignore vendored
View File

@ -1,2 +1 @@
__pycache__ __pycache__
calendar_url.txt

View File

@ -14,23 +14,6 @@ pip install python-escpos[all] --user
pip install chess pip install chess
``` ```
### Tasks from Google Calendar
```
pip install requests icalendar recurring-ical-events pytz
```
You need to specify the calendar URL by pasting it into `calendar_url.txt` in this project directory.
> To find the secret iCal URL for your Google Calendar, follow these steps:
>
> Open Google Calendar in your web browser.
> In the top right, click the Settings (gear icon) > Settings.
> On the left sidebar, under "Settings for my calendars", click the name of the calendar you want to use.
> Scroll down to the "Integrate calendar" section.
> Look for the field "Secret address in iCal format".
> Copy this URL (it should end in .ics).
## Config ## Config

View File

@ -5,7 +5,7 @@ from jobs.czech_words import CZECH_WORDS
class DivisionCipherJob(Job): class DivisionCipherJob(Job):
def __init__(self): def __init__(self):
self.user_phrase = None self.secret = "TAJENKA"
def get_name(self): def get_name(self):
return "TAJENKA DELENIM" return "TAJENKA DELENIM"
@ -13,20 +13,21 @@ class DivisionCipherJob(Job):
def configure(self): def configure(self):
print("\n--- Configure Division Cipher ---") print("\n--- Configure Division Cipher ---")
phrase = input("Enter secret phrase (default: Random): ").strip().upper() phrase = input("Enter secret phrase (default: Random): ").strip().upper()
self.user_phrase = phrase if phrase else None
raw_secret = phrase if phrase else random.choice(CZECH_WORDS)
def print_body(self, p):
raw_secret = self.user_phrase if self.user_phrase else random.choice(CZECH_WORDS)
# Remove accents to ensure mapping to A-Z works # Remove accents to ensure mapping to A-Z works
nfkd_form = unicodedata.normalize('NFKD', raw_secret) nfkd_form = unicodedata.normalize('NFKD', raw_secret)
only_ascii = "".join([c for c in nfkd_form if not unicodedata.combining(c)]) only_ascii = "".join([c for c in nfkd_form if not unicodedata.combining(c)])
# Keep only A-Z # Keep only A-Z
secret = "".join([c for c in only_ascii.upper() if 'A' <= c <= 'Z']) self.secret = "".join([c for c in only_ascii.upper() if 'A' <= c <= 'Z'])
if not self.secret:
self.secret = "TAJENKA"
if not secret: def print_body(self, p):
secret = "TAJENKA" secret = self.secret
p.text("Vylusti tajenku!\n") p.text("Vylusti tajenku!\n")
p.text("Vysledek deleni je poradi pismena\n") p.text("Vysledek deleni je poradi pismena\n")

View File

@ -1,131 +0,0 @@
import datetime
import os.path
from .base import Job
# Wrap imports to prevent crashing if dependencies are missing
try:
import requests
import icalendar
import recurring_ical_events
import pytz
HAS_ICAL_DEPS = True
except ImportError:
HAS_ICAL_DEPS = False
class TasksJob(Job):
def __init__(self):
self.days_to_print = 1
def get_name(self):
return "UKOLY DNE"
def configure(self):
if not os.path.exists('calendar_url.txt'):
print("\n--- Configure Calendar URL ---")
print("To find your Google Calendar URL:")
print("1. Go to Settings > Select Calendar > Integrate calendar")
print("2. Copy 'Secret address in iCal format'")
print("-" * 30)
print("Enter the public or secret address in iCal format (.ics).")
print("Example: https://calendar.google.com/calendar/ical/.../basic.ics")
url = input("URL: ").strip()
if url:
with open('calendar_url.txt', 'w') as f:
f.write(url)
print("URL saved.")
else:
print("\nCalendar URL is already configured (delete calendar_url.txt to reset).")
print("-" * 30)
try:
d_input = input(f"Number of days to print [{self.days_to_print}]: ").strip()
if d_input:
self.days_to_print = int(d_input)
except ValueError:
pass
def print_body(self, p):
if not HAS_ICAL_DEPS:
print("Error: Missing iCal Libraries.")
p.text("Error: Missing iCal Libraries.\n")
p.text("Run: pip install requests icalendar recurring-ical-events pytz\n")
return
if not os.path.exists('calendar_url.txt'):
print("Error: Calendar URL not configured.")
p.text("Error: Calendar URL not configured.\n")
p.text("Run configuration in TUI first.\n")
return
with open('calendar_url.txt', 'r') as f:
url = f.read().strip()
try:
# 1. Fetch the .ics file
# Timeout is important so the printer doesn't hang forever
response = requests.get(url, timeout=30)
response.raise_for_status()
# 2. Parse Calendar
cal = icalendar.Calendar.from_ical(response.content)
# 3. Loop over days
base_now = datetime.datetime.now().astimezone()
for i in range(self.days_to_print):
p.cut()
target_date = base_now + datetime.timedelta(days=i)
# Print Calendar Name
cal_name = cal.get('X-WR-CALNAME')
if cal_name:
p.set(align='center', bold=True)
p.text(f"{str(cal_name)}\n")
days_cz = ["Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"]
p.text(f"{days_cz[target_date.weekday()]} {target_date.strftime('%d.%m.%Y')}\n")
p.set(align='left', bold=False)
p.text("-" * 32 + "\n")
start_of_day = target_date.replace(hour=0, minute=0, second=0, microsecond=0)
end_of_day = target_date.replace(hour=23, minute=59, second=59, microsecond=0)
# 4. Expand Recurring Events
events = recurring_ical_events.of(cal).between(start_of_day, end_of_day)
# 5. Sort by start time
def get_start_time(e):
dt = e.get('DTSTART').dt
if not isinstance(dt, datetime.datetime):
return datetime.datetime.combine(dt, datetime.time.min).replace(tzinfo=base_now.tzinfo)
return dt
events.sort(key=get_start_time)
if not events:
p.text("Zadne ukoly.\n")
else:
for event in events:
summary = str(event.get('SUMMARY', '(bez nazvu)'))
dtstart = event.get('DTSTART').dt
if not isinstance(dtstart, datetime.datetime):
time_str = "Cely den"
else:
local_dt = dtstart.astimezone(base_now.tzinfo)
time_str = local_dt.strftime('%H:%M')
p.set(bold=True)
p.text(f"{time_str} [_]")
p.set(bold=False)
p.text(f" {summary}\n")
location = event.get('LOCATION')
if location:
p.text(f" @ {str(location)}\n")
p.text("-" * 32 + "\n")
except Exception as e:
print(f"Error: {e}")
p.text(f"Error: {e}\n")

View File

@ -11,7 +11,6 @@ from jobs.joke import JokeJob
from jobs.maze_multitarget import MazeMultitargetJob from jobs.maze_multitarget import MazeMultitargetJob
from jobs.flush import FlushJob from jobs.flush import FlushJob
from jobs.word_search import WordSearchJob from jobs.word_search import WordSearchJob
from jobs.tasks import TasksJob
# ========================================== # ==========================================
# CONFIGURATION # CONFIGURATION
@ -61,7 +60,6 @@ JOBS = [
MathHomeworkJob(), MathHomeworkJob(),
UnitConversionJob(), UnitConversionJob(),
ChessPuzzleJob(), ChessPuzzleJob(),
TasksJob(),
MazeJob(), MazeJob(),
DivisionCipherJob(), DivisionCipherJob(),
DecimalDivisionJob(), DecimalDivisionJob(),
@ -117,8 +115,6 @@ def run_tui():
if copies > 1: if copies > 1:
print(f" Printing copy {i + 1}...") print(f" Printing copy {i + 1}...")
job.run(p) job.run(p)
time.sleep(0.5)
# If using Dummy, print the output to console to verify # If using Dummy, print the output to console to verify
if isinstance(p, Dummy): if isinstance(p, Dummy):

View File

@ -1,36 +0,0 @@
#!/usr/bin/env python3
import time
import argparse
from print_server import get_printer
from jobs.tasks import TasksJob
def main():
parser = argparse.ArgumentParser(description="Print daily tasks schedule.")
parser.add_argument("--days", type=int, default=1, help="Number of days to print (default: 1)")
args = parser.parse_args()
print("Initializing printer...")
p = get_printer()
if not p:
print("Failed to connect to printer.")
return
print(f"Fetching and printing tasks for {args.days} day(s)...")
job = TasksJob()
job.days_to_print = args.days
try:
# Run the job
job.run(p)
print("Done.")
except Exception as e:
print(f"Error during print job: {e}")
finally:
# Ensure connection is closed cleanly
if hasattr(p, 'close'):
time.sleep(0.5)
p.close()
if __name__ == "__main__":
print(" == Tasks Printer ==")
main()