View Single Post
Old 11-02-2025, 03:52 PM   #6
bluefish2020
Junior Member
bluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead communitybluefish2020 has become a pillar of the MobileRead community
 
bluefish2020's Avatar
 
Posts: 3
Karma: 15972
Join Date: Mar 2025
Device: kindle oasis
I do something close to that using an Action Chain similar to this code:

Code:
from calibre_plugins.action_chains.actions.base import ChainAction

class MarkLastBookInSeriesAction(ChainAction):
    name = 'Mark Last Book In Series'

    def run(self, gui, settings, chain):
        db = gui.current_db
        api = gui.current_db.new_api

        book_ids = {}
        series_names = api.all_field_names('series')

        for series_name in series_names:
            series_id = api.get_item_id('series', series_name)
            books_in_series = api.books_for_field('series', series_id)
            print(f"loaded {len(books_in_series)} books in series {series_name}")
            book_id = self.last_book_in_series(api, books_in_series)
            mark = 'last_book' if len(books_in_series) > 1 else 'only_book'
            if book_id:
                book_ids.update({book_id: mark})

        db.set_marked_ids(book_ids)
        # in practice setting the search likely belongs in its own link of the chain but this makes it less complicated to explain
        gui.search.setEditText('marked:true')
        gui.search.do_search()

    def last_book_in_series(self, api, books_in_series):       
        indexes = api.all_field_for("series_index", books_in_series, None)

        # primary works vs short stories...
        # if 11.0 and 11.1 exist, do we really want the 11.1? probably not.
        # also, ignore anything under 1. omnibus and prequels etc.
        last_primary_work = None
        last_minor_work = None
        any_work = None

        for book_id, i in sorted(indexes.items(), key=lambda kv: (kv[1], kv[0]), reverse=True):
            if any_work is None:
                any_work = book_id
            if i < 1.0:
                continue
            if i.is_integer():
                if last_primary_work is None:
                    last_primary_work = book_id  # it would be safe to just return this now
            else:
                if last_minor_work is None:
                    last_minor_work = book_id

        return last_primary_work or last_minor_work or any_work
bluefish2020 is offline   Reply With Quote