Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-fanficfare for 
openSUSE:Factory checked in at 2026-02-03 21:35:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-fanficfare (Old)
 and      /work/SRC/openSUSE:Factory/.python-fanficfare.new.1995 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-fanficfare"

Tue Feb  3 21:35:51 2026 rev:75 rq:1330811 version:4.53.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-fanficfare/python-fanficfare.changes      
2025-12-02 13:21:33.190370556 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-fanficfare.new.1995/python-fanficfare.changes
    2026-02-03 21:36:41.265695223 +0100
@@ -1,0 +2,22 @@
+Tue Jan 27 16:44:19 UTC 2026 - Matej Cepl <[email protected]>
+
+- Update to the version 4.53.0:
+  - Fix for rare 'false' as INI list corner case
+  - base_xenforo2forum_adapter: Add include_nonauthor_poster
+    option
+  - adapter_storiesonlinenet: Improve inject_chapter_title
+  - writer_epub: Add option as page_progression_direction_rtl
+  - Changes for #1292 for normalizing different series URL forms.
+  - adapter_literotica: Remove unused chapter_categories_use_all
+    option, fix other site options for better defaults.ini
+  - Calc words_added even if not in logpage_entries.
+  - AO3: Site changed 'don't have permission' string
+  - adapter_literotica: Get series ID from data object
+  - adapter_literotica: Add chapter descriptions to summary
+  - adapter_literotica: Don't require tags_from_chapters for old
+    eroticatags collection
+  - adapter_fictionlive: create self.chapter_id_to_api earlier
+    for normalize_chapterurl
+  - adapter_literotica: Fix for one-shot aver_rating
+
+-------------------------------------------------------------------

Old:
----
  FanFicFare-4.52.0.tar.gz

New:
----
  FanFicFare-4.53.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-fanficfare.spec ++++++
--- /var/tmp/diff_new_pack.cLn9Pj/_old  2026-02-03 21:36:41.793717438 +0100
+++ /var/tmp/diff_new_pack.cLn9Pj/_new  2026-02-03 21:36:41.793717438 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-fanficfare
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 %define modnamedown fanficfare
 %define skip_python2 1
 Name:           python-fanficfare
-Version:        4.52.0
+Version:        4.53.0
 Release:        0
 Summary:        Tool for making eBooks from stories on fanfiction and other 
web sites
 License:        GPL-3.0-only

++++++ FanFicFare-4.52.0.tar.gz -> FanFicFare-4.53.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/FanFicFare-4.52.0/calibre-plugin/__init__.py 
new/FanFicFare-4.53.0/calibre-plugin/__init__.py
--- old/FanFicFare-4.52.0/calibre-plugin/__init__.py    2025-12-01 
15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/calibre-plugin/__init__.py    2026-01-01 
16:18:34.000000000 +0100
@@ -33,7 +33,7 @@
 from calibre.customize import InterfaceActionBase
 
 # pulled out from FanFicFareBase for saving in prefs.py
-__version__ = (4, 52, 0)
+__version__ = (4, 53, 0)
 
 ## Apparently the name for this class doesn't matter--it was still
 ## 'demo' for the first few versions.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/FanFicFare-4.52.0/calibre-plugin/plugin-defaults.ini 
new/FanFicFare-4.53.0/calibre-plugin/plugin-defaults.ini
--- old/FanFicFare-4.52.0/calibre-plugin/plugin-defaults.ini    2025-12-01 
15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/calibre-plugin/plugin-defaults.ini    2026-01-01 
16:18:34.000000000 +0100
@@ -1158,6 +1158,11 @@
 ## NOTE: SV requires login (always_login:true) to see dice rolls.
 #include_dice_rolls:false
 
+## If the poster is *not* the author (IE, original poster), include a
+## poster link prepended to the chapter text.
+## Eg: "<p>Chapter by: <a...>ThePoster</a></p>"
+#include_nonauthor_poster:false
+
 [epub]
 
 ## Each output format has a section that overrides [defaults]
@@ -1411,6 +1416,10 @@
 ## under [defaults] or [epub].
 #force_update_epub_always:false
 
+## Mark epub as having right-to-left page progression direction.
+## Useful for RtL languages such as Japanese.
+#page_progression_direction_rtl:false
+
 [html]
 
 ## include images from img tags in the body and summary of
