Import Json API

Hello, I’m an interessted in creating a Json API for the import. For this I implementet a custom ImportSession, recording every task in choose_match while skipping them. This is used to build a list of found matches and required decisions for the user.

But now I have the problem of importing one of the matches, with the descision of the user, after the Session is finished. Is there a good solution for this already or how could this be solved without changeing to much of the current way imports work?

Wow; that’s quite ambitious! Is your eventual goal here to build a new user interface on top of that JSON API? Sounds cool.

The problem you printed out—i.e., “reviving” an import task asynchronously, perhaps after beets itself has terminated—is indeed the hard part. There will be no easy way around this. There might, however, be several hard ways to do it. You might find these issue threads enlightening:
https://github.com/beetbox/beets/issues/3073 https://github.com/beetbox/beets/issues/736

I think the thing you’ll need to do is create a way to serialize an ImportTask and reconstitute it later as part of a new session. Does that make sense?

Thanks for the info! A web interface is not my direct goal, as im not really good at frontend development xD
My first goal is to just implement the api, so its possible to run imports remotely without ssh.

For an easy beginning I think I will just save the ImportTasks in memory, solving persistence when the import is working. As for the import I plan to override the run method to only read tasks, look up the canditates and then implement an new pipeline stage that saves the tasks.
Then I will write a function to update a task according to some user input from an endpoint.
What I still need to find is the point in the normal pipeline from which i should continue to apply the choice for a task and import it to the database, especially when it comes to plugins.

1 Like

Got it. It seems like you’ll want to set up an import pipeline that only has the last few stages, after a decision is made. If you look at ImportSession.run, you can see the standard order in which stages are run:

For your purposes, I think you’ll want to include everything after user_query—crucially, the plugin stages and manipulate_files. But before injecting things back into the pipeline, you’ll probably want to call apply_choice to save things back to the database:

In general, the design is such that pipeline stages never really have “in-flight” changes to Album and Item objects that are not saved to the database. Each stage is responsible for calling store to ensure that updates are persisted.

I was thinking the other day that storing import jobs as their own objects in the DB might actually be useful. The imports table would store import job records, keeping track of original directory, command line options passed in, the match choice, status, etc.

Typical use cases would include being able to run an initial import of a large collection of music while setting quiet and timid, and come back and query for any import jobs where the autotagger wants your input. Or alternatively, you could query for import jobs that are completed, but where the original imports originated in a particular directory.

Each album and item would also record which import job it originated with. You could query the library to determine which import job a given file was originally associated with.

Perhaps this would be best as a separate thread, but this would certainly lend itself towards a web dashboard for imports in the future.

I actually started building the webinterface for the import. It is in a very rudimentary state, but if you want to take a look you can find it in my fork (https://github.com/MrNuggelz/beets/tree/ImportWebInterface)
There is a list of things that i think should be done before a release:

  • Implement Search by Artist and Album as well as by Id
  • Choosing different candidates
  • Display difference/changes like its done in the console
  • Handle existing Albums/Tracks (merge, delete etc.)
  • Saving ImportTasks in the database
1 Like