files: Updates to not cache thumbnails locally. Also get notified by inotify
This commit is contained in:
parent
f8ca339de5
commit
bd1650fd18
@ -3,7 +3,7 @@ import gi
|
||||
import logging
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, Gdk, GdkPixbuf, GLib, Pango
|
||||
from gi.repository import Gtk, Gdk, GdkPixbuf, Gio, GLib, Pango
|
||||
import os
|
||||
klipperscreendir = os.getcwd()
|
||||
|
||||
@ -13,7 +13,8 @@ class KlippyGtk:
|
||||
width_ratio = 16
|
||||
height_ratio = 9.375
|
||||
|
||||
def __init__(self, width, height):
|
||||
def __init__(self, screen, width, height):
|
||||
self.screen = screen
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
@ -98,6 +99,16 @@ class KlippyGtk:
|
||||
|
||||
return pixbuf
|
||||
|
||||
def PixbufFromHttp(self, resource, style=False, width_scale=1, height_scale=1):
|
||||
response = self.screen.apiclient.get_thumbnail_stream(resource)
|
||||
if response == False:
|
||||
return None
|
||||
stream = Gio.MemoryInputStream.new_from_data(response, None)
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, int(round(self.img_width * width_scale)),
|
||||
int(round(self.img_height * height_scale)), True)
|
||||
|
||||
return pixbuf
|
||||
|
||||
def ProgressBar(self, style=False):
|
||||
bar = Gtk.ProgressBar()
|
||||
|
||||
|
@ -20,6 +20,14 @@ class KlippyRest:
|
||||
def get_printer_info(self):
|
||||
return self.send_request("printer/info")
|
||||
|
||||
def get_thumbnail_stream(self, thumbnail):
|
||||
url = "http://%s:%s/server/files/gcodes/%s" % (self.ip, self.port, thumbnail)
|
||||
response = requests.get(url, stream=True)
|
||||
if response.status_code == 200:
|
||||
response.raw.decode_content = True
|
||||
return response.content
|
||||
return False
|
||||
|
||||
def send_request(self, method):
|
||||
url = "http://%s:%s/%s" % (self.ip, self.port, method)
|
||||
logging.debug("Sending request to %s" % url)
|
||||
|
@ -22,6 +22,16 @@ class KlippyFiles():
|
||||
if not os.path.exists(self.thumbnail_dir):
|
||||
os.makedirs(self.thumbnail_dir)
|
||||
|
||||
self.gcodes_path = None
|
||||
|
||||
def initialize(self):
|
||||
self.gcodes_path = None
|
||||
if "virtual_sdcard" in self._screen.printer.get_config_section_list():
|
||||
vsd = self._screen.printer.get_config_section("virtual_sdcard")
|
||||
if "path" in vsd:
|
||||
self.gcodes_path = vsd['path']
|
||||
logging.info("Gcodes path: %s" % self.gcodes_path)
|
||||
|
||||
def _callback(self, result, method, params):
|
||||
if method == "server.files.list":
|
||||
if "result" in result and isinstance(result['result'],list):
|
||||
@ -32,44 +42,57 @@ class KlippyFiles():
|
||||
deletedfiles.remove(item['filename'])
|
||||
else:
|
||||
newfiles.append(item['filename'])
|
||||
#logging.debug("New file: %s", item['filename'])
|
||||
self.filelist.append(item['filename'])
|
||||
self.files[item['filename']] = {
|
||||
"size": item['size'],
|
||||
"modified": item['modified']
|
||||
}
|
||||
self.request_metadata(item['filename'])
|
||||
self.add_file(item, False)
|
||||
|
||||
if len(self.callbacks) > 0 and (len(newfiles) > 0 or len(deletedfiles) > 0):
|
||||
for cb in self.callbacks:
|
||||
cb(newfiles, deletedfiles, [])
|
||||
if len(newfiles) > 0 or len(deletedfiles) > 0:
|
||||
self.run_callbacks(newfiles, deletedfiles)
|
||||
|
||||
if len(deletedfiles) > 0:
|
||||
#logging.debug("Deleted files: %s", deletedfiles)
|
||||
for file in deletedfiles:
|
||||
self.filelist.remove(file)
|
||||
self.files.pop(file, None)
|
||||
self.remove_file(file)
|
||||
|
||||
elif method == "server.files.metadata":
|
||||
if "error" in result.keys():
|
||||
logging.debug("Error in getting metadata for %s. Retrying in 6 seconds" %(params['filename']))
|
||||
return
|
||||
|
||||
#logging.debug("Got metadata for %s" % (result['result']['filename']))
|
||||
|
||||
for x in result['result']:
|
||||
self.files[params['filename']][x] = result['result'][x]
|
||||
if "thumbnails" in self.files[params['filename']]:
|
||||
self.files[params['filename']]['thumbnails'].sort(key=lambda x: x['size'], reverse=True)
|
||||
|
||||
for thumbnail in self.files[params['filename']]['thumbnails']:
|
||||
f = open("%s/%s-%s" % (self.thumbnail_dir, params['filename'].split('/')[-1], thumbnail['size']),
|
||||
"wb")
|
||||
f.write(base64.b64decode(thumbnail['data']))
|
||||
f.close()
|
||||
for cb in self.callbacks:
|
||||
logging.debug("Running metadata callbacks")
|
||||
cb([], [], [params['filename']])
|
||||
thumbnail['local'] = False
|
||||
if self.gcodes_path != None:
|
||||
fpath = os.path.join(self.gcodes_path, params['filename'])
|
||||
fdir = os.path.dirname(fpath)
|
||||
path = os.path.join(fdir, thumbnail['relative_path'])
|
||||
if os.access(path, os.R_OK):
|
||||
thumbnail['local'] = True
|
||||
thumbnail['path'] = path
|
||||
if thumbnail['local'] == False:
|
||||
fdir = os.path.dirname(params['filename'])
|
||||
thumbnail['path'] = os.path.join(fdir, thumbnail['relative_path'])
|
||||
self.run_callbacks(mods=[params['filename']])
|
||||
|
||||
def add_file(self, item, notify=True):
|
||||
if 'filename' not in item and 'path' not in item:
|
||||
logging.info("Error adding item, unknown filename or path: %s" % item)
|
||||
return
|
||||
|
||||
filename = item['path'] if "path" in item else item['filename']
|
||||
if filename in self.filelist:
|
||||
logging.info("File already exists: %s" % filename)
|
||||
return
|
||||
|
||||
self.filelist.append(filename)
|
||||
self.files[filename] = {
|
||||
"size": item['size'],
|
||||
"modified": item['modified']
|
||||
}
|
||||
self.request_metadata(filename)
|
||||
if notify == True:
|
||||
self.run_callbacks(newfiles=[filename])
|
||||
|
||||
def add_file_callback(self, callback):
|
||||
try:
|
||||
@ -77,6 +100,19 @@ class KlippyFiles():
|
||||
except:
|
||||
logging.debug("Callback not found: %s" % callback)
|
||||
|
||||
def process_update(self, data):
|
||||
if 'item' in data and data['item']['root'] != 'gcodes':
|
||||
return
|
||||
|
||||
if data['action'] == "create_file":
|
||||
self.add_file(data['item'])
|
||||
elif data['action'] == "delete_file":
|
||||
self.remove_file(data['item']['path'])
|
||||
elif data['action'] == "move_file":
|
||||
self.add_file(data['item'], False)
|
||||
self.remove_file(data['source_item']['path'], False)
|
||||
self.run_callbacks(newfiles=[data['item']['path']], deletedfiles=[data['source_item']['path']])
|
||||
|
||||
def remove_file_callback(self, callback):
|
||||
if callback in self.callbacks:
|
||||
self.callbacks.pop(self.callbacks.index(callback))
|
||||
@ -94,7 +130,11 @@ class KlippyFiles():
|
||||
def get_thumbnail_location(self, filename):
|
||||
if not self.has_thumbnail(filename):
|
||||
return None
|
||||
return "%s/%s-%s" % (self.thumbnail_dir, filename.split('/')[-1], self.files[filename]['thumbnails'][0]['size'])
|
||||
|
||||
thumb = self.files[filename]['thumbnails'][0]
|
||||
if thumb['local'] == False:
|
||||
return ['http', thumb['path']]
|
||||
return ['file', thumb['path']]
|
||||
|
||||
def has_thumbnail(self, filename):
|
||||
if filename not in self.files:
|
||||
@ -109,18 +149,32 @@ class KlippyFiles():
|
||||
def refresh_files(self):
|
||||
self._screen._ws.klippy.get_file_list(self._callback)
|
||||
|
||||
def remove_file(self, filename, notify=True):
|
||||
if filename not in self.filelist:
|
||||
return
|
||||
|
||||
self.filelist.remove(filename)
|
||||
self.files.pop(filename, None)
|
||||
|
||||
if notify == True:
|
||||
self.run_callbacks(deletedfiles=[filename])
|
||||
|
||||
def ret_file_data (self, filename):
|
||||
print("Getting file info for %s" % (filename))
|
||||
self._screen._ws.klippy.get_file_metadata(filename, self._callback)
|
||||
|
||||
def run_callbacks(self, newfiles=[], deletedfiles=[], mods=[]):
|
||||
if len(self.callbacks) <= 0:
|
||||
return
|
||||
|
||||
for cb in self.callbacks:
|
||||
GLib.idle_add(cb, newfiles, deletedfiles, mods)
|
||||
|
||||
def get_file_list(self):
|
||||
return self.filelist
|
||||
|
||||
def get_file_info(self, filename):
|
||||
if filename not in self.files:
|
||||
return None
|
||||
return {"path":None,"modified":0,"size":0}
|
||||
|
||||
return self.files[filename]
|
||||
|
||||
def add_file(self, file_name, size, modified, old_file_name = None):
|
||||
print(file_name)
|
||||
|
@ -100,7 +100,15 @@ class ScreenPanel:
|
||||
def get_file_image(self, filename, width=1.6, height=1.6):
|
||||
if not self._files.has_thumbnail(filename):
|
||||
return None
|
||||
return self._gtk.PixbufFromFile(self._files.get_thumbnail_location(filename), None, width, height)
|
||||
|
||||
loc = self._files.get_thumbnail_location(filename)
|
||||
if loc == None:
|
||||
return None
|
||||
if loc[0] == "file":
|
||||
return self._gtk.PixbufFromFile(loc[1], None, width, height)
|
||||
if loc[0] == "http":
|
||||
return self._gtk.PixbufFromHttp(loc[1], None, width, height)
|
||||
return None
|
||||
|
||||
def home(self, widget):
|
||||
self._screen._ws.klippy.gcode_script(KlippyGcodes.HOME)
|
||||
|
@ -394,8 +394,9 @@ class PrintPanel(ScreenPanel):
|
||||
for child in self.dir_panels[dirpan].get_children():
|
||||
self.dir_panels[dirpan].remove(child)
|
||||
|
||||
for file in self._screen.files.get_file_list():
|
||||
self.add_file(file)
|
||||
flist = sorted(self._screen.files.get_file_list(), key=lambda item: '/' in item)
|
||||
for file in flist:
|
||||
GLib.idle_add(self.add_file, file)
|
||||
|
||||
def update_file(self, filename):
|
||||
if filename not in self.labels['files']:
|
||||
|
12
screen.py
12
screen.py
@ -109,7 +109,7 @@ class KlipperScreen(Gtk.Window):
|
||||
self.set_resizable(False)
|
||||
logging.info("Screen resolution: %sx%s" % (self.width, self.height))
|
||||
|
||||
self.gtk = KlippyGtk(self.width, self.height)
|
||||
self.gtk = KlippyGtk(self, self.width, self.height)
|
||||
self.init_style()
|
||||
|
||||
self.printer_initializing(_("Initializing"))
|
||||
@ -586,7 +586,8 @@ class KlipperScreen(Gtk.Window):
|
||||
self.printer.process_update(data)
|
||||
elif action == "notify_filelist_changed":
|
||||
logging.debug("Filelist changed: %s", json.dumps(data,indent=2))
|
||||
#self.files.add_file()
|
||||
if self.files != None:
|
||||
self.files.process_update(data)
|
||||
elif action == "notify_metadata_update":
|
||||
self.files.request_metadata(data['filename'])
|
||||
elif action == "notify_power_changed":
|
||||
@ -652,7 +653,13 @@ class KlipperScreen(Gtk.Window):
|
||||
_ = self.lang.gettext
|
||||
|
||||
printer_info = self.apiclient.get_printer_info()
|
||||
if printer_info == False:
|
||||
logging.info("Unable to get printer info from moonraker")
|
||||
return False
|
||||
data = self.apiclient.send_request("printer/objects/query?" + "&".join(PRINTER_BASE_STATUS_OBJECTS))
|
||||
if data == False:
|
||||
logging.info("Error getting printer object data")
|
||||
return False
|
||||
powerdevs = self.apiclient.send_request("machine/device_power/devices")
|
||||
data = data['result']['status']
|
||||
|
||||
@ -660,6 +667,7 @@ class KlipperScreen(Gtk.Window):
|
||||
self.printer.reinit(printer_info['result'], data)
|
||||
self.ws_subscribe()
|
||||
|
||||
self.files.initialize()
|
||||
self.files.refresh_files()
|
||||
|
||||
if powerdevs != False:
|
||||
|
Loading…
x
Reference in New Issue
Block a user