def config_init(path: str, force: bool) -> None: """Initialize a new configuration files.""" create_config_dir_if_not_exists(path) validate_config_overwrite(path, force) new_config = get_new_config() new_config.save(path) logger.info("Successfully set the configuration!")
def config_show(is_json: bool) -> None: """Show all the available configuration.""" result = _config.as_dict() if "password" in result: result["password"] = "******" if is_json: logger.info(json.dumps(result)) else: logger.info(yaml.safe_dump(result))
def feed_import(opml_path: str, force: bool) -> None: """Import feeds from an OPML file.""" feeds = convert_opml_to_dict(opml_path) validate_conflicts(feeds, force) config.feeds.update(feeds) config.save() logger.info("Successfully imported the feeds!")
def kindle_send(feed_title: str, url: str) -> None: """Send updates from one or all feeds (or a single article).""" validate_parser() logger.info(f"[Parsing articles with the `{config.parser}` parser]\n") if feed_title: send_articles_for_feed(feed_title) elif url: send_article_from_url(url) else: logger.notice("Sending articles from all feeds...\n") for feed_title in config.feeds: send_articles_for_feed(feed_title)
def feed_remove(title: str) -> None: """Remove a feed from the config.""" if not title: feed_titles = list(config.feeds.keys()) title, _ = pick(feed_titles, "Please choose the feed to remove") found = config.feeds.pop(title, False) config.save() if found: logger.info(f"Successfully removed `{title}` from the list of feeds") else: logger.info(f"Could not find `{title}` in the list of feeds")
def config_set(key: str, force: bool) -> None: """Set a value in the config.""" if getattr(_config, key): if force: logger.warning("Overriding an existing value...") else: logger.error( f"A value already exists for `{key}`.\nPass the --force flag to overwrite it." ) sys.exit(1) value = Prompt.get(key) setattr(_config, key, value) logger.info("Configuration successfully updated!")
def feed_add(title: str, url: str, force: bool) -> None: """Add an RSS feed.""" validate_existing_feeds(title, force) feeds = get_feeds_from_url(url) if not feeds: logger.error("Could not find an RSS feed") sys.exit(1) elif len(feeds) == 1: feed = feeds[0] else: feed, _ = pick(feeds, "Please choose the correct feed from this list:") config.feeds[title] = {"url": feed} config.save() logger.info("Successfully added the feed!")
def get_feeds_from_url(url: str) -> list: """ Try to parse the URL and find any RSS feeds in the webpage Adapted from: https://gist.github.com/alexmill/9bc634240531d81c3abe """ logger.info(f"Attempting to find RSS feeds from {url}...") # If the URL itself is a proper RSS feed, just return it if is_rss_feed(url): logger.debug("URL is already a proper RSS feed") return [url] html = get_html(url) possible_feeds = get_feeds_from_links(html) + get_feeds_from_atags( url, html) return [url for url in set(possible_feeds) if is_rss_feed(url)]
def send_updates(unread_articles: List[Article], feed_title: str) -> None: """Iterate over `unread_articles`, and send each one to the kindle""" if unread_articles: if Parser(config.parser) == Parser.PUSH_TO_KINDLE: successful_count = send_urls([(article.title, article.link) for article in unread_articles]) else: successful_count = send_epub_books(unread_articles, feed_title) if successful_count: logger.notice( f"Successfully sent {successful_count} articles from the `{feed_title}` feed!" ) else: logger.error( f"Failed to send any articles to `{feed_title}`. See errors above" ) else: logger.info(f"No new content for `{feed_title}`")
def parse(self, parser: ParserBase) -> bool: """ Prepare the content of the article for EPUB Performs these tasks: 1. Parse the article with the Mercury parser 2. Download all the images mentioned in the article (EPUB format only supports embedded local images) 3. Replace all the <img "src"> tags with the local paths of the downloaded images :return: True iff the parsing succeeded """ logger.info(f"Parsing `{self.title}`...") parsed_article = parser.parse(self.url) raw_content = parsed_article.get("content") if not raw_content: return False # When some blogs (like xkcd.com) are parsed, # their content doesn't include the actual image, so we're adding it here if lead_image_url := parsed_article.get("lead_image_url"): raw_content = f'<img src="{lead_image_url}"/>\n{raw_content}'
def build(self) -> str: """ Create an EPUB file from articles and templates :return: Path to the created epub archive """ logger.info(f"Creating an EPUB book for `{self.title}`...") try: self.prepare_epub_dirs() self.copy_fixed_files() self.render_title() self.render_ncx_toc() self.render_html_toc() self.render_articles() self.render_opf() epub_path = self.compress_epub() logger.info("Successfully created an EPUB archive!") return epub_path finally: rmtree(self._dst_path)