Skip to content

Commit 1d85d21

Browse files
authored
0.0.4
Moved URL injection of file metadata to FileAdded event Removed leading / from URL to resolve multi-instance related issues Changed alignment option to a select list Improved performance using regex pattern matching instead of line processing Deleting folder will now also delete extracted thumbnails
1 parent ae5ccb3 commit 1d85d21

File tree

4 files changed

+30
-76
lines changed

4 files changed

+30
-76
lines changed

README.md

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ This plugin will extract the embedded thumbnails from PrusaSlicer gcode files wh
44

55
The thumbnail image extracted will always be the last resolution provided in the thumbnail setting. So for example the Prusa Mini setting is `thumbnails = 16x16,220x124` so the thumbnail that will be extracted will be 220x124 pixels as seen in the screenshots below. Check the Configuration section below for additional details.
66

7-
**Note:** If you use the option to start printing after upload from PrusaSlicer than the thumbnail will not show up until after the print completes because of the current programming implementation. I will be working to get around this in the next version 0.0.4 release.
8-
97
The preview thumbnail can be shown in OctoPrint from the files list by clicking the newly added image button.
108

119
![button](screenshot_button.png)

octoprint_prusaslicerthumbnails/__init__.py

+24-72
Original file line numberDiff line numberDiff line change
@@ -9,55 +9,6 @@
99
import os
1010
import datetime
1111

12-
class ThumbnailProcessor(octoprint.filemanager.util.LineProcessorStream):
13-
14-
def __init__(self, fileBufferedReader, path, logger):
15-
super(ThumbnailProcessor, self).__init__(fileBufferedReader)
16-
self._thumbnail_data = ""
17-
self._collecting_data = False
18-
self._logger = logger
19-
self._path = path
20-
self._folder_path = os.path.dirname(path)
21-
22-
def process_line(self, origLine):
23-
if not len(origLine):
24-
return None
25-
26-
isBytesLineForPy3 = type(origLine) is bytes and not (type(origLine) is str)
27-
line = octoprint.util.to_unicode(origLine, errors="replace")
28-
line = line.lstrip()
29-
30-
if (len(line) != 0 and line.startswith("; thumbnail end")):
31-
self._collecting_data = False
32-
if len(self._thumbnail_data) > 0:
33-
if not os.path.exists(self._folder_path):
34-
os.makedirs(self._folder_path)
35-
if os.path.exists(self._path):
36-
os.remove(self._path)
37-
import base64
38-
with open(self._path, "wb") as fh:
39-
fh.write(base64.b64decode(self._thumbnail_data))
40-
self._thumbnail_data = ""
41-
42-
if (len(line) != 0 and self._collecting_data == True):
43-
self._thumbnail_data += line.replace("; ","")
44-
45-
if (len(line) != 0 and line.startswith("; thumbnail begin")):
46-
self._collecting_data = True
47-
48-
line = origLine
49-
50-
if (isBytesLineForPy3 and type(line) is str):
51-
# line = line.encode('utf8')
52-
# line = line.encode('ISO-8859-1')
53-
line = octoprint.util.to_bytes(line, errors="replace")
54-
else:
55-
if (isBytesLineForPy3 == False):
56-
# do nothing, because we don't modify the line
57-
if (type(line) is unicode):
58-
line = octoprint.util.to_native_str(line)
59-
return line
60-
6112
class PrusaslicerthumbnailsPlugin(octoprint.plugin.SettingsPlugin,
6213
octoprint.plugin.AssetPlugin,
6314
octoprint.plugin.TemplatePlugin,
@@ -97,34 +48,36 @@ def get_template_configs(self):
9748
dict(type="settings", custom_bindings=False, template="prusaslicerthumbnails_settings.jinja2"),
9849
]
9950

51+
def _extract_thumbnail(self, gcode_filename, thumbnail_filename):
52+
import re
53+
import base64
54+
regex = r"(?:^; thumbnail begin \d+x\d+ \d+)(?:\n|\r\n?)((?:.+(?:\n|\r\n?))+)(?:^; thumbnail end)"
55+
with open(gcode_filename,"rb") as gcode_file:
56+
test_str = gcode_file.read().decode('utf-8')
57+
matches = re.findall(regex, test_str, re.MULTILINE)
58+
if len(matches) > 0:
59+
path = os.path.dirname(thumbnail_filename)
60+
if not os.path.exists(path):
61+
os.makedirs(path)
62+
with open(thumbnail_filename,"wb") as png_file:
63+
png_file.write(base64.b64decode(matches[-1:][0].replace("; ", "").encode()))
64+
10065
##~~ EventHandlerPlugin mixin
10166

