├── .editorconfig ├── .gitignore ├── MANIFEST.in ├── README.md ├── babel.cfg ├── continuousprint ├── __init__.py ├── static │ └── js │ │ └── continuousprint.js └── templates │ ├── README.txt │ ├── continuousprint_settings.jinja2 │ └── continuousprint_tab.jinja2 ├── requirements.txt └── setup.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [**.py] 13 | indent_style = tab 14 | 15 | [**.js] 16 | indent_style = space 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | .idea 4 | *.iml 5 | build 6 | dist 7 | *.egg* 8 | .DS_Store 9 | *.zip 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | recursive-include continuousprint/templates * 3 | recursive-include continuousprint/translations * 4 | recursive-include continuousprint/static * 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Continuous Print Queue Plugin 2 | 3 | Octoprint plugin that allows users to generate a print queue, specify a print bed clearning script and run the queue which will print-clear-print until the end of the queue. 4 | 5 | ## Setup 6 | 7 | Install manually using this URL: 8 | 9 | https://github.com/nukeem/continuousprint/archive/master.zip 10 | 11 | 12 | 13 | ## Configuration 14 | 15 | Make sure you have a method of clearning the bed automatically and have set the print bed clearing script or you'll end up messing the first print. 16 | -------------------------------------------------------------------------------- /babel.cfg: -------------------------------------------------------------------------------- 1 | [python: */**.py] 2 | [jinja2: */**.jinja2] 3 | extensions=jinja2.ext.autoescape, jinja2.ext.with_ 4 | 5 | [javascript: */**.js] 6 | extract_messages = gettext, ngettext 7 | -------------------------------------------------------------------------------- /continuousprint/__init__.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from __future__ import absolute_import 3 | 4 | import octoprint.plugin 5 | import flask, json 6 | from octoprint.server.util.flask import restricted_access 7 | from octoprint.events import eventManager, Events 8 | 9 | class ContinuousprintPlugin(octoprint.plugin.SettingsPlugin, 10 | octoprint.plugin.TemplatePlugin, 11 | octoprint.plugin.AssetPlugin, 12 | octoprint.plugin.StartupPlugin, 13 | octoprint.plugin.BlueprintPlugin, 14 | octoprint.plugin.EventHandlerPlugin): 15 | 16 | print_history = [] 17 | enabled = False 18 | paused = False 19 | 20 | 21 | ##~~ SettingsPlugin mixin 22 | def get_settings_defaults(self): 23 | return dict( 24 | cp_queue="[]", 25 | cp_bed_clearing_script="M17 ;enable steppers\nM91 ; Set relative for lift\nG0 Z10 ; lift z by 10\nG90 ;back to absolute positioning\nM190 R25 ; set bed to 25 for cooldown\nG4 S90 ; wait for temp stabalisation\nM190 R30 ;verify temp below threshold\nG0 X200 Y235 ;move to back corner\nG0 X110 Y235 ;move to mid bed aft\nG0 Z1v ;come down to 1MM from bed\nG0 Y0 ;wipe forward\nG0 Y235 ;wipe aft\nG28 ; home", 26 | cp_queue_finished="M18 ; disable steppers\nM104 T0 S0 ; extruder heater off\nM140 S0 ; heated bed heater off\nM300 S880 P300 ; beep to show its finished" 27 | ) 28 | 29 | 30 | 31 | 32 | ##~~ StartupPlugin mixin 33 | def on_after_startup(self): 34 | self._logger.info("Continuous Print Plugin started") 35 | 36 | 37 | 38 | 39 | ##~~ Event hook 40 | def on_event(self, event, payload): 41 | from octoprint.events import Events 42 | ## Print complete check it was the print in the bottom of the queue and not just any print 43 | if event == Events.PRINT_DONE: 44 | if self.enabled == True: 45 | self.complete_print(payload) 46 | 47 | # On fail stop all prints 48 | if event == Events.PRINT_FAILED or event == Events.PRINT_CANCELLED: 49 | self.enabled = False # Set enabled to false 50 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="error", msg="Print queue cancelled")) 51 | 52 | if event == Events.PRINTER_STATE_CHANGED: 53 | # If the printer is operational and the last print succeeded then we start next print 54 | state = self._printer.get_state_id() 55 | if state == "OPERATIONAL": 56 | self.start_next_print() 57 | 58 | if event == Events.FILE_SELECTED: 59 | # Add some code to clear the print at the bottom 60 | self._logger.info("File selected") 61 | bed_clearing_script=self._settings.get(["cp_bed_clearing_script"]) 62 | 63 | if event == Events.UPDATED_FILES: 64 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="updatefiles", msg="")) 65 | 66 | def complete_print(self, payload): 67 | queue = json.loads(self._settings.get(["cp_queue"])) 68 | if payload["path"]==queue[0]["path"]: 69 | # Remove the print from the queue 70 | queue.pop(0) 71 | self._settings.set(["cp_queue"], json.dumps(queue)) 72 | self._settings.save() 73 | 74 | # Add to the history 75 | self.print_history.append(dict( 76 | name = payload["name"], 77 | time = payload["time"] 78 | )) 79 | 80 | # Clear down the bed 81 | self.clear_bed() 82 | 83 | # Tell the UI to reload 84 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="reload", msg="")) 85 | else: 86 | enabled = False 87 | 88 | def parse_gcode(self, input_script): 89 | script = [] 90 | for x in input_script: 91 | if x.find("[PAUSE]", 0) > -1: 92 | self.paused = True 93 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="paused", msg="Queue paused")) 94 | else: 95 | script.append(x) 96 | return script; 97 | 98 | def clear_bed(self): 99 | self._logger.info("Clearing bed") 100 | bed_clearing_script=self._settings.get(["cp_bed_clearing_script"]).split("\n") 101 | self._printer.commands(self.parse_gcode(bed_clearing_script)) 102 | 103 | def complete_queue(self): 104 | self.enabled = False # Set enabled to false 105 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="complete", msg="Print Queue Complete")) 106 | queue_finished_script = self._settings.get(["cp_queue_finished"]).split("\n") 107 | self._printer.commands(self.parse_gcode(queue_finished_script)) 108 | 109 | def start_next_print(self): 110 | if self.enabled == True and self.paused == False: 111 | queue = json.loads(self._settings.get(["cp_queue"])) 112 | if len(queue) > 0: 113 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="popup", msg="Starting print: " + queue[0]["name"])) 114 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="reload", msg="")) 115 | 116 | sd = False 117 | if queue[0]["sd"] == "true": 118 | sd = True 119 | try: 120 | self._printer.select_file(queue[0]["path"], sd) 121 | self._logger.info(queue[0]["path"]) 122 | self._printer.start_print() 123 | except InvalidFileLocation: 124 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="popup", msg="ERROR file not found")) 125 | except InvalidFileType: 126 | self._plugin_manager.send_plugin_message(self._identifier, dict(type="popup", msg="ERROR file not gcode")) 127 | else: 128 | self.complete_queue() 129 | 130 | 131 | ##~~ APIs 132 | @octoprint.plugin.BlueprintPlugin.route("/queue", methods=["GET"]) 133 | @restricted_access 134 | def get_queue(self): 135 | queue = json.loads(self._settings.get(["cp_queue"])) 136 | 137 | for x in self.print_history: 138 | queue.append(x) 139 | 140 | return flask.jsonify(queue=queue) 141 | 142 | @octoprint.plugin.BlueprintPlugin.route("/queueup", methods=["GET"]) 143 | @restricted_access 144 | def queue_up(self): 145 | index = int(flask.request.args.get("index", 0)) 146 | queue = json.loads(self._settings.get(["cp_queue"])) 147 | orig = queue[index] 148 | queue[index] = queue[index-1] 149 | queue[index-1] = orig 150 | self._settings.set(["cp_queue"], json.dumps(queue)) 151 | self._settings.save() 152 | return flask.jsonify(queue=queue) 153 | 154 | @octoprint.plugin.BlueprintPlugin.route("/queuedown", methods=["GET"]) 155 | @restricted_access 156 | def queue_down(self): 157 | index = int(flask.request.args.get("index", 0)) 158 | queue = json.loads(self._settings.get(["cp_queue"])) 159 | orig = queue[index] 160 | queue[index] = queue[index+1] 161 | queue[index+1] = orig 162 | self._settings.set(["cp_queue"], json.dumps(queue)) 163 | self._settings.save() 164 | return flask.jsonify(queue=queue) 165 | 166 | @octoprint.plugin.BlueprintPlugin.route("/addqueue", methods=["POST"]) 167 | @restricted_access 168 | def add_queue(self): 169 | queue = json.loads(self._settings.get(["cp_queue"])) 170 | queue.append(dict( 171 | name=flask.request.form["name"], 172 | path=flask.request.form["path"], 173 | sd=flask.request.form["sd"] 174 | )) 175 | self._settings.set(["cp_queue"], json.dumps(queue)) 176 | self._settings.save() 177 | return flask.make_response("success", 200) 178 | 179 | @octoprint.plugin.BlueprintPlugin.route("/removequeue", methods=["DELETE"]) 180 | @restricted_access 181 | def remove_queue(self): 182 | queue = json.loads(self._settings.get(["cp_queue"])) 183 | self._logger.info(flask.request.args.get("index", 0)) 184 | queue.pop(int(flask.request.args.get("index", 0))) 185 | self._settings.set(["cp_queue"], json.dumps(queue)) 186 | self._settings.save() 187 | return flask.make_response("success", 200) 188 | 189 | @octoprint.plugin.BlueprintPlugin.route("/startqueue", methods=["GET"]) 190 | @restricted_access 191 | def start_queue(self): 192 | self.print_history = [] 193 | self.paused = False 194 | self.enabled = True # Set enabled to true 195 | self.start_next_print() 196 | return flask.make_response("success", 200) 197 | 198 | @octoprint.plugin.BlueprintPlugin.route("/resumequeue", methods=["GET"]) 199 | @restricted_access 200 | def resume_queue(self): 201 | self.paused = False 202 | self.start_next_print() 203 | return flask.make_response("success", 200) 204 | 205 | ##~~ TemplatePlugin 206 | def get_template_vars(self): 207 | return dict( 208 | cp_enabled=self.enabled, 209 | cp_bed_clearing_script=self._settings.get(["cp_bed_clearing_script"]), 210 | cp_queue_finished=self._settings.get(["cp_queue_finished"]), 211 | cp_paused=self.paused 212 | ) 213 | def get_template_configs(self): 214 | return [ 215 | dict(type="settings", custom_bindings=False, template="continuousprint_settings.jinja2"), 216 | dict(type="tab", custom_bindings=False, template="continuousprint_tab.jinja2") 217 | ] 218 | 219 | ##~~ AssetPlugin 220 | def get_assets(self): 221 | return dict( 222 | js=["js/continuousprint.js"] 223 | ) 224 | 225 | 226 | ##~~ Softwareupdate hook 227 | def get_update_information(self): 228 | # Define the configuration for your plugin to use with the Software Update 229 | # Plugin here. See https://docs.octoprint.org/en/master/bundledplugins/softwareupdate.html 230 | # for details. 231 | return dict( 232 | continuousprint=dict( 233 | displayName="Continuous Print Plugin", 234 | displayVersion=self._plugin_version, 235 | 236 | # version check: github repository 237 | type="github_release", 238 | user="nukeem", 239 | repo="continuousprint", 240 | current=self._plugin_version, 241 | 242 | # update method: pip 243 | pip="https://github.com/nukeem/continuousprint/archive/{target_version}.zip" 244 | ) 245 | ) 246 | 247 | 248 | __plugin_name__ = "Continuous Print" 249 | __plugin_pythoncompat__ = ">=2.7,<4" # python 2 and 3 250 | 251 | def __plugin_load__(): 252 | global __plugin_implementation__ 253 | __plugin_implementation__ = ContinuousprintPlugin() 254 | 255 | global __plugin_hooks__ 256 | __plugin_hooks__ = { 257 | "octoprint.plugin.softwareupdate.check_config": __plugin_implementation__.get_update_information 258 | } 259 | 260 | -------------------------------------------------------------------------------- /continuousprint/static/js/continuousprint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * View model for OctoPrint-Print-Queue 3 | * 4 | * Author: Michael New 5 | * License: AGPLv3 6 | */ 7 | 8 | $(function() { 9 | function ContinuousPrintViewModel(parameters) { 10 | var self = this; 11 | self.params = parameters; 12 | 13 | self.printerState = parameters[0]; 14 | self.loginState = parameters[1]; 15 | self.files = parameters[2]; 16 | self.settings = parameters[3]; 17 | self.is_paused = ko.observable(); 18 | self.onBeforeBinding = function() { 19 | self.loadQueue(); 20 | self.is_paused(false); 21 | } 22 | 23 | 24 | self.loadQueue = function() { 25 | $('#queue_list').html(""); 26 | $.ajax({ 27 | url: "plugin/continuousprint/queue", 28 | type: "GET", 29 | dataType: "json", 30 | headers: { 31 | "X-Api-Key":UI_API_KEY, 32 | }, 33 | success:function(r){ 34 | if (r.queue.length > 0) { 35 | for(var i = 0; i < r.queue.length; i++) { 36 | var file = r.queue[i]; 37 | var row; 38 | if (file["time"] == undefined) { 39 | var other = "   "; 40 | if (i == 0) other = ""; 41 | if (i == 1) other = " "; 42 | row = $("
"+file.name+"
" + other + "
"); 43 | row.find(".fa-minus").click(function() { 44 | self.removeFromQueue($(this).data("index")); 45 | }); 46 | row.find(".fa-chevron-up").click(function() { 47 | self.moveUp($(this).data("index")); 48 | }); 49 | row.find(".fa-chevron-down").click(function() { 50 | self.moveDown($(this).data("index")); 51 | }); 52 | } else { 53 | var time = file.time / 60; 54 | var suffix = " mins"; 55 | if (time > 60) { 56 | time = time / 60; 57 | suffix = " hours"; 58 | if (time > 24) { 59 | time = time / 24; 60 | suffix = " days"; 61 | } 62 | } 63 | 64 | row = $("
Complete: "+ file.name+ "
took: " + time.toFixed(0) + suffix + "
") 65 | } 66 | $('#queue_list').append(row); 67 | } 68 | } else { 69 | $('#queue_list').html("
Queue is empty
"); 70 | } 71 | } 72 | }); 73 | }; 74 | 75 | self.getFileList = function() { 76 | $('#file_list').html(""); 77 | $.ajax({ 78 | url: "/api/files?recursive=true", 79 | type: "GET", 80 | dataType: "json", 81 | headers: { 82 | "X-Api-Key":UI_API_KEY, 83 | }, 84 | success:function(r){ 85 | var filelist = []; 86 | if (r.files.length > 0) { 87 | filelist = self.recursiveGetFiles(r.files); 88 | 89 | for(var i = 0; i < filelist.length; i++) { 90 | var file = filelist[i]; 91 | var row = $("
"+file.path+"
"); 92 | row.find(".fa").click(function() { 93 | self.addToQueue({ 94 | name: $(this).data("name"), 95 | path: $(this).data("path"), 96 | sd: $(this).data("sd") 97 | }); 98 | }); 99 | $('#file_list').append(row); 100 | } 101 | 102 | } else { 103 | $('#file_list').html("
No files found
"); 104 | } 105 | } 106 | }); 107 | } 108 | 109 | $(document).ready(function(){ 110 | self.getFileList(); 111 | 112 | $("#gcode_search").keyup(function() { 113 | var criteria = this.value.toLowerCase(); 114 | $("#file_list > div").each(function(){ 115 | if ($(this).data("name").indexOf(criteria) == -1) { 116 | $(this).hide(); 117 | } else { 118 | $(this).show(); 119 | } 120 | }) 121 | }); 122 | 123 | 124 | }); 125 | 126 | 127 | self.recursiveGetFiles = function(files) { 128 | var filelist = []; 129 | for(var i = 0; i < files.length; i++) { 130 | var file = files[i]; 131 | if (file.name.toLowerCase().indexOf(".gco") > -1 || file.name.toLowerCase().indexOf(".gcode") > -1) { 132 | filelist.push(file); 133 | } else if (file.children != undefined) { 134 | console.log("Getting children", self.recursiveGetFiles(file.children)) 135 | filelist = filelist.concat(self.recursiveGetFiles(file.children)); 136 | } 137 | } 138 | return filelist; 139 | } 140 | 141 | self.addToQueue = function(data) { 142 | $.ajax({ 143 | url: "plugin/continuousprint/addqueue", 144 | type: "POST", 145 | dataType: "text", 146 | headers: { 147 | "X-Api-Key":UI_API_KEY, 148 | }, 149 | data: data, 150 | success: function(c) { 151 | self.loadQueue(); 152 | }, 153 | error: function() { 154 | self.loadQueue(); 155 | } 156 | }); 157 | } 158 | 159 | self.moveUp = function(data) { 160 | $.ajax({ 161 | url: "plugin/continuousprint/queueup?index=" + data, 162 | type: "GET", 163 | dataType: "json", 164 | headers: {"X-Api-Key":UI_API_KEY}, 165 | success: function(c) { 166 | self.loadQueue(); 167 | }, 168 | error: function() { 169 | self.loadQueue(); 170 | } 171 | }); 172 | } 173 | 174 | self.moveDown = function(data) { 175 | $.ajax({ 176 | url: "plugin/continuousprint/queuedown?index=" + data, 177 | type: "GET", 178 | dataType: "json", 179 | headers: {"X-Api-Key":UI_API_KEY}, 180 | success: function(c) { 181 | self.loadQueue(); 182 | }, 183 | error: function() { 184 | self.loadQueue(); 185 | } 186 | }); 187 | } 188 | 189 | self.removeFromQueue = function(data) { 190 | $.ajax({ 191 | url: "plugin/continuousprint/removequeue?index=" + data, 192 | type: "DELETE", 193 | dataType: "text", 194 | headers: { 195 | "X-Api-Key":UI_API_KEY, 196 | }, 197 | success: function(c) { 198 | self.loadQueue(); 199 | }, 200 | error: function() { 201 | self.loadQueue(); 202 | } 203 | }); 204 | } 205 | 206 | self.startQueue = function() { 207 | self.is_paused(false); 208 | $.ajax({ 209 | url: "plugin/continuousprint/startqueue", 210 | type: "GET", 211 | dataType: "json", 212 | headers: { 213 | "X-Api-Key":UI_API_KEY, 214 | }, 215 | data: {} 216 | }); 217 | } 218 | 219 | self.resumeQueue = function() { 220 | self.is_paused(false) 221 | $.ajax({ 222 | url: "plugin/continuousprint/resumequeue", 223 | type: "GET", 224 | dataType: "json", 225 | headers: { 226 | "X-Api-Key":UI_API_KEY, 227 | }, 228 | data: {} 229 | }); 230 | } 231 | 232 | self.onDataUpdaterPluginMessage = function(plugin, data) { 233 | if (plugin != "continuousprint") return; 234 | 235 | var theme = 'info'; 236 | switch(data["type"]) { 237 | case "popup": 238 | theme = "info"; 239 | break; 240 | case "error": 241 | theme = 'danger'; 242 | self.loadQueue(); 243 | break; 244 | case "complete": 245 | theme = 'success'; 246 | self.loadQueue(); 247 | break; 248 | case "reload": 249 | theme = 'success' 250 | self.loadQueue(); 251 | break; 252 | case "paused": 253 | self.is_paused(true); 254 | break; 255 | case "updatefiles": 256 | self.getFileList(); 257 | break; 258 | } 259 | 260 | if (data.msg != "") { 261 | new PNotify({ 262 | title: 'Continuous Print', 263 | text: data.msg, 264 | type: theme, 265 | hide: true, 266 | buttons: { 267 | closer: true, 268 | sticker: false 269 | } 270 | }); 271 | } 272 | } 273 | } 274 | 275 | // This is how our plugin registers itself with the application, by adding some configuration 276 | // information to the global variable OCTOPRINT_VIEWMODELS 277 | OCTOPRINT_VIEWMODELS.push([ 278 | // This is the constructor to call for instantiating the plugin 279 | ContinuousPrintViewModel, 280 | 281 | // This is a list of dependencies to inject into the plugin, the order which you request 282 | // here is the order in which the dependencies will be injected into your view model upon 283 | // instantiation via the parameters argument 284 | ["printerStateViewModel", "loginStateViewModel", "filesViewModel", "settingsViewModel"], 285 | 286 | // Finally, this is the list of selectors for all elements we want this view model to be bound to. 287 | ["#tab_plugin_continuousprint"] 288 | ]); 289 | }); 290 | -------------------------------------------------------------------------------- /continuousprint/templates/README.txt: -------------------------------------------------------------------------------- 1 | Put your plugin's Jinja2 templates here. -------------------------------------------------------------------------------- /continuousprint/templates/continuousprint_settings.jinja2: -------------------------------------------------------------------------------- 1 |