@@ -2293,21 +2302,17 @@
 averrating_label:Average Rating
 extra_titlepage_entries:eroticatags,averrating
 
-## Chapters can be in different categories. Default to not using all
-## to be consistent with previous version.
-chapter_categories_use_all: false
-
 ## For multiple chapter stories, attempt to clean up the chapter title. This 
will
 ## remove the story title and change "Ch. 01" to "Chapter 1", "Pt. 01" to 
"Part 1"
 ## or just use the text. If this can't be done, the full title is used.
-clean_chapter_titles: false
+#clean_chapter_titles: false
 
 ## For stories, collect tags from individual chapter pages in addition to the
 ## series page tags. This allows collection of tags beyond the top 10 on the 
series but 
 ## if the author updates tags on a chapter and not the series, those tags may 
persist even if
 ## the chapter is not fetched during an update.
 ## Default is false to maintain previous behavior.
-tags_from_chapters: false
+#tags_from_chapters: false
 
 ## For multi-chapter stories (series), use the chapter approval dates for 
datePublished
 ## and dateUpdated instead of the series metadata dates. This provides more 
accurate dates
@@ -2316,7 +2321,7 @@
 ## approved, if chapters are approved out of order, or if the works were 
approved/updated
 ## before literotica's current series system was implemented.
 ## Default is false to maintain previous behavior.
-dates_from_chapters: false
+#dates_from_chapters: false
 
 ## Some stories mistakenly include 'Ch' or 'Pt' at the end of the
 ## story title. Appears to be a site bug or common author error.  Copy
@@ -2325,11 +2330,13 @@
 # title=> (Ch|Pt)$=>
 
 ## Add the chapter description at the start of each chapter.
-description_in_chapter: false
+#description_in_chapter: false
 
 ## Author's stories are now hidden behind 'Show More' button.
 ## This option will attemph to fetch the stories.
-fetch_stories_from_api: true
+#fetch_stories_from_api: true
+
+#include_chapter_descriptions_in_summary: false
 
 ## Clear FanFiction from defaults, site is original fiction.
 extratags:Erotica
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/FanFicFare-4.52.0/fanficfare/adapters/adapter_fictionlive.py 
new/FanFicFare-4.53.0/fanficfare/adapters/adapter_fictionlive.py
--- old/FanFicFare-4.52.0/fanficfare/adapters/adapter_fictionlive.py    
2025-12-01 15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/adapters/adapter_fictionlive.py    
2026-01-01 16:18:34.000000000 +0100
@@ -55,6 +55,8 @@
         self.story_id = self.parsedUrl.path.split('/')[3]
         self.story.setMetadata('storyId', self.story_id)
 
+        self.chapter_id_to_api = {}
+
         # normalize URL. omits title in the url
         self._setURL("https://fiction.live/stories//{s_id}".format(s_id = 
self.story_id));
 
@@ -222,8 +224,6 @@
         ## api url to get content of a multi route chapter. requires only the 
route id and no timestamps
         route_chunkrange_url = 
"https://fiction.live/api/anonkun/route/{c_id}/chapters";
 
-        self.chapter_id_to_api = {}
-
         def add_chapter_url(title, bounds):
             "Adds a chapter url based on the start/end chunk-range timestamps."
             start, end = bounds
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/FanFicFare-4.52.0/fanficfare/adapters/adapter_literotica.py 
new/FanFicFare-4.53.0/fanficfare/adapters/adapter_literotica.py
--- old/FanFicFare-4.52.0/fanficfare/adapters/adapter_literotica.py     
2025-12-01 15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/adapters/adapter_literotica.py     
2026-01-01 16:18:34.000000000 +0100
@@ -19,6 +19,7 @@
 import logging
 logger = logging.getLogger(__name__)
 import re
+import json
 
 from bs4.element import Comment
 from ..htmlcleanup import stripHTML
@@ -194,8 +195,18 @@
 
         isSingleStory = '/series/se' not in self.url
 
