View Full Version : Getting custom metadata field in GUI plugin
02-10-2012, 10:41 AM
Recently I have started to use Calibre to transfer files to Kindle and found that APNX file is generated and books have "page numbers". However, APNX generator by John Schember is calculating page numbers in it's own algorithms.
I myself want a possibility to provide page number to the generator myself. Contacted John with few questions, but he did not want to waste his time, so simply gave me sources. I have no knowledge with Python at all, but have an idea about coding so changed his plugin so far, that I can enter desired page count for a book and generate appropriate APNX file.
Unfortunately, page count is hardcoded, so for any book I am going to read I need to change and reload the plugin. Silly way, of course.
So I want to enhance that plugin in the following way: add custom metadata field, call it "Page Count" and put page count of appropriate book into it. When I select that book and then click "Generate APNX File", plugin should read the value from that field and use it for APNX generation.
As I am unfamiliar with Calibre internals, could you please give me simple source example: what to import, how to get the metadata object for selected book(s) and how to read particular custom metadata column.
02-10-2012, 12:09 PM
There are plenty of examples in the plugins forum if you look at other plugins that work with custom columns, like Reading List, Count Pages, Goodreads Sync that spring to mind.
For instance if you look at the Reading List plugin, in action.py there is an "apply_tags_to_list" function which in that particular case will apply a value to either the tags column or a custom column, depending on which the user has configured. It also reads the value of that column first, using db.get_custom(). In config.py you will find code related to the preferences for the plugin which allow the user to specify which custom column they want updated (something you will want to do for your changes to the APNX plugin as well), so that shows how to get a list of available custom columns by type.
It would also be nice to see the changes you make to the GUI standalone plugin being applied to the file type plugin that ships with Calibre. So that way when people send books to their Kindles using Send to device, it can pull the value from a custom column in the same way (the GUI plugin you mention wouldn't normally be used by people who actually own a Kindle). As I wrote on the Count pages plugin thread, if that functionality was available I might be motivated to support Count Pages pulling page numbers from a website like Goodreads or Amazon as an alternative to estimating by various count algorithms.
If the only reason John didn't do this previously was due to lack of time I don't mind making the changes myself. There is one technical issue with a file type plugin, in that it ordinarily does not have access to the db object (unlike GUI plugins which do through self.gui.current_db). However that can be circumvented with an import that Kovid added a number of months ago to allow any piece of code to get access to the "current" db.
@Kovid - did John discuss this with you at all/do you have any objections to me making the additions to that file type plugin?
Alternatively Saulius - if you want to do both I am happy to leave them both in your hands. I didn't volunteer previously because the plugins were John's work, but since I know he is working hard on Sigil it is all likely pretty low on his priority list.
02-10-2012, 12:18 PM
File type plugins really should not be accessing the GUI. Nor should they need to, the custom metadata will be available in the mi object. In this case, the changes would have to be made to the kindle driver plugin, not a file type plugin. The relevant function is upload_cover (which john hijacked to upload the apnx file instead). IIRC this function is passed a metadata object, so all you need now is a modification to add a preference to the kindle driver that will allow users to specify which column should be used for this information.
I have no objections to this in principle (I might have technical ones when I see an implementation, but those can be fixed).
02-10-2012, 12:49 PM
Cheers Kovid, sorry for mentioning a "file type" plugin, was typing from work without the calibre code in front of me so was relying on my bad memory :)
When I PM'd John about this ages ago he did wonder about there being a problem getting access to the custom columns from that plugin, hence my comments. However it could well be he also was speculating off the top of his head and I have just perputated a myth :). As you say with a metadata object there isn't really an issue.
I'll have a look on the weekend then if you aren't against the idea in principle.
@SauliusP - if you aren't in a desperate rush, you might just want to wait a day or so for me to knock this up and then just copy the relevant bits of the implementation.
02-10-2012, 02:05 PM
Hi, thank you for quick response.
Kiwidude, if you could take that plugin (and APNXBuilder itself, which works when MOBI is sent to Kindle) and add the functionality of taking page count from custom metadata column, that would be tremendous. I would simple spend two or three months on that and don't think it is worth it.
So far, some "hacking" I've already done and will attach what I've got.
I have implemented, as I've said, quick and dirty solution, with hard-coded page count. I have also copied the source of APNXBuilder into plugin's source file, as it is the "file type" kiwidude mentioned and I had to add one more method to it, which would accept page count as an argument. That method I've called get_pages_exact. So APNXBuilder, before calling this method, should also take page count from some user-defined column. You'll find two places in the code, where that method is called, with hardcoded value of 349 (last book I have planned to read has this count of pages).
plugin_apnx_generator-1.1.0.zip: John's original plugin.
apnx-generator-exact.zip: my "quick'n'dirty" solution. However, I think, that get_pages_exact is quite in acceptable shape to be put into official source.
As a workflow, I would imagine this:
1. MOBI file is sent to Kindle.
2. APNXBuilder is called to create APNX file (as it is now, too)
3. Default action: try to read page count from user-defined column, probably, default name "Page Count".
4. If "Page Count" reading fails (0 or null value or column not created by user), try get_pages_accurate (Default method by John).
5. If accurate fails, call get_pages_fast.
All above three methods do not write anything, just generate an array of locations in MOBI file. Array member count matches that of the pages.
As additional functionality for GUI plugin, there might be even another action, i.e. possibility to enter page count via dialogue, in case custom column is not defined, but you just want to do it right away.
02-10-2012, 04:35 PM
Ok, had a quick dabble tonight, was less work than I imagined, mainly because the options for UI for device plugins is fairly limited ;)
Attached is a patch file Kovid. I leave it to you to change the descriptions etc if you have a better way of expressing it. The behaviour is that if a valid custom column name is specified in the Kindle device configuration, *and* it has a non-zero value in it, then that page count will go to the Kindle. Otherwise it falls back to the existing behaviour of computing a count.
02-11-2012, 12:53 AM
02-11-2012, 02:31 AM
Great, thank you, guys. So this will be in the next a Friday's release? Ahh, waiting for it!