diff --git a/sites/__init__.py b/sites/__init__.py index bbc62fe..29904df 100644 --- a/sites/__init__.py +++ b/sites/__init__.py @@ -116,13 +116,30 @@ def get_site_specific_option_defs(): # default=True, help="If true, images embedded in the story will be downloaded" ), + SiteSpecificOption( + 'spoilers', + '--spoilers', + choices=('include', 'inline', 'skip'), + default='include', + help="Whether to include spoilers" + ), + SiteSpecificOption( + 'deprecated_skip_spoilers', + '--skip-spoilers/--include-spoilers', + help="If true, do not transcribe any tags that are marked as a spoiler. (DEPRECATED)", + exposed=False, + click_kwargs={ + "callback": lambda ctx, param, value: ctx.params.update({"spoilers": value and "skip" or "include"}), + }, + ), ] @classmethod def get_default_options(cls): options = {} for option in cls.get_site_specific_option_defs(): - options[option.name] = option.default + if option.exposed: + options[option.name] = option.default return options @classmethod @@ -134,8 +151,8 @@ def interpret_site_specific_options(cls, **kwargs): """ options = {} for option in cls.get_site_specific_option_defs(): - option_value = kwargs[option.name] - if option_value is not None: + option_value = kwargs.get(option.name) + if option.exposed and option_value is not None: options[option.name] = option_value return options @@ -289,7 +306,7 @@ def _clean(self, contents, base=False): return contents -@define(unsafe_hash=True, frozen=True) +@define class SiteSpecificOption: """Represents a site-specific option that can be configured. @@ -300,18 +317,29 @@ class SiteSpecificOption: type: object = None default: bool = False help: str = None + choices: tuple = None + exposed: bool = True + click_kwargs: frozenset = field(converter=lambda kwargs: frozenset(kwargs.items()), default={}) + + def __eq__(self, other): + return self.name == other.name + + def __hash__(self): + return hash(self.name) def as_click_option(self): return click.option( str(self.name), str(self.flag_pattern), - type=self.type, + type=self.choices and click.Choice(self.choices) or self.type, # Note: This default not matching self.default is intentional. # It ensures that we know if a flag was explicitly provided, # which keeps it from overriding options set in leech.json etc. # Instead, default is used in site_cls.get_default_options() default=None, - help=self.help if self.help is not None else "" + help=self.help if self.help is not None else "", + expose_value=self.exposed, + **dict(self.click_kwargs) ) diff --git a/sites/royalroad.py b/sites/royalroad.py index 771045d..a640dc9 100644 --- a/sites/royalroad.py +++ b/sites/royalroad.py @@ -16,12 +16,6 @@ class RoyalRoad(Site): @staticmethod def get_site_specific_option_defs(): return Site.get_site_specific_option_defs() + [ - SiteSpecificOption( - 'skip_spoilers', - '--skip-spoilers/--include-spoilers', - default=True, - help="If true, do not transcribe any tags that are marked as a spoiler." - ), SiteSpecificOption( 'offset', '--offset', @@ -123,14 +117,18 @@ def _clean_spoilers(self, content, chapterid): # Spoilers to footnotes for spoiler in content.find_all(class_=('spoiler-new')): spoiler_title = spoiler.get('data-caption') - if self.options['skip_spoilers']: + new_spoiler = self._new_tag('div', class_="leech-spoiler") + if self.options['spoilers'] == 'skip': + new_spoiler.append(spoiler_title and f'[SPOILER: {spoiler_title}]' or '[SPOILER]') + elif self.options['spoilers'] == 'inline': + if spoiler_title: + new_spoiler.append(f"{spoiler_title}: ") + new_spoiler.append(spoiler) + else: link = self._footnote(spoiler, chapterid) if spoiler_title: link.string = spoiler_title - else: - link = spoiler_title and f'[SPOILER: {spoiler_title}]' or '[SPOILER]' - new_spoiler = self._new_tag('div', class_="leech-spoiler") - new_spoiler.append(link) + new_spoiler.append(link) spoiler.replace_with(new_spoiler) diff --git a/sites/xenforo.py b/sites/xenforo.py index b71c553..324925b 100644 --- a/sites/xenforo.py +++ b/sites/xenforo.py @@ -27,12 +27,6 @@ def get_site_specific_option_defs(): default=False, help="If true, the post marked as an index will be included as a chapter." ), - SiteSpecificOption( - 'skip_spoilers', - '--skip-spoilers/--include-spoilers', - default=True, - help="If true, do not transcribe any tags that are marked as a spoiler." - ), SiteSpecificOption( 'offset', '--offset', diff --git a/sites/xenforo2.py b/sites/xenforo2.py index 6e43a9e..157d776 100644 --- a/sites/xenforo2.py +++ b/sites/xenforo2.py @@ -40,17 +40,19 @@ def _clean_spoilers(self, post, chapterid): # spoilers don't work well, so turn them into epub footnotes for spoiler in post.find_all(class_='bbCodeSpoiler'): spoiler_title = spoiler.find(class_='bbCodeSpoiler-button-title') - if self.options['skip_spoilers']: - link = self._footnote(spoiler.find(class_='bbCodeBlock-content').extract(), chapterid) + spoiler_contents = spoiler.find(class_='bbCodeBlock-content').extract() + new_spoiler = self._new_tag('div', class_="leech-spoiler") + if self.options['spoilers'] == 'skip': + new_spoiler.append(spoiler_title and f'[SPOILER: {spoiler_title.get_text()}]' or '[SPOILER]') + elif self.options['spoilers'] == 'inline': if spoiler_title: - link.string = spoiler_title.get_text() + new_spoiler.append(f"{spoiler_title.get_text()}: ") + new_spoiler.append(spoiler_contents) else: + link = self._footnote(spoiler_contents, chapterid) if spoiler_title: - link = f'[SPOILER: {spoiler_title.get_text()}]' - else: - link = '[SPOILER]' - new_spoiler = self._new_tag('div', class_="leech-spoiler") - new_spoiler.append(link) + link.string = spoiler_title.get_text() + new_spoiler.append(link) spoiler.replace_with(new_spoiler) def _post_date(self, post):