list timelapses on printer with thumbnail and download button

This commit is contained in:
jneilliii 2024-05-18 14:31:03 -04:00
parent 56e5fb4dd2
commit 112210a3f1
2 changed files with 166 additions and 6 deletions

View File

@ -1,12 +1,19 @@
# coding=utf-8 # coding=utf-8
from __future__ import absolute_import from __future__ import absolute_import
import os
import threading import threading
import time import time
import flask
import datetime
import octoprint.plugin import octoprint.plugin
from octoprint.events import Events from octoprint.events import Events
from octoprint.util import get_formatted_size, get_formatted_datetime, is_hidden_path
from octoprint.server.util.flask import no_firstrun_access
from octoprint.server.util.tornado import LargeResponseHandler, UrlProxyHandler, path_validation_factory
from octoprint.access.permissions import Permissions
from urllib.parse import quote as urlquote
from .ftpsclient import IoTFTPSClient from .ftpsclient import IoTFTPSClient
@ -14,13 +21,15 @@ class BambuPrintPlugin(octoprint.plugin.SettingsPlugin,
octoprint.plugin.TemplatePlugin, octoprint.plugin.TemplatePlugin,
octoprint.plugin.AssetPlugin, octoprint.plugin.AssetPlugin,
octoprint.plugin.EventHandlerPlugin, octoprint.plugin.EventHandlerPlugin,
octoprint.plugin.SimpleApiPlugin): octoprint.plugin.SimpleApiPlugin,
octoprint.plugin.BlueprintPlugin):
def get_assets(self): def get_assets(self):
return {'js': ["js/bambu_printer.js"]} return {'js': ["js/bambu_printer.js"]}
def get_template_configs(self): def get_template_configs(self):
return [{"type": "settings", "custom_bindings": True}] #, {"type": "generic", "custom_bindings": True, "template": "bambu_printer.jinja2"}] return [{"type": "settings", "custom_bindings": True},
{"type": "generic", "custom_bindings": True, "template": "bambu_timelapse.jinja2"}] #, {"type": "generic", "custom_bindings": True, "template": "bambu_printer.jinja2"}]
def get_settings_defaults(self): def get_settings_defaults(self):
return {"device_type": "X1C", return {"device_type": "X1C",
@ -47,7 +56,6 @@ class BambuPrintPlugin(octoprint.plugin.SettingsPlugin,
def get_api_commands(self): def get_api_commands(self):
return {"register": ["email", "password", "region", "auth_token"]} return {"register": ["email", "password", "region", "auth_token"]}
def on_api_command(self, command, data): def on_api_command(self, command, data):
import flask
if command == "register": if command == "register":
if "email" in data and "password" in data and "region" in data and "auth_token" in data: if "email" in data and "password" in data and "region" in data and "auth_token" in data:
self._logger.info(f"Registering user {data['email']}") self._logger.info(f"Registering user {data['email']}")
@ -129,6 +137,100 @@ class BambuPrintPlugin(octoprint.plugin.SettingsPlugin,
else: else:
return [] return []
def get_timelapse_file_list(self):
if flask.request.path.startswith('/api/timelapse'):
def process():
host = self._settings.get(["host"])
access_code = self._settings.get(["access_code"])
return_file_list = []
try:
ftp = IoTFTPSClient(f"{host}", 990, "bblp", f"{access_code}", ssl_implicit=True)
timelapse_file_list = ftp.list_files("timelapse/", ".mp4") or []
for entry in timelapse_file_list:
if entry.startswith("/"):
filename = entry[1:].replace("timelapse/", "")
else:
filename = entry.replace("timelapse/", "")
filesize = ftp.ftps_session.size(f"timelapse/{filename}")
date_str = ftp.ftps_session.sendcmd(f"MDTM timelapse/{filename}").replace("213 ", "")
filedate = datetime.datetime.strptime(date_str, "%Y%m%d%H%M%S").replace(tzinfo=datetime.timezone.utc).timestamp()
return_file_list.append(
{
"bytes": filesize,
"date": get_formatted_datetime(datetime.datetime.fromtimestamp(filedate)),
"name": filename,
"size": get_formatted_size(filesize),
"thumbnail": "/plugin/bambu_printer/thumbnail/" + filename.replace(".mp4", ".jpg"),
"timestamp": filedate,
"url": f"/plugin/bambu_printer/timelapse/{filename}"
})
self._plugin_manager.send_plugin_message(self._identifier, {'files': return_file_list})
except Exception as e:
self._logger.debug(f"Error getting timelapse files: {e}")
thread = threading.Thread(target=process)
thread.daemon = True
thread.start()
def _hook_octoprint_server_api_before_request(self, *args, **kwargs):
return [self.get_timelapse_file_list]
@octoprint.plugin.BlueprintPlugin.route("/timelapse/<filename>", methods=["GET"])
@octoprint.server.util.flask.restricted_access
@no_firstrun_access
@Permissions.TIMELAPSE_DOWNLOAD.require(403)
def downloadTimelapse(self, filename):
dest_filename = os.path.join(self.get_plugin_data_folder(), filename)
host = self._settings.get(["host"])
access_code = self._settings.get(["access_code"])
if not os.path.exists(dest_filename):
ftp = IoTFTPSClient(f"{host}", 990, "bblp", f"{access_code}", ssl_implicit=True)
download_result = ftp.download_file(
source=f"timelapse/{filename}",
dest=dest_filename,
)
return flask.redirect("/plugin/bambu_printer/download/timelapse/" + urlquote(filename), code=302)
@octoprint.plugin.BlueprintPlugin.route("/thumbnail/<filename>", methods=["GET"])
@octoprint.server.util.flask.restricted_access
@no_firstrun_access
@Permissions.TIMELAPSE_DOWNLOAD.require(403)
def downloadTimelapse(self, filename):
dest_filename = os.path.join(self.get_plugin_data_folder(), filename)
host = self._settings.get(["host"])
access_code = self._settings.get(["access_code"])
if not os.path.exists(dest_filename):
ftp = IoTFTPSClient(f"{host}", 990, "bblp", f"{access_code}", ssl_implicit=True)
download_result = ftp.download_file(
source=f"timelapse/thumbnail/{filename}",
dest=dest_filename,
)
return flask.redirect("/plugin/bambu_printer/download/thumbnail/" + urlquote(filename), code=302)
def is_blueprint_csrf_protected(self):
return True
def route_hook(self, server_routes, *args, **kwargs):
return [
(r"/download/timelapse/(.*)", LargeResponseHandler,
{'path': self.get_plugin_data_folder(), 'as_attachment': True, 'path_validation': path_validation_factory(
lambda path: not is_hidden_path(path), status_code=404)}),
(r"/download/thumbnail/(.*)", LargeResponseHandler,
{'path': self.get_plugin_data_folder(), 'as_attachment': True, 'path_validation': path_validation_factory(
lambda path: not is_hidden_path(path), status_code=404)})
]
def get_update_information(self): def get_update_information(self):
return {'bambu_printer': {'displayName': "Bambu Printer", return {'bambu_printer': {'displayName': "Bambu Printer",
'displayVersion': self._plugin_version, 'displayVersion': self._plugin_version,
@ -164,4 +266,6 @@ def __plugin_load__():
"octoprint.filemanager.extension_tree": __plugin_implementation__.support_3mf_files, "octoprint.filemanager.extension_tree": __plugin_implementation__.support_3mf_files,
"octoprint.printer.sdcardupload": __plugin_implementation__.upload_to_sd, "octoprint.printer.sdcardupload": __plugin_implementation__.upload_to_sd,
"octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information, "octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information,
"octoprint.server.api.before_request": __plugin_implementation__._hook_octoprint_server_api_before_request,
"octoprint.server.http.routes": __plugin_implementation__.route_hook
} }

View File

@ -11,6 +11,9 @@ $(function () {
self.settingsViewModel = parameters[0]; self.settingsViewModel = parameters[0];
self.filesViewModel = parameters[1]; self.filesViewModel = parameters[1];
self.loginStateViewModel = parameters[2];
self.accessViewModel = parameters[3];
self.timelapseViewModel = parameters[4];
self.getAuthToken = function (data) { self.getAuthToken = function (data) {
self.settingsViewModel.settings.plugins.bambu_printer.auth_token(""); self.settingsViewModel.settings.plugins.bambu_printer.auth_token("");
@ -27,6 +30,59 @@ $(function () {
}); });
}; };
// initialize list helper
self.listHelper = new ItemListHelper(
"timelapseFiles",
{
name: function (a, b) {
// sorts ascending
if (a["name"].toLocaleLowerCase() < b["name"].toLocaleLowerCase())
return -1;
if (a["name"].toLocaleLowerCase() > b["name"].toLocaleLowerCase())
return 1;
return 0;
},
date: function (a, b) {
// sorts descending
if (a["date"] > b["date"]) return -1;
if (a["date"] < b["date"]) return 1;
return 0;
},
size: function (a, b) {
// sorts descending
if (a["bytes"] > b["bytes"]) return -1;
if (a["bytes"] < b["bytes"]) return 1;
return 0;
}
},
{},
"name",
[],
[],
CONFIG_TIMELAPSEFILESPERPAGE
);
self.onDataUpdaterPluginMessage = function(plugin, data) {
if (plugin != "bambu_printer") {
return;
}
if (data.files !== undefined) {
console.log(data.files);
self.listHelper.updateItems(data.files);
self.listHelper.resetPage();
}
};
self.onBeforeBinding = function () {
$('#bambu_timelapse').appendTo("#timelapse");
};
self.showTimelapseThumbnail = function(data) {
$("#bambu_printer_timelapse_thumbnail").attr("src", data.thumbnail);
$("#bambu_printer_timelapse_preview").modal('show');
};
/*$('#files div.upload-buttons > span.fileinput-button:first, #files div.folder-button').remove(); /*$('#files div.upload-buttons > span.fileinput-button:first, #files div.folder-button').remove();
$('#files div.upload-buttons > span.fileinput-button:first').removeClass('span6').addClass('input-block-level'); $('#files div.upload-buttons > span.fileinput-button:first').removeClass('span6').addClass('input-block-level');
@ -85,8 +141,8 @@ $(function () {
OCTOPRINT_VIEWMODELS.push({ OCTOPRINT_VIEWMODELS.push({
construct: Bambu_printerViewModel, construct: Bambu_printerViewModel,
// ViewModels your plugin depends on, e.g. loginStateViewModel, settingsViewModel, ... // ViewModels your plugin depends on, e.g. loginStateViewModel, settingsViewModel, ...
dependencies: ["settingsViewModel", "filesViewModel"], dependencies: ["settingsViewModel", "filesViewModel", "loginStateViewModel", "accessViewModel", "timelapseViewModel"],
// Elements to bind to, e.g. #settings_plugin_bambu_printer, #tab_plugin_bambu_printer, ... // Elements to bind to, e.g. #settings_plugin_bambu_printer, #tab_plugin_bambu_printer, ...
elements: ["#bambu_printer_print_options", "#settings_plugin_bambu_printer"] elements: ["#bambu_printer_print_options", "#settings_plugin_bambu_printer", "#bambu_timelapse"]
}); });
}); });