10267
def on_event(self, event, payload):
103-
if event == "FileAdded" and "gcode" in payload["type"]:
104-
self._logger.info("File Added: %s" % payload["path"])
105-
if event == "FileRemoved" and "gcode" in payload["type"]:
68+
if event == "FolderRemoved" and payload["storage"] == "local":
69+
import shutil
70+
shutil.rmtree(self.get_plugin_data_folder() + "/" + payload["path"], ignore_errors=True)
71+
if event in ["FileAdded","FileRemoved"] and payload["storage"] == "local" and "gcode" in payload["type"]:
10672
thumbnail_filename = self.get_plugin_data_folder() + "/" + payload["path"].replace(".gcode",".png")
10773
if os.path.exists(thumbnail_filename):
10874
os.remove(thumbnail_filename)
109-
if event == "MetadataAnalysisStarted" and ".gcode" in payload["path"]:
110-
self._analysis_active = True
111-
if event == "MetadataAnalysisFinished" and ".gcode" in payload["path"]:
112-
thumbnail_filename = self.get_plugin_data_folder() + "/" + payload["path"].replace(".gcode",".png")
113-
if os.path.exists(thumbnail_filename):
114-
thumbnail_url = "/plugin/prusaslicerthumbnails/thumbnail/" + payload["path"].replace(".gcode", ".png") + "?" + "{:%Y%m%d%H%M%S}".format(datetime.datetime.now())
115-
self._storage_interface = self._file_manager._storage(payload.get("origin", "local"))
116-
self._storage_interface.set_additional_metadata(payload.get("path"), "thumbnail", thumbnail_url, overwrite=True)
117-
self._analysis_active = False
118-
119-
##~~ preprocessor hook
120-
121-
def thumbnail_extractor(self, path, file_object, links=None, printer_profile=None, allow_overwrite=True, *args, **kwargs):
122-
if not octoprint.filemanager.valid_file_type(path, type="gcode"):
123-
return file_object
124-
125-
thumbnail_filename = self.get_plugin_data_folder() + "/" + path.replace(".gcode",".png")
126-
return octoprint.filemanager.util.StreamWrapper(file_object.filename, ThumbnailProcessor(file_object.stream(), thumbnail_filename, self._logger))
127-
# return file_object
75+
if event == "FileAdded":
76+
gcode_filename = self._file_manager.path_on_disk("local", payload["path"])
77+
self._extract_thumbnail(gcode_filename, thumbnail_filename)
78+
if os.path.exists(thumbnail_filename):
79+
thumbnail_url = "plugin/prusaslicerthumbnails/thumbnail/" + payload["path"].replace(".gcode", ".png") + "?" + "{:%Y%m%d%H%M%S}".format(datetime.datetime.now())
80+
self._file_manager.set_additional_metadata("local", payload["path"], "thumbnail", thumbnail_url, overwrite=True)
12881

12982
##~~ Routes hook
13083
def route_hook(self, server_routes, *args, **kwargs):
@@ -165,7 +118,6 @@ def __plugin_load__():
165118
global __plugin_hooks__
166119
__plugin_hooks__ = {
167120
"octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information,
168-
"octoprint.filemanager.preprocessor": __plugin_implementation__.thumbnail_extractor,
169121
"octoprint.server.http.routes": __plugin_implementation__.route_hook
170122
}
171123

octoprint_prusaslicerthumbnails/templates/prusaslicerthumbnails_settings.jinja2

+5-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
</label>
2323
</div>
2424
<div class="controls">
25-
<input type="text" class="input-small" data-bind="enable:settings.plugins.prusaslicerthumbnails.inline_thumbnail() == true && settings.plugins.prusaslicerthumbnails.align_inline_thumbnail() == true, value: settings.plugins.prusaslicerthumbnails.inline_thumbnail_align_value">
25+
<select class="input-small" style="width: 101px;" data-bind="enable:settings.plugins.prusaslicerthumbnails.inline_thumbnail() == true && settings.plugins.prusaslicerthumbnails.align_inline_thumbnail() == true, value: settings.plugins.prusaslicerthumbnails.inline_thumbnail_align_value">
26+
<option value="left">Left</option>
27+
<option value="center">Center</option>
28+
<option value="right">Right</option>
29+
</select>
2630
</div>
2731
</div>

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
plugin_name = "PrusaSlicer Thumbnails"
1515

1616
# The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module
17-
plugin_version = "0.0.3"
17+
plugin_version = "0.0.4"
1818

1919
# The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin
2020
# module

0 commit comments

Comments
 (0)