Config scripts, webdav access initial work, some other improvements
This commit is contained in:
parent
397a096608
commit
04c22c513b
5 changed files with 131 additions and 191 deletions
|
@ -11,6 +11,10 @@ config = {
|
|||
"PRINTER_USB_ID": "",
|
||||
"PRINTER_INTERFACE": 0,
|
||||
"PRINTER_ENDPOINT": 0x01,
|
||||
"WEBDAV_USER": "",
|
||||
"WEBDAV_PASSWORD": "",
|
||||
"WEBDAV_SERVER": "",
|
||||
"CALENDAR_PATH": "",
|
||||
}
|
||||
|
||||
|
||||
|
|
183
gui.py
183
gui.py
|
@ -1,183 +0,0 @@
|
|||
# Python imports
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
# Gtk and Gobject
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, Gio
|
||||
|
||||
# Internationalization support
|
||||
import gettext
|
||||
import locale
|
||||
|
||||
# Printing library import
|
||||
import smallprint
|
||||
|
||||
|
||||
if os.path.exists('locale/po') and os.path.exists('res'):
|
||||
# We're in the development tree
|
||||
DIR = "locale/po/"
|
||||
RESOURCES = "res/"
|
||||
|
||||
else:
|
||||
DIR = "po"
|
||||
RESOURCES = "res/"
|
||||
|
||||
# Internationalization code, we'll cross that bridge when we get there
|
||||
# APP = "smallprint"
|
||||
#
|
||||
#
|
||||
# locale.setlocale(locale.LC_ALL, '')
|
||||
#
|
||||
# gettext.bindtextdomain(APP, DIR)
|
||||
# locale.bindtextdomain(APP, DIR)
|
||||
#
|
||||
#
|
||||
# gettext.textdomain(APP)
|
||||
# _ = gettext.gettext
|
||||
#
|
||||
|
||||
|
||||
class MainWindowMethods(Gtk.Application):
|
||||
"""
|
||||
Main Application object with the main window signals
|
||||
"""
|
||||
def __init__(self):
|
||||
Gtk.Application.__init__(self, application_id="apps.gnome.smallprint",
|
||||
flags=Gio.ApplicationFlags.FLAGS_NONE)
|
||||
|
||||
self.connect("activate", self.on_app_start)
|
||||
|
||||
def on_app_start(self, data=None):
|
||||
"""
|
||||
Loads the MainWindow widgets, shows it up and starts the main loop
|
||||
"""
|
||||
self.builder = Gtk.Builder()
|
||||
# self.builder.set_translation_domain(APP)
|
||||
self.builder.add_from_file(os.path.join(RESOURCES, 'smallprint.gtkbuilder'))
|
||||
self.builder.connect_signals(self)
|
||||
|
||||
# We get the window and show it
|
||||
self.window = self.builder.get_object("MainWindow")
|
||||
self.add_window(self.window)
|
||||
self.window.show_all()
|
||||
|
||||
def onOpenMenuClicked(self, event):
|
||||
"""
|
||||
User has pressed Open in the menu
|
||||
"""
|
||||
# Create the FileChooser Dialog
|
||||
chooser = Gtk.FileChooserDialog(_("Open JSON text file"), self.window,
|
||||
Gtk.FileChooserAction.OPEN,
|
||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
||||
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
|
||||
|
||||
# Launch it
|
||||
response = chooser.run()
|
||||
|
||||
# If we choose a file, we load it
|
||||
if response == Gtk.ResponseType.OK:
|
||||
filename = chooser.get_filename()
|
||||
label = self.builder.get_object("StatusLabel")
|
||||
|
||||
# We update the statusbar accordingly to what has happened
|
||||
if self.logicObj.loadjson(filename):
|
||||
|
||||
label.set_text(filename)
|
||||
treeStore = self.builder.get_object("treestore1")
|
||||
treeStore.clear()
|
||||
self.logicObj.loadTree(treeStore)
|
||||
|
||||
else:
|
||||
|
||||
label.set_text(_("No JSON loaded."))
|
||||
|
||||
# We finish the dialog
|
||||
chooser.destroy()
|
||||
|
||||
def onCopyJSONClicked(self, widget):
|
||||
"""
|
||||
User asked to paste a JSON code
|
||||
"""
|
||||
# Show up the TextWindow
|
||||
textWindow = self.builder.get_object("TextWindow")
|
||||
textWindow.show_all()
|
||||
|
||||
def onCopyJSONDelete(self, widget, event):
|
||||
"""
|
||||
We've been told to close the CopyJSON Window
|
||||
"""
|
||||
textWindow = self.builder.get_object("TextWindow")
|
||||
textWindow.hide()
|
||||
|
||||
return True
|
||||
|
||||
def onCopyJSONDestroy(self, widget):
|
||||
"""
|
||||
We've been tasked with removing the CopyJSON window
|
||||
"""
|
||||
textWindow = self.builder.get_object("TextWindow")
|
||||
textWindow.hide()
|
||||
|
||||
return True
|
||||
|
||||
def onCopyJSONAcceptClicked(self, widget):
|
||||
"""
|
||||
The input is finished and accepted.
|
||||
"""
|
||||
textView = self.builder.get_object("textview1")
|
||||
jsonBuffer = textView.get_buffer()
|
||||
jsonText = jsonBuffer.get_text(jsonBuffer.get_start_iter(),
|
||||
jsonBuffer.get_end_iter(), True)
|
||||
|
||||
textWindow = self.builder.get_object("TextWindow")
|
||||
textWindow.hide()
|
||||
treestore = self.builder.get_object("treestore1")
|
||||
treestore.clear()
|
||||
|
||||
if self.logicObj.loadJSONText(jsonText):
|
||||
|
||||
status_label = self.builder.get_object("StatusLabel")
|
||||
status_label.set_text(_("Loaded from the clipboard."))
|
||||
self.logicObj.loadTree(treestore)
|
||||
|
||||
def onCopyJSONCancelClicked(self, widget):
|
||||
"""
|
||||
The user changed its mind and pressed cancel
|
||||
"""
|
||||
textWindow = self.builder.get_object("TextWindow")
|
||||
textWindow.hide()
|
||||
|
||||
def onExitMenuClicked(self, widget):
|
||||
"""
|
||||
Menu option Exit has been clicked
|
||||
"""
|
||||
self.quit()
|
||||
|
||||
def onAboutMenuActivate(self, widget):
|
||||
"""
|
||||
About option clicked
|
||||
"""
|
||||
about_dialog = self.builder.get_object("AboutDialog")
|
||||
about_dialog.run()
|
||||
about_dialog.hide()
|
||||
|
||||
def onMainWindowDelete(self, widget, event):
|
||||
"""
|
||||
Our MainWindow has been deleted or closed
|
||||
"""
|
||||
pass
|
||||
|
||||
def onAboutDialogClose(self, widget, event=None):
|
||||
pass
|
||||
|
||||
def onAboutDialogDeleteEvent(self, widget, event=None):
|
||||
pass
|
||||
|
||||
|
||||
# Main procedure
|
||||
if __name__ == "__main__":
|
||||
|
||||
mainWindow = MainWindowMethods()
|
||||
mainWindow.run(None)
|
|
@ -8,7 +8,6 @@ ignition-gemini==0.1.7
|
|||
importlib-metadata==1.7.0
|
||||
Pillow==7.2.0
|
||||
pycairo==1.19.1
|
||||
PyGObject==3.38.0
|
||||
pyserial==3.4
|
||||
python-escpos==2.2.0
|
||||
pyusb==1.0.2
|
||||
|
|
|
@ -99,11 +99,19 @@ def print_weather(printer, city=None):
|
|||
printer.text(f"{description}\n\n")
|
||||
icon_code = weather['weather'][0]['icon']
|
||||
|
||||
if not os.path.exists(f"icons/weather/{icon_code}.png"):
|
||||
icon_path = "icons/weather/any.png"
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__)) # Get this file's current directory
|
||||
|
||||
if not os.path.exists(os.path.join(dir_path, "icons/weather")):
|
||||
dir_path = "/usr/share/smallprint/icons/weather"
|
||||
|
||||
else:
|
||||
icon_path = f"icons/weather/{icon_code}.png"
|
||||
dir_path = os.path.join(dir_path, "icons/weather")
|
||||
|
||||
if not os.path.exists(os.path.join(dir_path, f"{icon_code}.png")):
|
||||
icon_path = os.path.join(dir_path, "any.png")
|
||||
|
||||
else:
|
||||
icon_path = os.path.join(dir_path, f"{icon_code}.png")
|
||||
|
||||
# TODO: The image impl should be an option
|
||||
printer.image(icon_path,
|
||||
|
@ -223,7 +231,7 @@ def print_rss(printer, link, news=3):
|
|||
"""
|
||||
reset_defaults(printer)
|
||||
feed = feedparser.parse(link)
|
||||
title = feed["channel"]["title"]
|
||||
title = feed["channel"].get("title", link)[:16]
|
||||
|
||||
printer.set(align="center",
|
||||
text_type="BU",
|
||||
|
@ -241,14 +249,17 @@ def _print_rss_item(item):
|
|||
title = item["title"]
|
||||
date = item["published"]
|
||||
text = clear_html(item["summary"])
|
||||
if len(text) > 255:
|
||||
# Limit the text output in certain "summaries"
|
||||
text = text[:252] + "...\n"
|
||||
link = item["link"]
|
||||
|
||||
printer.set(align="left",
|
||||
printer.set(align="center",
|
||||
text_type="BU",
|
||||
smooth=True)
|
||||
printer.text(f"{title}\n")
|
||||
reset_defaults(printer)
|
||||
printer.set(align="right",
|
||||
printer.set(align="left",
|
||||
font="b")
|
||||
printer.text(f"{date}\n\n")
|
||||
printer.text(text)
|
||||
|
@ -324,6 +335,44 @@ def print_image(printer, image):
|
|||
os.remove("temp.png")
|
||||
|
||||
|
||||
def printing_script(printer):
|
||||
"""
|
||||
Gets the configuration and parses its script
|
||||
"""
|
||||
script = config.get("SCRIPT")
|
||||
|
||||
if not script:
|
||||
logger.error("No script in config file")
|
||||
return
|
||||
|
||||
for command in script:
|
||||
key = list(command)[0]
|
||||
value = command[key]
|
||||
if key == 'WEATHER':
|
||||
print_weather(printer, city=value)
|
||||
|
||||
if key == 'RSS':
|
||||
print_rss(printer, value)
|
||||
|
||||
if key == 'GEMINI':
|
||||
print_gemini(printer, value)
|
||||
|
||||
if key == 'FILE':
|
||||
print_file(printer, value)
|
||||
|
||||
if key == 'IMAGE':
|
||||
print_image(printer, value)
|
||||
|
||||
if key == 'TEXT':
|
||||
print_text(printer, value)
|
||||
|
||||
printer.set(align="center",
|
||||
text_type="NORMAL",
|
||||
font="b",
|
||||
smooth=True)
|
||||
printer.text("-----\n")
|
||||
|
||||
|
||||
def clear_html(text):
|
||||
cleanr = re.compile('<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});')
|
||||
cleantext = re.sub(cleanr, '', text)
|
||||
|
@ -355,25 +404,39 @@ if __name__ == "__main__":
|
|||
|
||||
generate_qr = args.genqr
|
||||
|
||||
ops_called = 0
|
||||
|
||||
if args.text:
|
||||
ops_called += 1
|
||||
print_text(printer, args.text[0])
|
||||
printer.text("\n\n")
|
||||
|
||||
if args.file:
|
||||
ops_called += 1
|
||||
print_file(printer, args.file)
|
||||
printer.text("\n\n")
|
||||
|
||||
if args.weather:
|
||||
print_weather(printer)
|
||||
ops_called += 1
|
||||
print_weather(printer, args.weather)
|
||||
printer.text("\n\n")
|
||||
|
||||
if args.gemini:
|
||||
ops_called += 1
|
||||
print_gemini(printer, args.gemini)
|
||||
printer.text("\n\n")
|
||||
|
||||
if args.news:
|
||||
ops_called += 1
|
||||
print_rss(printer, args.news)
|
||||
|
||||
if args.image:
|
||||
ops_called += 1
|
||||
print_image(printer, args.image[0])
|
||||
printer.text("\n\n")
|
||||
|
||||
# In case we get called (almost) empty
|
||||
if ops_called == 0:
|
||||
# Try to parse a config script
|
||||
printing_script(printer)
|
||||
printer.text("\n\n")
|
||||
|
|
57
webdav.py
Normal file
57
webdav.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
from icalendar import Calendar, Event
|
||||
from webdav3.client import Client as WDClient
|
||||
|
||||
|
||||
class Client:
|
||||
def __init__(self, config):
|
||||
"""
|
||||
Initializes a client
|
||||
"""
|
||||
options = {
|
||||
'webdav_hostname': config["WEBDAV_SERVER"],
|
||||
'webdav_login': config["WEBDAV_USER"],
|
||||
'webdav_password': config["WEBDAV_PASSWORD"],
|
||||
}
|
||||
self.calendar_path = config["CALENDAR_PATH"]
|
||||
self.client = WDClient(options)
|
||||
|
||||
def retrieve_calendars_list(self):
|
||||
"""
|
||||
Retrieves the calendar list
|
||||
"""
|
||||
return self.client.list(self.path)
|
||||
|
||||
def read_calendar(self, pathname):
|
||||
"""
|
||||
Given a filename, tries to read the calendar event
|
||||
"""
|
||||
f, temp_path = tempfile.mkstemp()
|
||||
rpath = os.path.join(self.calendar_path, pathname)
|
||||
self.client.download_sync(remote_path=rpath,
|
||||
local_path=temp_path)
|
||||
# Read the temporary data, close the file, remove it
|
||||
data = f.read()
|
||||
f.close()
|
||||
os.remove(temp_path)
|
||||
# Now with the data read, we can process it
|
||||
return self.parse_calendar(data)
|
||||
|
||||
def parse_calendar(self, data):
|
||||
"""
|
||||
Parses ICS calendar data received
|
||||
"""
|
||||
calendar = Calendar.from_ical(data)
|
||||
for component in calendar.walk():
|
||||
if component.name == 'VEVENT':
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def get_todays_events(self):
|
||||
"""
|
||||
Get todays events
|
||||
"""
|
||||
pass
|
Loading…
Reference in a new issue