#!/usr/bin/env python # vim:fileencoding=utf-8 # # Title: Substack # License: GNU General Public License v3 – https://www.gnu.org/licenses/gpl-3.0.html # Copyright: Nathan Cook (nathan.cook@gmail.com) ## # Written: 2020-12-18 ## __license__ = 'GNU General Public License v3 – https://www.gnu.org/licenses/gpl-3.0.html' __copyright__ = 'Nathan Cook – 2020-12-19' __version__ = 'v0.1.1' __date__ = '2020-12-19' __author__ = 'topynate' import json from calibre.web.feeds.news import BasicNewsRecipe from mechanize import Request class Substack(BasicNewsRecipe): title = 'Substack' __author__ = 'topynate' oldest_article = 7 language = 'en' max_articles_per_feed = 100 auto_cleanup = True needs_subscription = 'optional' use_embedded_content = False recipe_specific_options = { 'days': { 'short': 'Oldest article to download from this news source. In days ', 'long': 'For example, 0.5, gives you articles from the past 12 hours', 'default': str(oldest_article) } } def __init__(self, *args, **kwargs): BasicNewsRecipe.__init__(self, *args, **kwargs) d = self.recipe_specific_options.get('days') if d and isinstance(d, str): self.oldest_article = float(d) # Every Substack publication has an RSS feed at https://{name}.substack.com/feed. # The same URL provides either all posts, or all free posts + previews of paid posts, # depending on whether you're logged in. feeds = [ ('Novum Lumen', 'https://novumlumen.substack.com/feed'), # gratuitously self-promotional example ] def get_browser(self): br = BasicNewsRecipe.get_browser(self) if self.username is not None and self.password is not None: br.open('https://substack.com/account/login?redirect=%2F&email=&with_password=') data = json.dumps({'email': self.username, 'password': self.password, 'captcha_response':None}) req = Request( url='https://substack.com/api/v1/email-login', headers={ 'Accept': '*/*', 'Content-Type': 'application/json', 'Origin': 'https://substack.com', 'Referer': 'https://substack.com/account/login?redirect=%2F&email=&with_password=', }, data=data, method='POST') res = br.open(req) if res.getcode() != 200: raise ValueError('Login failed, check username and password') return br