import logging import os import gi gi.require_version("Gtk", "3.0") class KlippyFiles: def __init__(self, screen): self._screen = screen self.callbacks = [] self.files = {} self.directories = [] self.gcodes_path = None def set_gcodes_path(self): virtual_sdcard = self._screen.printer.get_config_section("virtual_sdcard") if virtual_sdcard and "path" in virtual_sdcard: self.gcodes_path = os.path.expanduser(virtual_sdcard['path']) logging.info(f"Gcodes path: {self.gcodes_path}") def _callback(self, result, method, params): if "error" in result: logging.debug(result["error"]) return if method == "server.files.list": for item in result["result"]: self.files[item["path"]] = item self.request_metadata(item["path"]) elif method == "server.files.metadata": for x in result['result']: if params['filename'] not in self.files: self.files[params['filename']] = {} self.files[params['filename']][x] = result['result'][x] if 'path' not in self.files[params['filename']]: self.files[params['filename']]['path'] = params['filename'] if "thumbnails" in self.files[params['filename']]: self.files[params['filename']]['thumbnails'].sort(key=lambda y: y['size'], reverse=True) for thumbnail in self.files[params['filename']]['thumbnails']: thumbnail['local'] = False if self.gcodes_path is not None: path = os.path.join( os.path.dirname(os.path.join(self.gcodes_path, params['filename'])), thumbnail['relative_path'] ) if os.access(path, os.R_OK): thumbnail['local'] = True thumbnail['path'] = path if thumbnail['local'] is False: thumbnail['path'] = os.path.join( os.path.dirname(params['filename']), thumbnail['relative_path'] ) self._screen.process_update("notify_metadata_update", params) self.run_callbacks( "modify_file", {'action': "modify_file", 'item': self.files[params['filename']]} ) def add_file(self, item): if 'path' not in item: logging.info(f"Error adding item, unknown path: {item}") return self.files[item['path']] = item self.request_metadata(item['path']) def remove_file(self, filename): if filename in self.files: self.files.pop(filename) def add_callback(self, callback): self.callbacks.append(callback) def remove_callback(self, callback): if callback in self.callbacks: self.callbacks.remove(callback) return logging.info(f"callback not found {callback}") def process_update(self, data): if ( 'item' in data and data['item']['root'] != 'gcodes' or data['action'].endswith("file") and not self.is_gcode(data['item']['path']) ): 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'] == "modify_file": self.request_metadata(data['item']['path']) elif data['action'] == "move_file": self.files[data['item']['path']] = self.files.pop(data['source_item']['path']) self.files[data['item']['path']].update(data['item']) self.run_callbacks(data['action'], data) @staticmethod def is_gcode(path): return os.path.splitext(path)[1] in {'.gcode', '.gco', '.g'} def file_metadata_exists(self, filename): return filename in self.files and "slicer" in self.files[filename] def get_thumbnail_location(self, filename, small=False): if all(( small, len(self.files[filename]['thumbnails']) > 1 )): thumb = self.files[filename]['thumbnails'][1] else: thumb = self.files[filename]['thumbnails'][0] return ['file', thumb['path']] if thumb['local'] else ['http', thumb['path']] def has_thumbnail(self, filename): return filename in self.files and "thumbnails" in self.files[filename] def request_metadata(self, filename): if self.is_gcode(filename): self._screen._ws.klippy.get_file_metadata(filename, self._callback) else: logging.info("Not a gcode") def refresh_files(self): self._screen._ws.klippy.get_file_list(self._callback) def run_callbacks(self, action, item): for cb in self.callbacks: cb(action, item) def get_file_info(self, path): if path not in self.files: logging.info(f"Metadata not found {path}") self.request_metadata(path) return {} return self.files[path] def get_dir_info(self, directory): self._screen._ws.klippy.get_dir_info(self._callback, directory=directory)