176 lines
6.0 KiB
Python
176 lines
6.0 KiB
Python
import logging
|
|
import asyncio
|
|
import json
|
|
import os
|
|
import base64
|
|
|
|
from contextlib import suppress
|
|
from threading import Thread
|
|
|
|
import gi
|
|
gi.require_version("Gtk", "3.0")
|
|
from gi.repository import Gtk, Gdk, GLib
|
|
|
|
logger = logging.getLogger("KlipperScreen.KlippyFiles")
|
|
|
|
RESCAN_INTERVAL = 4
|
|
|
|
class KlippyFiles(Thread):
|
|
callbacks = []
|
|
filelist = []
|
|
files = {}
|
|
metadata_timeout = {}
|
|
timeout = None
|
|
thumbnail_dir = "/tmp/.KS-thumbnails"
|
|
|
|
def __init__(self, screen, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.loop = None
|
|
self._poll_task = None
|
|
self._screen = screen
|
|
|
|
if not os.path.exists(self.thumbnail_dir):
|
|
os.makedirs(self.thumbnail_dir)
|
|
|
|
def run(self):
|
|
self.loop = asyncio.new_event_loop()
|
|
loop = self.loop
|
|
asyncio.set_event_loop(loop)
|
|
try:
|
|
self._poll_task = asyncio.ensure_future(self._poll())
|
|
loop.run_forever()
|
|
loop.run_until_complete(loop.shutdown_asyncgens())
|
|
|
|
self._poll_task.cancel()
|
|
with suppress(asyncio.CancelledError):
|
|
loop.run_until_complete(self._poll_task)
|
|
finally:
|
|
loop.close()
|
|
|
|
def stop(self):
|
|
self.loop.call_soon_threadsafe(self.loop.stop)
|
|
|
|
async def _poll(self):
|
|
await self.ret_files()
|
|
while True:
|
|
try:
|
|
await self.ret_files()
|
|
except:
|
|
logger.exception("Poll files error")
|
|
await asyncio.sleep(4)
|
|
|
|
|
|
def _callback(self, result, method, params):
|
|
if method == "server.files.list":
|
|
if "result" in result and isinstance(result['result'],list):
|
|
newfiles = []
|
|
deletedfiles = self.filelist.copy()
|
|
for item in result['result']:
|
|
if item['filename'] in self.files:
|
|
deletedfiles.remove(item['filename'])
|
|
else:
|
|
newfiles.append(item['filename'])
|
|
logger.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'])
|
|
|
|
if len(self.callbacks) > 0 and (len(newfiles) > 0 or len(deletedfiles) > 0):
|
|
logger.debug("Running callbacks...")
|
|
for cb in self.callbacks:
|
|
cb(newfiles, deletedfiles, [])
|
|
|
|
if len(deletedfiles) > 0:
|
|
logger.debug("Deleted files: %s", deletedfiles)
|
|
for file in deletedfiles:
|
|
self.filelist.remove(file)
|
|
self.files.pop(file, None)
|
|
|
|
elif method == "server.files.metadata":
|
|
if "error" in result.keys():
|
|
logger.debug("Error in getting metadata for %s. Retrying in 6 seconds" %(params['filename']))
|
|
return
|
|
|
|
logger.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:
|
|
logger.debug("Running metadata callbacks")
|
|
cb([], [], [params['filename']])
|
|
|
|
def add_file_callback(self, callback):
|
|
try:
|
|
self.callbacks.append(callback)
|
|
except:
|
|
logger.debug("Callback not found: %s" % callback)
|
|
|
|
def remove_file_callback(self, callback):
|
|
if callback in self.callbacks:
|
|
self.callbacks.pop(self.callbacks.index(callback))
|
|
|
|
def add_timeout(self):
|
|
if self.timeout == None:
|
|
self.timeout = GLib.timeout_add(4000, self.ret_files)
|
|
|
|
def file_exists(self, filename):
|
|
return True if filename in self.filelist else False
|
|
|
|
def file_metadata_exists(self, filename):
|
|
if not self.file_exists(filename):
|
|
return False
|
|
if "slicer" in self.files[filename]:
|
|
return True
|
|
return False
|
|
|
|
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'])
|
|
|
|
def has_thumbnail(self, filename):
|
|
if filename not in self.files:
|
|
return False
|
|
return "thumbnails" in self.files[filename] and len(self.files[filename]) > 0
|
|
|
|
def remove_timeout(self):
|
|
if self.timeout != None:
|
|
self.timeout = None
|
|
|
|
def request_metadata(self, filename):
|
|
if filename not in self.filelist:
|
|
return False
|
|
self._screen._ws.klippy.get_file_metadata(filename, self._callback)
|
|
|
|
async def ret_files(self, retval=True):
|
|
logger.debug("Scanning for files")
|
|
if not self._screen._ws.klippy.get_file_list(self._callback):
|
|
self.timeout = None
|
|
|
|
def ret_file_data (self, filename):
|
|
print("Getting file info for %s" % (filename))
|
|
self._screen._ws.klippy.get_file_metadata(filename, self._callback)
|
|
|
|
def get_file_list(self):
|
|
return self.filelist
|
|
|
|
def get_file_info(self, filename):
|
|
if filename not in self.files:
|
|
return None
|
|
|
|
return self.files[filename]
|
|
|
|
def add_file(self, file_name, size, modified, old_file_name = None):
|
|
print(file_name)
|