-        ## common between one-shots and multi-chapters
+        if not isSingleStory:
+            # Normilize the url?
+            state = re.findall(r"prefix\=\"/series/\",state='(.+?)'</script>", 
data)
+            json_state = 
json.loads(state[0].replace("\\'","'").replace("\\\\","\\"))
+            url_series_id = 
unicode(re.match(self.getSiteURLPattern(),self.url).group('storyseriesid'))
+            json_series_id = unicode(json_state['series']['data']['id'])
+            if json_series_id != url_series_id:
+                res = re.sub(url_series_id, json_series_id, unicode(self.url))
+                logger.debug("Normalized url: %s"%res)
+                self._setURL(res)
 
+        ## common between one-shots and multi-chapters
         # title
         self.story.setMetadata('title', stripHTML(soup.select_one('h1')))
         # logger.debug(self.story.getMetadata('title'))
@@ -225,31 +236,29 @@
         else: # if all else fails
             self.story.setMetadata('authorId', stripHTML(authora))
 
-        ## Collect tags from series/story page if tags_from_chapters is enabled
-        if self.getConfig("tags_from_chapters"):
-            if soup.select('div#tabpanel-tags'):
-                # logger.debug("tags1")
-                self.story.extendList('eroticatags', [ stripHTML(t).title() 
for t in soup.select('div#tabpanel-tags a.av_as') ])
-            if soup.select('div[class^="_widget__tags_"]'):
-                # logger.debug("tags2")
-                self.story.extendList('eroticatags', [ stripHTML(t).title() 
for t in soup.select('div[class^="_widget__tags_"] a[class^="_tags__link_"]') ])
+        if soup.select('div#tabpanel-tags'):
+            # logger.debug("tags1")
+            self.story.extendList('eroticatags', [ stripHTML(t).title() for t 
in soup.select('div#tabpanel-tags a.av_as') ])
+        if soup.select('div[class^="_widget__tags_"]'):
+            # logger.debug("tags2")
+            self.story.extendList('eroticatags', [ stripHTML(t).title() for t 
in soup.select('div[class^="_widget__tags_"] a[class^="_tags__link_"]') ])
         # logger.debug(self.story.getList('eroticatags'))
 
         ## look first for 'Series Introduction', then Info panel short desc
         ## series can have either, so put in common code.
+        desc = []
         introtag = soup.select_one('div.bp_rh')
-        descdiv = soup.select_one('div#tabpanel-info div.bn_B')
-        if not descdiv:
-            descdiv = soup.select_one('div[class^="_tab__pane_"] 
div[class^="_widget__info_"]')
+        descdiv = soup.select_one('div#tabpanel-info div.bn_B') or \
+                  soup.select_one('div[class^="_tab__pane_"] 
div[class^="_widget__info_"]')
         if introtag and stripHTML(introtag):
             # make sure there's something in the tag.
             # logger.debug("intro %s"%introtag)
-            self.setDescription(self.url,introtag)
+            desc.append(unicode(introtag))
         elif descdiv and stripHTML(descdiv):
             # make sure there's something in the tag.
             # logger.debug("desc %s"%descdiv)
-            self.setDescription(self.url,descdiv)
-        else:
+            desc.append(unicode(descdiv))
+        if not desc or 
self.getConfig("include_chapter_descriptions_in_summary"):
             ## Only for backward compatibility with 'stories' that
             ## don't have an intro or short desc.
             descriptions = []
@@ -259,7 +268,9 @@
                 descriptions.append("%d. %s" % (i + 1, 
stripHTML(chapterdesctag)))
                 # now put it back--it's used below
                 chapterdesctag.append(a)
-            
self.setDescription(authorurl,"<p>"+"</p>\n<p>".join(descriptions)+"</p>")
+            desc.append(unicode("<p>"+"</p>\n<p>".join(descriptions)+"</p>"))
+
+        self.setDescription(self.url,u''.join(desc))
 
         if isSingleStory:
             ## one-shots don't *display* date info, but they have it
@@ -276,6 +287,12 @@
                 self.story.setMetadata('datePublished', dateval)
                 self.story.setMetadata('dateUpdated', dateval)
 
+            ## one-shots don't have same json data to get aver_rating
+            ## from below. This kludge matches the data_approve
+            rateall = re.search(r'rate_all:([\d\.]+)',data)
+            if rateall:
+                self.story.setMetadata('averrating', '%4.2f' % 
float(rateall.group(1)))
+
             ## one-shots assumed completed.
             self.story.setMetadata('status','Completed')
 
@@ -341,15 +358,10 @@
                 state = 
data[i+len(state_start):data.index(state_end,i)].replace("\\'","'").replace("\\\\","\\")
                 if state:
                     # logger.debug(state)
-                    import json
                     json_state = json.loads(state)
                     # logger.debug(json.dumps(json_state, 
sort_keys=True,indent=2, separators=(',', ':')))
                     all_rates = []