Continuous Print Settings

2 |
3 |

4 | When continually printing the bed needs to be cleared in order for the next print to work. 5 |

6 |

7 | There is a special [PAUSE] command that doesn't get sent to the printer but instead indefinatly pauses the queue until the resume button is pressed.
8 | Note: this doesn't put the printer into a paused state it simply tells the queue to wait. 9 |

10 | 11 |
12 | 13 |
14 | 15 |
16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 |
24 |
-------------------------------------------------------------------------------- /continuousprint/templates/continuousprint_tab.jinja2: -------------------------------------------------------------------------------- 1 | 4 | 7 | 10 | 11 | 12 |

Continuous Print Queue

13 |
14 |

Select files from the file list to include in the print queue, the print queue will print from top to bottom.

15 |
16 | 17 |

Print Queue

18 |
19 |

20 |

File List

21 | 22 |
23 |
24 |
25 | 26 |
27 |
28 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ### 2 | # This file is only here to make sure that something like 3 | # 4 | # pip install -e . 5 | # 6 | # works as expected. Requirements can be found in setup.py. 7 | ### 8 | 9 | . 10 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | ######################################################################################################################## 4 | ### Do not forget to adjust the following variables to your own plugin. 5 | 6 | # The plugin's identifier, has to be unique 7 | plugin_identifier = "continuousprint" 8 | 9 | # The plugin's python package, should be "octoprint_", has to be unique 10 | plugin_package = "continuousprint" 11 | 12 | # The plugin's human readable name. Can be overwritten within OctoPrint's internal data via __plugin_name__ in the 13 | # plugin module 14 | plugin_name = "continuousprint" 15 | 16 | # The plugin's version. Can be overwritten within OctoPrint's internal data via __plugin_version__ in the plugin module 17 | plugin_version = "1.0.3" 18 | 19 | # The plugin's description. Can be overwritten within OctoPrint's internal data via __plugin_description__ in the plugin 20 | # module 21 | plugin_description = """Allows a print to be restarted after it has complete. Use with ending Gcode to sweep the old print off the bed""" 22 | 23 | # The plugin's author. Can be overwritten within OctoPrint's internal data via __plugin_author__ in the plugin module 24 | plugin_author = "Paul Goddard" 25 | 26 | # The plugin's author's mail address. 27 | plugin_author_email = "nukeem@gmail.com" 28 | 29 | # The plugin's homepage URL. Can be overwritten within OctoPrint's internal data via __plugin_url__ in the plugin module 30 | plugin_url = "https://github.com/nukeem/continuousprint" 31 | 32 | # The plugin's license. Can be overwritten within OctoPrint's internal data via __plugin_license__ in the plugin module 33 | plugin_license = "AGPLv3" 34 | 35 | # Any additional requirements besides OctoPrint should be listed here 36 | plugin_requires = [] 37 | 38 | ### -------------------------------------------------------------------------------------------------------------------- 39 | ### More advanced options that you usually shouldn't have to touch follow after this point 40 | ### -------------------------------------------------------------------------------------------------------------------- 41 | 42 | # Additional package data to install for this plugin. The subfolders "templates", "static" and "translations" will 43 | # already be installed automatically if they exist. Note that if you add something here you'll also need to update 44 | # MANIFEST.in to match to ensure that python setup.py sdist produces a source distribution that contains all your 45 | # files. This is sadly due to how python's setup.py works, see also http://stackoverflow.com/a/14159430/2028598 46 | plugin_additional_data = [] 47 | 48 | # Any additional python packages you need to install with your plugin that are not contained in .* 49 | plugin_additional_packages = [] 50 | 51 | # Any python packages within .* you do NOT want to install with your plugin 52 | plugin_ignored_packages = [] 53 | 54 | # Additional parameters for the call to setuptools.setup. If your plugin wants to register additional entry points, 55 | # define dependency links or other things like that, this is the place to go. Will be merged recursively with the 56 | # default setup parameters as provided by octoprint_setuptools.create_plugin_setup_parameters using 57 | # octoprint.util.dict_merge. 58 | # 59 | # Example: 60 | # plugin_requires = ["someDependency==dev"] 61 | # additional_setup_parameters = {"dependency_links": ["https://github.com/someUser/someRepo/archive/master.zip#egg=someDependency-dev"]} 62 | additional_setup_parameters = {} 63 | 64 | ######################################################################################################################## 65 | 66 | from setuptools import setup 67 | 68 | try: 69 | import octoprint_setuptools 70 | except: 71 | print("Could not import OctoPrint's setuptools, are you sure you are running that under " 72 | "the same python installation that OctoPrint is installed under?") 73 | import sys 74 | sys.exit(-1) 75 | 76 | setup_parameters = octoprint_setuptools.create_plugin_setup_parameters( 77 | identifier=plugin_identifier, 78 | package=plugin_package, 79 | name=plugin_name, 80 | version=plugin_version, 81 | description=plugin_description, 82 | author=plugin_author, 83 | mail=plugin_author_email, 84 | url=plugin_url, 85 | license=plugin_license, 86 | requires=plugin_requires, 87 | additional_packages=plugin_additional_packages, 88 | ignored_packages=plugin_ignored_packages, 89 | additional_data=plugin_additional_data 90 | ) 91 | 92 | if len(additional_setup_parameters): 93 | from octoprint.util import dict_merge 94 | setup_parameters = dict_merge(setup_parameters, additional_setup_parameters) 95 | 96 | setup(**setup_parameters) 97 | --------------------------------------------------------------------------------