Plugin to advance to next file - please advise if there's a better way

I've been working on a plugin to add an API end point to automatically load the next file in the current folder. My use case is that I have an IoT button that I currently have setup that calls the API end point to start printing (so if I have a file currently loaded I can re-print it) and I'd like to add a new end point to move on to the next file (for this particular definition of next) when I double press or hold down the IoT button.

I currently have it working, but this is my first python project and first Octoprint Plugin so I'm just curious if there are better ways to go about what I'm doing.

Thank you for any advice/critiques!

# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

import octoprint.plugin
import flask
import os

class LoadNextFilePlugin(octoprint.plugin.SimpleApiPlugin):
    def on_api_get(self, request):
        if self._printer.is_closed_or_error():
            return flask.jsonify(printer="is_closed_or_error")
        jobData = self._printer.get_current_job()

        if jobData["file"]["path"] != None:
            # we have a job - save some information about the current file
            origin = jobData["file"]["origin"]
            isSD = origin != "local"
            currentPath = jobData["file"]["path"]
            currentName = jobData["file"]["name"]
            currentDisplayName = jobData["file"]["display"]
            currentFolder = os.path.dirname(jobData["file"]["path"])
            # get all the files and folders in the current folder
            folderFilesAndFolders = self._file_manager.list_files(path=currentFolder, recursive=False)[origin]

            # filter the list to have just the files - can't use filter on list_files because it seems to always include folders
            folderFiles = {}
            for key, node in folderFilesAndFolders.items():
                if node["type"] != "folder":
                    folderFiles[key] = node

            # sort the files in the desired manner
            sortedFiles = sorted(folderFiles.keys())

            # figure out the index of the next file (looping)
            currentIndexIntoSorted = sortedFiles.index(currentName)
            nextIndex = currentIndexIntoSorted + 1
            if nextIndex == len(sortedFiles):
                nextIndex = 0

            # store the info for the next file
            nextFileInfo = folderFiles[sortedFiles[nextIndex]]
            nextASCIIName = nextFileInfo["name"]
            nextPath = nextFileInfo["path"]

            # select the file
            self._printer.select_file(nextPath, isSD)

            # update the printer display to let us know it worked
            self._printer.commands("M117 Loaded {0}".format(nextASCIIName))

            responseData = { "old": currentName, "new": nextASCIIName }
            return flask.jsonify(responseData)
            self._printer.commands("M117 No File Loaded")
            return flask.jsonify(noFileCurrentlyLoaded="true")

__plugin_name__ = "LoadNextFile"
__plugin_version__ = "0.1.0"
__plugin_description__ = "Adds an API endpoint to load the next file in the current folder alphabetically"
__plugin_pythoncompat__ = ">=2.7,<4"
__plugin_implementation__ = LoadNextFilePlugin()

The logic looks sound to me. Though instead of using a get request, you should use post. Since get ideally should be used for finding out information, post is for commands. This also enables you to have multiple commands, though the post from the button would be slightly more complex.

There's examples in the docs for simpleAPI plugins.

1 Like