-                    ## one-shot
-                    if 'story' in json_state:
-                        all_rates = [ 
float(json_state['story']['data']['rate_all']) ]
-                    ## series
-                    elif 'series' in json_state:
+                    if 'series' in json_state:
                         all_rates = [ float(x['rate_all']) for x in 
json_state['series']['works'] ]
 
                         ## Extract dates from chapter approval dates if 
dates_from_chapters is enabled
@@ -372,7 +384,7 @@
                     ## alternate chapters from JSON
                     if self.num_chapters() < 1:
                         logger.debug("Getting Chapters from series JSON")
-                        seriesid = 
json_state.get('series',{}).get('coversSeriesId',None)
+                        seriesid = 
json_state.get('series',{}).get('data',{}).get('id',None)
                         if seriesid:
                             logger.info("Fetching chapter data from JSON")
                             logger.debug(seriesid)
@@ -471,8 +483,8 @@
 
         page_urls = get_urls_from_html(soup, url, 
configuration=self.configuration, normalize=normalize)
 
-        if not self.getConfig("fetch_stories_from_api"):
-            logger.debug('Not enabled')
+        if not self.getConfig("fetch_stories_from_api",True):
+            logger.debug('fetch_stories_from_api Not enabled')
             return {'urllist': page_urls}
 
         user_story_list = 
re.search(r'literotica\.com/authors/.+?/lists\?listid=(?P<list_id>\d+)', url)
@@ -543,7 +555,6 @@
             logger.debug("Type of works not found")
             return {'urllist': urls}
 
-        import json
         last_page = int(js_story_list.group('last_page'))
         current_page = int(js_story_list.group('current_page')) + 1
         # Fetching the remaining urls from api. Can't trust the number given 
about the pages left from a website. Sometimes even the api returns outdated 
number of pages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/FanFicFare-4.52.0/fanficfare/adapters/adapter_storiesonlinenet.py 
new/FanFicFare-4.53.0/fanficfare/adapters/adapter_storiesonlinenet.py
--- old/FanFicFare-4.52.0/fanficfare/adapters/adapter_storiesonlinenet.py       
2025-12-01 15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/adapters/adapter_storiesonlinenet.py       
2026-01-01 16:18:34.000000000 +0100
@@ -628,11 +628,13 @@
 
         chapter_title = None
         if self.getConfig('inject_chapter_title'):
-            h2tag = pagetag.find('h2')
-            if h2tag:
-                # I'm seeing an h1 now, but it's not logged in?
-                # Something's broken...
-                chapter_title = h2tag.extract()
+            if self.num_chapters() > 1:
+                cttag = pagetag.find('h2')
+            else:
+                ## single chapter stories formatted a little differently.
+                cttag = pagetag.find('h1')
+            if cttag:
+                chapter_title = cttag.extract()
 
         # Strip te header section
         tag = pagetag.find('header')
@@ -714,4 +716,5 @@
         # inject_chapter_title
         if chapter_title:
             chapter_title.name='h3'
+            chapter_title['class']='inject_chapter_title'
             pagetag.insert(0,chapter_title)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/FanFicFare-4.52.0/fanficfare/adapters/base_otw_adapter.py 
new/FanFicFare-4.53.0/fanficfare/adapters/base_otw_adapter.py
--- old/FanFicFare-4.52.0/fanficfare/adapters/base_otw_adapter.py       
2025-12-01 15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/adapters/base_otw_adapter.py       
2026-01-01 16:18:34.000000000 +0100
@@ -237,7 +237,7 @@
         if 'This work is part of an ongoing challenge and will be revealed 
