Skip to content

Commit

Permalink
0.0.7 (#26)
Browse files Browse the repository at this point in the history
* added a file crawler in settings that will extract missing thumbnails
* switched state panel thumbnail subscription monitoring
  • Loading branch information
jneilliii authored Apr 29, 2020
1 parent 3843543 commit 4fd227e
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 17 deletions.
55 changes: 54 additions & 1 deletion octoprint_prusaslicerthumbnails/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
class PrusaslicerthumbnailsPlugin(octoprint.plugin.SettingsPlugin,
octoprint.plugin.AssetPlugin,
octoprint.plugin.TemplatePlugin,
octoprint.plugin.EventHandlerPlugin):
octoprint.plugin.EventHandlerPlugin,
octoprint.plugin.SimpleApiPlugin):

def __init__(self):
self._fileRemovalTimer = None
Expand Down Expand Up @@ -55,6 +56,7 @@ def _extract_thumbnail(self, gcode_filename, thumbnail_filename):
regex = r"(?:^; thumbnail begin \d+x\d+ \d+)(?:\n|\r\n?)((?:.+(?:\n|\r\n?))+)(?:^; thumbnail end)"
with open(gcode_filename,"rb") as gcode_file:
test_str = gcode_file.read().decode('utf-8')
test_str = test_str.replace(b'\r\n',b'\n')
matches = re.findall(regex, test_str, re.MULTILINE)
if len(matches) > 0:
path = os.path.dirname(thumbnail_filename)
Expand All @@ -81,6 +83,57 @@ def on_event(self, event, payload):
self._file_manager.set_additional_metadata("local", payload["path"], "thumbnail", thumbnail_url, overwrite=True)
self._file_manager.set_additional_metadata("local", payload["path"], "thumbnail_src", self._identifier, overwrite=True)

##~~ SimpleApiPlugin mixin

def _process_gcode(self, gcode_file, results=[]):
self._logger.debug(gcode_file["path"])
if gcode_file.get("type") == "machinecode":
self._logger.debug(gcode_file.get("thumbnail"))
if gcode_file.get("thumbnail") == None:
self._logger.debug("No Thumbnail for %s, attempting extraction" % gcode_file["path"])
results["no_thumbnail"].append(gcode_file["path"])
self.on_event("FileAdded", dict(path=gcode_file["path"],storage="local",type=["gcode"]))
elif "prusaslicerthumbnails" in gcode_file.get("thumbnail") and not gcode_file.get("thumbnail_src"):
self._logger.debug("No Thumbnail source for %s, adding" % gcode_file["path"])
results["no_thumbnail_src"].append(gcode_file["path"])
self._file_manager.set_additional_metadata("local", gcode_file["path"], "thumbnail_src", self._identifier, overwrite=True)
elif gcode_file.get("type") == "folder" and not gcode_file.get("children") == None:
children = gcode_file["children"]
for key, file in children.items():
self._process_gcode(children[key], results)
elif gcode_file.get("type") == "folder" and gcode_file.get("children") == None:
results["warning"] = True
return results

def get_api_commands(self):
return dict(crawl_files=[])

def on_api_command(self, command, data):
import flask
import json
from octoprint.server import user_permission
if not user_permission.can():
return flask.make_response("Insufficient rights", 403)

if command == "crawl_files":
self._logger.debug("Crawling Files")
FileList = self._file_manager.list_files()
LocalFiles = FileList["local"]
results = dict(no_thumbnail=[],no_thumbnail_src=[])
for key, file in LocalFiles.items():
results = self._process_gcode(LocalFiles[key], results)
# if LocalFiles[key].get("children") == None:
# # self._logger.debug(LocalFiles[key].get("thumbnail"))
# if LocalFiles[key].get("thumbnail") == None:
# # self._logger.debug("No Thumbnail for %s, attempting extraction" % file["path"])
# results["no_thumbnail"].append(file["path"])
# self.on_event("FileAdded", dict(path=file["path"],storage="local",type=["gcode"]))
# elif "prusaslicerthumbnails" in LocalFiles[key].get("thumbnail") and not LocalFiles[key].get("thumbnail_src"):
# # self._logger.debug("No Thumbnail source for %s, adding" % file["path"])
# results["no_thumbnail_src"].append(file["path"])
# self._file_manager.set_additional_metadata("local", file["path"], "thumbnail_src", self._identifier, overwrite=True)
return flask.jsonify(results)