soon!' in meta:
             raise exceptions.FailedToDownload('Site says: "This work is part 
of an ongoing challenge and will be revealed soon!"')
 
-        if '<div class="flash error">Sorry, you don&#39;t have permission to 
access the page you were trying to reach.</div>' in data:
+        if re.search(r'<div class="flash error">Sorry, you don(\'|&#39;)t have 
permission to access the page you were trying to reach.</div>', data):
             # note that it's not *actually* a 503 code...
             raise exceptions.FailedToDownload('Site says: "Sorry, you don\'t 
have permission to access the page you were trying to reach."')
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/FanFicFare-4.52.0/fanficfare/adapters/base_xenforo2forum_adapter.py 
new/FanFicFare-4.53.0/fanficfare/adapters/base_xenforo2forum_adapter.py
--- old/FanFicFare-4.52.0/fanficfare/adapters/base_xenforo2forum_adapter.py     
2025-12-01 15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/adapters/base_xenforo2forum_adapter.py     
2026-01-01 16:18:34.000000000 +0100
@@ -966,6 +966,28 @@
 
         postbody = self.get_post_body(souptag)
 
+        if self.getConfig("include_nonauthor_poster"):
+            poster_atag = souptag.select_one('div.message-userDetails 
a.username')
+            # logger.debug(stripHTML(poster_atag))
+            if True or stripHTML(poster_atag) not in 
self.story.getList('author'):
+                ## <div class="message-userDetails"> <h4
+                ## class="message-name"><a class="username"
+                ## 
href="https://forums.spacebattles.com/members/stargazingseraph.561651/";><span
+                ## class="username--style476">StargazingSeraph</span></a></h4>
+                if not topsoup:
+                    ## only top of soup has new_tag, and parents is a
+                    ## generator not a list.
+                    topsoup = [x for x in souptag.parents][-1]
+                poster = topsoup.new_tag('p')
+                poster['class']='poster'
+                poster.string="Chapter by: "
+                poster.append(poster_atag)
+
+                # logger.debug(poster)
+                postbody.insert(0,"\n")
+                postbody.insert(0,poster)
+                postbody.insert(0,"\n")
+
         # XenForo uses <base href="https://forums.spacebattles.com/"; />
         return self.utf8FromSoup(self.getURLPrefix(),postbody)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/FanFicFare-4.52.0/fanficfare/cli.py 
new/FanFicFare-4.53.0/fanficfare/cli.py
--- old/FanFicFare-4.52.0/fanficfare/cli.py     2025-12-01 15:25:22.000000000 
+0100
+++ new/FanFicFare-4.53.0/fanficfare/cli.py     2026-01-01 16:18:34.000000000 
+0100
@@ -28,7 +28,7 @@
 import os, sys, platform
 
 
-version="4.52.0"
+version="4.53.0"
 os.environ['CURRENT_VERSION_ID']=version
 
 global_cache = 'global_cache'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/FanFicFare-4.52.0/fanficfare/configurable.py 
new/FanFicFare-4.53.0/fanficfare/configurable.py
--- old/FanFicFare-4.52.0/fanficfare/configurable.py    2025-12-01 
15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/configurable.py    2026-01-01 
16:18:34.000000000 +0100
@@ -208,7 +208,6 @@
                'remove_empty_p':(None,None,boollist),
                'sort_ships':(None,None,boollist),
                'strip_chapter_numbers':(None,None,boollist),
-               'remove_class_chapter':(None,None,boollist),
                'mark_new_chapters':(None,None,boollist+['latestonly']),
                'titlepage_use_table':(None,None,boollist),
                'decode_emails':(None,None,boollist),
@@ -264,13 +263,13 @@
                
'romancecat_to_characters_ships':(['tthfanfic.org'],None,boollist),
 
                'use_meta_keywords':(['literotica.com'],None,boollist),
-               'chapter_categories_use_all':(['literotica.com'],None,boollist),
                'clean_chapter_titles':(['literotica.com'],None,boollist),
                'description_in_chapter':(['literotica.com'],None,boollist),
                'fetch_stories_from_api':(['literotica.com'],None,boollist),
                'order_chapters_by_date':(['literotica.com'],None,boollist),
                'tags_from_chapters':(['literotica.com'],None,boollist),
                'dates_from_chapters':(['literotica.com'],None,boollist),
+               
'include_chapter_descriptions_in_summary':(['literotica.com'],None,boollist),
 
                
'inject_chapter_title':(['asianfanfics.com']+wpc_list,None,boollist),
                'inject_chapter_image':(['asianfanfics.com'],None,boollist),
@@ -288,6 +287,7 @@
 
                'calibre_series_meta':(None,['epub'],boollist),
                'force_update_epub_always':(None,['epub'],boollist),
+               'page_progression_direction_rtl':(None,['epub'],boollist),
 
                'windows_eol':(None,['txt'],boollist),
 
@@ -325,6 +325,7 @@
                'use_threadmarks_cover':(base_xenforo2_list,None,boollist),
                'skip_sticky_first_posts':(base_xenforo2_list,None,boollist),
                'include_dice_rolls':(base_xenforo2_list,None,boollist+['svg']),
+               'include_nonauthor_poster':(base_xenforo2_list,None,boollist),
                'include_chapter_banner_images':(['wattpad.com'],None,boollist),
                'dateUpdated_method':(['wattpad.com'],None,['modifyDate', 
'lastPublishedPart']),
                'fix_excess_space': (['novelonlinefull.com', 'novelall.com'], 
['epub', 'html'], boollist),
@@ -461,6 +462,7 @@
                  'logpage_at_end',
                  'calibre_series_meta',
                  'force_update_epub_always',
+                 'page_progression_direction_rtl',
                  'include_subject_tags',
                  'include_titlepage',
                  'include_tocpage',
@@ -520,7 +522,6 @@
                  'pairingcat_to_characters_ships',
                  'romancecat_to_characters_ships',
                  'use_meta_keywords',
-                 'chapter_categories_use_all',
                  'clean_chapter_titles',
                  'conditionals_use_lists',
                  'description_in_chapter',
@@ -528,6 +529,7 @@
                  'fetch_stories_from_api',
                  'tags_from_chapters',
                  'dates_from_chapters',
+                 'include_chapter_descriptions_in_summary',
                  'inject_chapter_title',
                  'inject_chapter_image',
                  'append_datepublished_to_storyurl',
@@ -606,6 +608,7 @@
                  'use_threadmarks_cover',
                  'skip_sticky_first_posts',
                  'include_dice_rolls',
+                 'include_nonauthor_poster',
                  'include_chapter_banner_images',
                  'dateUpdated_method',
                  'datethreadmark_format',
@@ -817,7 +820,8 @@
 
     # split and strip each.
     def get_config_list(self, sections, key, default=[]):
-        vlist = re.split(r'(?<!\\),',self.get_config(sections,key)) # don't 
split on \,
+        ## "%s" to make false > "false"  Rare corner case, probably accidental
+        vlist = re.split(r'(?<!\\),',"%s"%self.get_config(sections,key)) # 
don't split on \,
         vlist = [x for x in [ v.strip().replace(r'\,',',') for v in vlist ] if 
x !='']
         if not vlist:
             return default
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/FanFicFare-4.52.0/fanficfare/defaults.ini 
new/FanFicFare-4.53.0/fanficfare/defaults.ini
--- old/FanFicFare-4.52.0/fanficfare/defaults.ini       2025-12-01 
15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/defaults.ini       2026-01-01 
16:18:34.000000000 +0100
@@ -1148,6 +1148,11 @@
 ## NOTE: SV requires login (always_login:true) to see dice rolls.
 #include_dice_rolls:false
 
+## If the poster is *not* the author (IE, original poster), include a
+## poster link prepended to the chapter text.
+## Eg: "<p>Chapter by: <a...>ThePoster</a></p>"
+#include_nonauthor_poster:false
+
 [epub]
 
 ## Each output format has a section that overrides [defaults]
@@ -1399,6 +1404,10 @@
 ## under [defaults] or [epub].
 #force_update_epub_always:false
 
+## Mark epub as having right-to-left page progression direction.
+## Useful for RtL languages such as Japanese.
+#page_progression_direction_rtl:false
+
 [html]
 
 ## include images from img tags in the body and summary of
@@ -2286,21 +2295,17 @@
 averrating_label:Average Rating
 extra_titlepage_entries:eroticatags,averrating
 
-## Chapters can be in different categories. Default to not using all
-## to be consistent with previous version.
-chapter_categories_use_all: false
-
 ## For multiple chapter stories, attempt to clean up the chapter title. This 
will
 ## remove the story title and change "Ch. 01" to "Chapter 1", "Pt. 01" to 
"Part 1"
 ## or just use the text. If this can't be done, the full title is used.
-clean_chapter_titles: false
+#clean_chapter_titles: false
 
 ## For stories, collect tags from individual chapter pages in addition to the
 ## series page tags. This allows collection of tags beyond the top 10 on the 
series but 
 ## if the author updates tags on a chapter and not the series, those tags may 
persist even if
 ## the chapter is not fetched during an update.
 ## Default is false to maintain previous behavior.
-tags_from_chapters: false
+#tags_from_chapters: false
 
 ## For multi-chapter stories (series), use the chapter approval dates for 
datePublished
 ## and dateUpdated instead of the series metadata dates. This provides more 
accurate dates
@@ -2309,7 +2314,7 @@
 ## approved, if chapters are approved out of order, or if the works were 
approved/updated
 ## before literotica's current series system was implemented.
 ## Default is false to maintain previous behavior.
-dates_from_chapters: false
+#dates_from_chapters: false
 
 ## Some stories mistakenly include 'Ch' or 'Pt' at the end of the
 ## story title. Appears to be a site bug or common author error.  Copy
@@ -2318,11 +2323,13 @@
 # title=> (Ch|Pt)$=>
 
 ## Add the chapter description at the start of each chapter.
-description_in_chapter: false
+#description_in_chapter: false
 
 ## Author's stories are now hidden behind 'Show More' button.
 ## This option will attemph to fetch the stories.
-fetch_stories_from_api: true
+#fetch_stories_from_api: true
+
+#include_chapter_descriptions_in_summary: false
 
 ## Clear FanFiction from defaults, site is original fiction.
 extratags:Erotica
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/FanFicFare-4.52.0/fanficfare/writers/writer_epub.py 
new/FanFicFare-4.53.0/fanficfare/writers/writer_epub.py
--- old/FanFicFare-4.52.0/fanficfare/writers/writer_epub.py     2025-12-01 
15:25:22.000000000 +0100
+++ new/FanFicFare-4.53.0/fanficfare/writers/writer_epub.py     2026-01-01 
16:18:34.000000000 +0100
@@ -294,13 +294,12 @@
 
         retval = START.substitute(self.story.getAllMetadata())
 
-        ## words_added is only used in logpage because it's the only
-        ## place we know the previous version's word count.
-        if 'words_added' in (self.getConfigList("logpage_entries") + 
self.getConfigList("extra_logpage_entries")):
-            new_words = self.story.getMetadata('numWords')
-            old_words = oldvalues.get('numWords',None)
-            if new_words and old_words:
-                
self.story.setMetadata('words_added',commaGroups(unicode(int(new_words.replace(',',''))-int(old_words.replace(',','')))))
+        ## words_added is calculated from logpage because it's the
+        ## only place we know the previous version's word count.
+        new_words = self.story.getMetadata('numWords')
+        old_words = oldvalues.get('numWords',None)
+        if new_words and old_words:
+            
self.story.setMetadata('words_added',commaGroups(unicode(int(new_words.replace(',',''))-int(old_words.replace(',','')))))
 
         for entry in self.getConfigList("logpage_entries") + 
self.getConfigList("extra_logpage_entries"):
             if self.isValidMetaEntry(entry):
@@ -816,6 +815,8 @@
 
 
         spine = newTag(contentdom,"spine",attrs={"toc":"ncx"})
+        if self.getConfig('page_progression_direction_rtl'):
+            spine.setAttribute("page-progression-direction","rtl")
         package.appendChild(spine)
         for itemref in itemrefs:
             spine.appendChild(newTag(contentdom,"itemref",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/FanFicFare-4.52.0/pyproject.toml 
new/FanFicFare-4.53.0/pyproject.toml
--- old/FanFicFare-4.52.0/pyproject.toml        2025-12-01 15:25:22.000000000 
+0100
+++ new/FanFicFare-4.53.0/pyproject.toml        2026-01-01 16:18:34.000000000 
+0100
@@ -16,7 +16,7 @@
 #
 # For a discussion on single-sourcing the version, see
 # https://packaging.python.org/guides/single-sourcing-package-version/
-version = "4.52.0"
+version = "4.53.0"
 
 # This is a one-line description or tagline of what your project does. This
 # corresponds to the "Summary" metadata field:

Reply via email to