##~~ Routes hook
def route_hook(self, server_routes, *args, **kwargs):
from octoprint.server.util.tornado import LargeResponseHandler, UrlProxyHandler, path_validation_factory
Expand Down
69 changes: 54 additions & 15 deletions octoprint_prusaslicerthumbnails/static/js/prusaslicerthumbnails.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ $(function() {
self.thumbnail_url = ko.observable('/static/img/tentacle-20x20.png');
self.thumbnail_title = ko.observable('');
self.inline_thumbnail = ko.observable();
self.crawling_files = ko.observable(false);
self.crawl_results = ko.observableArray([]);
self.show_crawl_warning = ko.observable(false);

self.filesViewModel.prusaslicerthumbnails_open_thumbnail = function(data) {
if(data.name.indexOf('.gcode') > 0){
Expand All @@ -31,6 +34,37 @@ $(function() {
self.DEFAULT_THUMBNAIL_ALIGN = "left"
self.filesViewModel.thumbnailAlignValue = ko.observable(self.DEFAULT_THUMBNAIL_ALIGN)

self.crawl_files = function(){
self.crawling_files(true);
self.crawl_results([]);
$.ajax({
url: API_BASEURL + "plugin/prusaslicerthumbnails",
type: "POST",
dataType: "json",
data: JSON.stringify({
command: "crawl_files"
}),
contentType: "application/json; charset=UTF-8"
}).done(function(data){
self.show_crawl_warning(false);
for (key in data) {
if(data[key].length && data[key] !== 'warning'){
self.crawl_results.push({name: ko.observable(key), files: ko.observableArray(data[key])});
} else if(key == 'warning'){
self.show_crawl_warning(true);
}
}
console.log(data);
if(self.crawl_results().length == 0){
self.crawl_results.push({name: ko.observable('No convertible files found'), files: ko.observableArray([])});
}
self.filesViewModel.requestData({force: true});
self.crawling_files(false);
}).fail(function(data){
self.crawling_files(false);
})
}

self.onBeforeBinding = function() {
// assign initial scaling
if (self.settingsViewModel.settings.plugins.prusaslicerthumbnails.scale_inline_thumbnail()==true){
Expand Down Expand Up @@ -66,20 +100,25 @@ $(function() {
self.filesViewModel.thumbnailAlignValue(newValue);
});

self.filesViewModel.listHelper.selectedItem.subscribe(function(data){
// remove the state panel thumbnail in case it's already there
if(data){
if(self.settingsViewModel.settings.plugins.prusaslicerthumbnails.state_panel_thumbnail() && data.thumbnail && data.thumbnail_src == 'prusaslicerthumbnails'){
if($('#prusalicer_state_thumbnail').length) {
$('#prusalicer_state_thumbnail > img').attr('src', data.thumbnail);
} else {
$('#state > div > hr:nth-child(4)').after('<div id="prusalicer_state_thumbnail" class="row-fluid"><img src="'+data.thumbnail+'" width="100%"/>\n<hr/></div>');
}
} else {
$('#prusalicer_state_thumbnail').remove();
}
} else {
$('#prusalicer_state_thumbnail').remove();
self.printerStateViewModel.filepath.subscribe(function(data){
if(data && typeof self.printerStateViewModel.sd() !== 'undefined'){
OctoPrint.files.get('local',data)
.done(function(file_data){
if(file_data){
if(self.settingsViewModel.settings.plugins.prusaslicerthumbnails.state_panel_thumbnail() && file_data.thumbnail && file_data.thumbnail_src == 'prusaslicerthumbnails'){
if($('#prusalicer_state_thumbnail').length) {
$('#prusalicer_state_thumbnail > img').attr('src', file_data.thumbnail);
} else {
$('#state > div > hr:nth-child(4)').after('<div id="prusalicer_state_thumbnail" class="row-fluid"><img src="'+file_data.thumbnail+'" width="100%"/>\n<hr/></div>');
}
} else {
$('#prusalicer_state_thumbnail').remove();
}
}
})
.fail(function(file_data){
console.log('Error getting file information for "'+data+'"');
});
}
});
}
Expand All @@ -106,6 +145,6 @@ $(function() {
OCTOPRINT_VIEWMODELS.push({
construct: PrusaslicerthumbnailsViewModel,
dependencies: ['settingsViewModel', 'filesViewModel', 'printerStateViewModel'],
elements: ['div#prusa_thumbnail_viewer']
elements: ['div#prusa_thumbnail_viewer', '#crawl_files', '#crawl_files_results']
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,32 @@
</select>
</div>
</div>
<div class="row-fluid" data-bind="allowBindings: false">
<div class="row-fluid" data-bind="allowBindings: true">
<div id="crawl_files" class="control-group">
<div class="controls">
<button class="btn btn-primary" data-bind="click: crawl_files, enable: !crawling_files()"><i class="fa fa-spinner fa-spin" data-bind="visible: crawling_files" style="display: none;"></i> Scan Files</button>
</div>
</div>
<div id="crawl_files_results" class="row-fluid" data-bind="if: crawl_results().length > 0">
<div class="alert alert-block">
<h4>Crawl Results</h4>
<div class="muted" data-bind="if: show_crawl_warning()"><small><span class="label label-important">Warning: </span> Currently the scan is only able to process the root folder and first level of sub-folders.</small></div>
<ul class="unstyled" data-bind="foreach: { data: crawl_results, as: 'category', noChildContext: true }">
<!-- ko if:category.files().length == 0 -->
<li><span data-bind="text: category.name" class="label label-success"></span></li>
<!-- /ko -->
<!-- ko if:category.files().length > 0 -->
<li><span data-bind="text: category.name, css: {'label-warning': category.name() == 'no_thumbnail', 'label-success': category.name() == 'no_thumbnail_src'}" class="label"></span>
<ul data-bind="foreach: { data: category.files, as: 'item', noChildContext: true }">
<li>
<span data-bind="text: item"></span>
</li>
</ul>
</li>
<!-- /ko -->
</ul>
</div>
</div>
</div>
</div>
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
plugin_name = "PrusaSlicer Thumbnails"

# The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module
plugin_version = "0.0.6"
plugin_version = "0.0.7"

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

0 comments on commit 4fd227e

Please sign in to comment.