Compare commits

..

8 Commits

Author SHA1 Message Date
5ea45dbbfd Updated version 2022-01-12 12:31:38 +01:00
d6ff153d26 Updated readme 2022-01-12 12:31:16 +01:00
c7948fcf07 Switched to tge nebula api 2022-01-12 12:29:27 +01:00
1bce8551e7 Added quitting the browser after finish 2022-01-12 06:33:31 +01:00
afba09e02d Switched to using beautifulsoup directly 2022-01-11 21:13:37 +01:00
d7aa69046d Added readme 2022-01-11 21:12:44 +01:00
a488bbd3e4 added requirements.txt 2022-01-11 17:33:23 +01:00
9806399a99 generating feed 2022-01-11 17:04:32 +01:00
11 changed files with 412 additions and 398 deletions

35
README.md Normal file
View File

@ -0,0 +1,35 @@
Logs into Nebula as the configured user, fetches available videos, and generates an RSS feed. No feed will be generated, if less than *feed_cache_time_seconds* seconds (set in config.json) have elapsed since last running this script.
Requirements
============
The following are needed to run this script:
- Python, version 3.8 to 3.10: I have tested 3.8.10 and 3.10.0. Older versions might work, but 3.6 is a hard minimum
- [Poetry](https://python-poetry.org): Not a hard requirement, I have included a requirements.txt which can be used to install dependencies with `pip install -r requirements.txt`
. I haven't tested this, and the list is auto-generated by poetry, using python 3.10
Installation
============
- Download or clone the repository.
- If you are using poetry, run `poetry install` in the `nebula-rss` directory.
- If you are not using poetry, run `pip install -r requirements.txt`. If that doesn't work, try manually installing the dependencies listed in `pyproject.toml`
- Copy `config_default.json` to `config.json`
Usage
=====
This assume you are inside the folder `nebula-rss`.
First, configure your username and password in `config.json`. You should also set your feed url and possibly adjust the path to the output file which will be generated.
Run `poetry run python main.py` to generate your feed. Alternatively, run `chmod +x ./main.py` to mark it as executable and then run `poetry run ./main.py`.
If you a not using poetry, run `python main.py` directly, or mark `main.py` as executable and run `./main.py`.
You will likely want to run the script regularly, to update the feed. I'm using the following crontab `* 0 * * * cd $HOME/nebula-rss; $HOME/.local/bin/poetry run ./main.py`, so that it runs once an hour.
I have not tested this on windows, but it should work without issues.
Notes
=====
This is an extremely hacky solution and uses the internal API. Naturally, this may break at any time.

View File

View File

@ -1,5 +1,8 @@
{ {
"username": "", "username": "",
"password": "", "password": "",
"driver_path": null "last_generated_ts": 0,
"feed_cache_time_seconds": 3600,
"output_file": "feed.rss",
"feed_url": ""
} }

19
main.py
View File

@ -1,16 +1,31 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import json import json
import os
import time
import nebula_rss import nebula_rss
if __name__ == '__main__': if __name__ == '__main__':
config = {} config = {}
with open('config.json') as config_file: config_file_path = 'config.json'
with open(config_file_path) as config_file:
config = json.load(config_file) config = json.load(config_file)
loader = nebula_rss.nebula_loader.NebulaLoader( loader = nebula_rss.nebula_loader.NebulaLoader(
username=config['username'], username=config['username'],
password=config['password'], password=config['password'],
driver_path=config.get('driver_path', None) driver_path=config.get('driver_path', None)
) )
loader.load() current_ts = time.time()
last_generation_time = config.get('last_generated_ts', 0)
feed_cache_time_seconds = config.get('feed_cache_time_seconds', 3600)
time_since_last_generation = current_ts - last_generation_time
if time_since_last_generation <= feed_cache_time_seconds and os.path.isfile(config['output_file']):
exit(0)
feed = nebula_rss.NebulaFeed(nebula_loader=loader, feed_url=config['feed_url'])
# generates bytes, not string for whatever reason
with open(config['output_file'], 'wb') as output_file:
output_file.write(feed.generate())
last_generation_time = config['last_generated_ts'] = current_ts
with open(config_file_path, 'w') as config_file:
json.dump(config, config_file, indent=4)

View File

@ -1,4 +1,5 @@
__version__ = '0.1.0' __version__ = '0.2.0'
from nebula_rss.nebula_video import NebulaVideo from nebula_rss.nebula_video import NebulaVideo
from nebula_rss.nebula_loader import NebulaLoader from nebula_rss.nebula_loader import NebulaLoader
from nebula_rss.nebula_feed import NebulaFeed

36
nebula_rss/nebula_feed.py Normal file
View File

@ -0,0 +1,36 @@
from feedgen.feed import FeedGenerator
from nebula_rss import NebulaLoader
class NebulaFeed:
def __init__(self, nebula_loader: NebulaLoader, feed_url: str):
self.nebula_loader = nebula_loader
self.feed_url = feed_url
def generate(self, format: str = 'atom') -> str:
videos = self.nebula_loader.load()
fg = FeedGenerator()
fg.id(self.feed_url)
fg.title('Nebula subscriptions')
fg.logo('https://nebula.app/apple-touch-icon.png')
fg.subtitle('Your subscribed videos')
fg.link(href=self.feed_url, rel='self')
fg.language('en')
for video in videos:
fe = fg.add_entry()
fe.id(video.url)
fe.title(video.title)
fe.link(href=video.url)
fe.author({'name': video.creator, 'email': 'Unknown'}) # Email is required for RSS format, but is not known
fe.enclosure(url=video.url)
fe.summary(f'New video by {video.creator}: {video.title}')
fe.published(video.release_at)
feed = ''
if format == 'atom':
feed = fg.atom_str(pretty=True)
elif format == 'rss':
feed = fg.rss_str(pretty=True)
else:
raise Exception(f'Unknown format: "{format}". Use "atom" or "rss')
return feed

View File

@ -1,18 +1,11 @@
import datetime import datetime
import logging
import os import os
import re import re
import time import time
from typing import List, Optional from typing import List, Optional
from selenium import webdriver import requests
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.remote.remote_connection import LOGGER
from bs4 import BeautifulSoup
from nebula_rss import NebulaVideo from nebula_rss import NebulaVideo
@ -26,69 +19,48 @@ class NebulaLoader:
): ):
self.username = username self.username = username
self.password = password self.password = password
self.session = requests.Session()
LOGGER.setLevel(logging.FATAL)
service = None
if driver_path:
service = Service(driver_path)
options = Options()
options.headless = True
self.driver = webdriver.Firefox(
service=service,
options=options,
log_path=os.devnull,
service_log_path=os.devnull)
self.driver.implicitly_wait(10) # seconds
@staticmethod @staticmethod
def _parse_anchor(anchor) -> NebulaVideo: def _parse_api_response(api_video) -> NebulaVideo:
info_div = anchor.next_sibling title = api_video['title']
details_anchor = info_div.find_all('a')[1] creator = api_video['channel_title']
divs = details_anchor.find_all('div') url = api_video['share_url']
title_div = divs[0] published_at = datetime.datetime.strptime(api_video['published_at'], "%Y-%m-%dT%H:%M:%S%z")
details_div = divs[1] return NebulaVideo(title, creator, url, published_at)
creator = details_div.find('span').string
release_text = details_div.find('time').get('datetime') def load_from_api(self):
release_date = datetime.datetime.fromisoformat(release_text.replace('Z', '+00:00')) api_base = 'https://api.watchnebula.com/api/v1'
return NebulaVideo( user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)'\
title=title_div.string, 'Version/15.2 Safari/605.1.15'
creator=creator, headers = {
url='https://nebula.app' + anchor.get('href'), 'User-Agent': user_agent,
release_at=release_date 'Nebula-Platform': 'web'
) }
login_data = {
'email': self.username,
'password': self.password
}
self.session.headers.update(headers)
login_response = self.session.post(api_base+'/auth/login/', json=login_data)
login_token = login_response.json()['key']
token_header = {
'Authorization': 'Token ' + login_token
}
self.session.headers.update(token_header)
auth_response = self.session.post(api_base+'/authorization/', json={})
jwt = auth_response.json()['token']
token_header['Authorization'] = 'Bearer ' + jwt
self.session.headers.update(token_header)
videos_response = self.session.get('https://content.watchnebula.com/library/video/?page=1')
return [NebulaLoader._parse_api_response(v) for v in videos_response.json()['results']]
def load(self) -> List[NebulaVideo]: def load(self) -> List[NebulaVideo]:
self.driver.get('https://nebula.app/login') videos = []
try:
username_input = '//*[@name="email"]' videos = self.load_from_api()
password_input = '//*[@name="password"]' finally:
login_submit = '//*[@id="NebulaApp"]/div[2]/div[2]/div[1]/div/form/button' self.driver.quit()
return videos
self.driver.find_element(By.XPATH, username_input).send_keys(self.username)
self.driver.find_element(By.XPATH, password_input).send_keys(self.password)
self.driver.find_element(By.XPATH, login_submit).click()
delay = 3
# wait for "My shows" link
wait = WebDriverWait(self.driver, delay)
myshows = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'menu a[href|="/myshows"]')))
myshows.click()
myshows = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'h2')))
video_links = []
count_remaining = 5
follower_error_re = re.compile("You aren't following any creators yet.*")
while not video_links and count_remaining > 0:
time.sleep(2)
soup = BeautifulSoup(self.driver.page_source, features="lxml")
follower_error = False
follower_error = [p for p in soup.find_all('p') if p.find(string=follower_error_re)]
if follower_error:
print('Error loading videos, reloading page')
self.driver.refresh()
count_remaining = 5
else:
all_anchors = soup.find_all('a')
video_links = [a for a in all_anchors if a.get('href').startswith('/videos/') and a.get('aria-hidden')]
count_remaining -= 1
return [NebulaLoader._parse_anchor(v) for v in video_links]

336
poetry.lock generated
View File

@ -1,11 +1,3 @@
[[package]]
name = "async-generator"
version = "1.10"
description = "Async generators and context managers for Python 3.5+"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]] [[package]]
name = "atomicwrites" name = "atomicwrites"
version = "1.4.0" version = "1.4.0"
@ -18,7 +10,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
name = "attrs" name = "attrs"
version = "21.4.0" version = "21.4.0"
description = "Classes Without Boilerplate" description = "Classes Without Boilerplate"
category = "main" category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
@ -28,32 +20,6 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
[[package]]
name = "beautifulsoup4"
version = "4.10.0"
description = "Screen-scraping library"
category = "main"
optional = false
python-versions = ">3.0.0"
[package.dependencies]
soupsieve = ">1.2"
[package.extras]
html5lib = ["html5lib"]
lxml = ["lxml"]
[[package]]
name = "bs4"
version = "0.0.1"
description = "Dummy package for Beautiful Soup"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
beautifulsoup4 = "*"
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2021.10.8" version = "2021.10.8"
@ -63,15 +29,15 @@ optional = false
python-versions = "*" python-versions = "*"
[[package]] [[package]]
name = "cffi" name = "charset-normalizer"
version = "1.15.0" version = "2.0.10"
description = "Foreign Function Interface for Python calling C code." description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main" category = "main"
optional = false optional = false
python-versions = "*" python-versions = ">=3.5.0"
[package.dependencies] [package.extras]
pycparser = "*" unicode_backport = ["unicodedata2"]
[[package]] [[package]]
name = "colorama" name = "colorama"
@ -81,25 +47,6 @@ category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "cryptography"
version = "36.0.1"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
cffi = ">=1.12"
[package.extras]
docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
sdist = ["setuptools_rust (>=0.11.4)"]
ssh = ["bcrypt (>=3.1.5)"]
test = ["pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"]
[[package]] [[package]]
name = "feedgen" name = "feedgen"
version = "0.9.0" version = "0.9.0"
@ -112,14 +59,6 @@ python-versions = "*"
lxml = "*" lxml = "*"
python-dateutil = "*" python-dateutil = "*"
[[package]]
name = "h11"
version = "0.12.0"
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
category = "main"
optional = false
python-versions = ">=3.6"
[[package]] [[package]]
name = "idna" name = "idna"
version = "3.3" version = "3.3"
@ -150,17 +89,6 @@ html5 = ["html5lib"]
htmlsoup = ["beautifulsoup4"] htmlsoup = ["beautifulsoup4"]
source = ["Cython (>=0.29.7)"] source = ["Cython (>=0.29.7)"]
[[package]]
name = "outcome"
version = "1.1.0"
description = "Capture the outcome of Python function calls."
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
attrs = ">=19.2.0"
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "21.3" version = "21.3"
@ -192,30 +120,6 @@ category = "dev"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pycparser"
version = "2.21"
description = "C parser in Python"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pyopenssl"
version = "21.0.0"
description = "Python wrapper module around the OpenSSL library"
category = "main"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
[package.dependencies]
cryptography = ">=3.3"
six = ">=1.5.2"
[package.extras]
docs = ["sphinx", "sphinx-rtd-theme"]
test = ["flaky", "pretend", "pytest (>=3.0.1)"]
[[package]] [[package]]
name = "pyparsing" name = "pyparsing"
version = "3.0.6" version = "3.0.6"
@ -260,17 +164,22 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
six = ">=1.5" six = ">=1.5"
[[package]] [[package]]
name = "selenium" name = "requests"
version = "4.1.0" version = "2.27.1"
description = "" description = "Python HTTP for Humans."
category = "main" category = "main"
optional = false optional = false
python-versions = "~=3.7" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[package.dependencies] [package.dependencies]
trio = ">=0.17,<1.0" certifi = ">=2017.4.17"
trio-websocket = ">=0.9,<1.0" charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
urllib3 = {version = ">=1.26,<2.0", extras = ["secure"]} idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
urllib3 = ">=1.21.1,<1.27"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
[[package]] [[package]]
name = "six" name = "six"
@ -280,30 +189,6 @@ category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "sniffio"
version = "1.2.0"
description = "Sniff out which async library your code is running under"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "sortedcontainers"
version = "2.4.0"
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "soupsieve"
version = "2.3.1"
description = "A modern CSS selector implementation for Beautiful Soup."
category = "main"
optional = false
python-versions = ">=3.6"
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.10.2" version = "0.10.2"
@ -312,36 +197,6 @@ category = "dev"
optional = false optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "trio"
version = "0.19.0"
description = "A friendly Python library for async concurrency and I/O"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
async-generator = ">=1.9"
attrs = ">=19.2.0"
cffi = {version = ">=1.14", markers = "os_name == \"nt\" and implementation_name != \"pypy\""}
idna = "*"
outcome = "*"
sniffio = "*"
sortedcontainers = "*"
[[package]]
name = "trio-websocket"
version = "0.9.2"
description = "WebSocket library for Trio"
category = "main"
optional = false
python-versions = ">=3.5"
[package.dependencies]
async-generator = ">=1.10"
trio = ">=0.11"
wsproto = ">=0.14"
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "1.26.8" version = "1.26.8"
@ -350,38 +205,17 @@ category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.dependencies]
certifi = {version = "*", optional = true, markers = "extra == \"secure\""}
cryptography = {version = ">=1.3.4", optional = true, markers = "extra == \"secure\""}
idna = {version = ">=2.0.0", optional = true, markers = "extra == \"secure\""}
pyOpenSSL = {version = ">=0.14", optional = true, markers = "extra == \"secure\""}
[package.extras] [package.extras]
brotli = ["brotlipy (>=0.6.0)"] brotli = ["brotlipy (>=0.6.0)"]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "wsproto"
version = "1.0.0"
description = "WebSockets state-machine based protocol implementation"
category = "main"
optional = false
python-versions = ">=3.6.1"
[package.dependencies]
h11 = ">=0.9.0,<1"
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.10" python-versions = ">=3.8, <4"
content-hash = "feac0aede04b3bbace7c3b2a6c9f0240e6ee1210abd4b598083952fcaa185e20" content-hash = "ca4f6c15a45ed5a3a8e516286424141af629a09a9b08fbc5fe694316f5a71725"
[metadata.files] [metadata.files]
async-generator = [
{file = "async_generator-1.10-py3-none-any.whl", hash = "sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b"},
{file = "async_generator-1.10.tar.gz", hash = "sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"},
]
atomicwrites = [ atomicwrites = [
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
@ -390,102 +224,21 @@ attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
] ]
beautifulsoup4 = [
{file = "beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf"},
{file = "beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"},
]
bs4 = [
{file = "bs4-0.0.1.tar.gz", hash = "sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"},
]
certifi = [ certifi = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
] ]
cffi = [ charset-normalizer = [
{file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, {file = "charset-normalizer-2.0.10.tar.gz", hash = "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd"},
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, {file = "charset_normalizer-2.0.10-py3-none-any.whl", hash = "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"},
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"},
{file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"},
{file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"},
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"},
{file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"},
{file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"},
{file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"},
{file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"},
{file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"},
{file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"},
{file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"},
{file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"},
{file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"},
{file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"},
{file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"},
{file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"},
{file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"},
{file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"},
{file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"},
{file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"},
{file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"},
{file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"},
{file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"},
{file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"},
{file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"},
{file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"},
{file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"},
{file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
] ]
colorama = [ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
] ]
cryptography = [
{file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b"},
{file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3"},
{file = "cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2"},
{file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f"},
{file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3"},
{file = "cryptography-36.0.1-cp36-abi3-win32.whl", hash = "sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca"},
{file = "cryptography-36.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf"},
{file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9"},
{file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1"},
{file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903"},
{file = "cryptography-36.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316"},
{file = "cryptography-36.0.1.tar.gz", hash = "sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638"},
]
feedgen = [ feedgen = [
{file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"}, {file = "feedgen-0.9.0.tar.gz", hash = "sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a"},
] ]
h11 = [
{file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
{file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"},
]
idna = [ idna = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
@ -556,10 +309,6 @@ lxml = [
{file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60"}, {file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60"},
{file = "lxml-4.7.1.tar.gz", hash = "sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24"}, {file = "lxml-4.7.1.tar.gz", hash = "sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24"},
] ]
outcome = [
{file = "outcome-1.1.0-py2.py3-none-any.whl", hash = "sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958"},
{file = "outcome-1.1.0.tar.gz", hash = "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967"},
]
packaging = [ packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
@ -572,14 +321,6 @@ py = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
] ]
pycparser = [
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
]
pyopenssl = [
{file = "pyOpenSSL-21.0.0-py2.py3-none-any.whl", hash = "sha256:8935bd4920ab9abfebb07c41a4f58296407ed77f04bd1a92914044b848ba1ed6"},
{file = "pyOpenSSL-21.0.0.tar.gz", hash = "sha256:5e2d8c5e46d0d865ae933bef5230090bdaf5506281e9eec60fa250ee80600cb3"},
]
pyparsing = [ pyparsing = [
{file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"}, {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
{file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"}, {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
@ -592,42 +333,19 @@ python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
] ]
selenium = [ requests = [
{file = "selenium-4.1.0-py3-none-any.whl", hash = "sha256:27e7b64df961d609f3d57237caa0df123abbbe22d038f2ec9e332fb90ec1a939"}, {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
{file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
] ]
six = [ six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
] ]
sniffio = [
{file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"},
{file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"},
]
sortedcontainers = [
{file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"},
{file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
]
soupsieve = [
{file = "soupsieve-2.3.1-py3-none-any.whl", hash = "sha256:1a3cca2617c6b38c0343ed661b1fa5de5637f257d4fe22bd9f1338010a1efefb"},
{file = "soupsieve-2.3.1.tar.gz", hash = "sha256:b8d49b1cd4f037c7082a9683dfa1801aa2597fb11c3a1155b7a5b94829b4f1f9"},
]
toml = [ toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
] ]
trio = [
{file = "trio-0.19.0-py3-none-any.whl", hash = "sha256:c27c231e66336183c484fbfe080fa6cc954149366c15dc21db8b7290081ec7b8"},
{file = "trio-0.19.0.tar.gz", hash = "sha256:895e318e5ec5e8cea9f60b473b6edb95b215e82d99556a03eb2d20c5e027efe1"},
]
trio-websocket = [
{file = "trio-websocket-0.9.2.tar.gz", hash = "sha256:a3d34de8fac26023eee701ed1e7bf4da9a8326b61a62934ec9e53b64970fd8fe"},
{file = "trio_websocket-0.9.2-py3-none-any.whl", hash = "sha256:5b558f6e83cc20a37c3b61202476c5295d1addf57bd65543364e0337e37ed2bc"},
]
urllib3 = [ urllib3 = [
{file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
{file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
] ]
wsproto = [
{file = "wsproto-1.0.0-py3-none-any.whl", hash = "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f"},
{file = "wsproto-1.0.0.tar.gz", hash = "sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38"},
]

View File

@ -1,15 +1,14 @@
[tool.poetry] [tool.poetry]
name = "nebula-rss" name = "nebula-rss"
version = "0.1.0" version = "0.2.0"
description = "" description = ""
authors = ["Max Nuding <max.nuding@icloud.com>"] authors = ["Max Nuding <max.nuding@icloud.com>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = ">=3.8, <4"
selenium = "^4.1.0"
feedgen = "^0.9.0" feedgen = "^0.9.0"
lxml = "^4.7.1" lxml = "^4.7.1"
bs4 = "^0.0.1" requests = "^2.27.1"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^6.2" pytest = "^6.2"

193
requirements.txt Normal file
View File

@ -0,0 +1,193 @@
async-generator==1.10; python_version >= "3.7" and python_version < "4.0" \
--hash=sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b \
--hash=sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144
attrs==21.4.0; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.5.0" \
--hash=sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4 \
--hash=sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd
beautifulsoup4==4.10.0; python_full_version > "3.0.0" \
--hash=sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf \
--hash=sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891
bs4==0.0.1 \
--hash=sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a
certifi==2021.10.8; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.7" \
--hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569 \
--hash=sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872
cffi==1.15.0; os_name == "nt" and implementation_name != "pypy" and python_version >= "3.7" and python_version < "4.0" and (python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.7") \
--hash=sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962 \
--hash=sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0 \
--hash=sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14 \
--hash=sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474 \
--hash=sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6 \
--hash=sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27 \
--hash=sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023 \
--hash=sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2 \
--hash=sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e \
--hash=sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7 \
--hash=sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3 \
--hash=sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c \
--hash=sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962 \
--hash=sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382 \
--hash=sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55 \
--hash=sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0 \
--hash=sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e \
--hash=sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39 \
--hash=sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc \
--hash=sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032 \
--hash=sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8 \
--hash=sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605 \
--hash=sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e \
--hash=sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc \
--hash=sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636 \
--hash=sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4 \
--hash=sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997 \
--hash=sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b \
--hash=sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2 \
--hash=sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7 \
--hash=sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66 \
--hash=sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029 \
--hash=sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880 \
--hash=sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20 \
--hash=sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024 \
--hash=sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e \
--hash=sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728 \
--hash=sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6 \
--hash=sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c \
--hash=sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443 \
--hash=sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a \
--hash=sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37 \
--hash=sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a \
--hash=sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e \
--hash=sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796 \
--hash=sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df \
--hash=sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8 \
--hash=sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a \
--hash=sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139 \
--hash=sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954
cryptography==36.0.1; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" \
--hash=sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b \
--hash=sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31 \
--hash=sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a \
--hash=sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173 \
--hash=sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12 \
--hash=sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3 \
--hash=sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2 \
--hash=sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f \
--hash=sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3 \
--hash=sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca \
--hash=sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf \
--hash=sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9 \
--hash=sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1 \
--hash=sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94 \
--hash=sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac \
--hash=sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee \
--hash=sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46 \
--hash=sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903 \
--hash=sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316 \
--hash=sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638
feedgen==0.9.0 \
--hash=sha256:8e811bdbbed6570034950db23a4388453628a70e689a6e8303ccec430f5a804a
h11==0.12.0; python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.6.1" \
--hash=sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6 \
--hash=sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042
idna==3.3; python_version >= "3.7" and python_version < "4.0" and (python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.7") \
--hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \
--hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d
lxml==4.7.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0") \
--hash=sha256:d546431636edb1d6a608b348dd58cc9841b81f4116745857b6cb9f8dadb2725f \
--hash=sha256:6308062534323f0d3edb4e702a0e26a76ca9e0e23ff99be5d82750772df32a9e \
--hash=sha256:f76dbe44e31abf516114f6347a46fa4e7c2e8bceaa4b6f7ee3a0a03c8eba3c17 \
--hash=sha256:d5618d49de6ba63fe4510bdada62d06a8acfca0b4b5c904956c777d28382b419 \
--hash=sha256:9393a05b126a7e187f3e38758255e0edf948a65b22c377414002d488221fdaa2 \
--hash=sha256:50d3dba341f1e583265c1a808e897b4159208d814ab07530202b6036a4d86da5 \
--hash=sha256:44f552e0da3c8ee3c28e2eb82b0b784200631687fc6a71277ea8ab0828780e7d \
--hash=sha256:e662c6266e3a275bdcb6bb049edc7cd77d0b0f7e119a53101d367c841afc66dc \
--hash=sha256:4c093c571bc3da9ebcd484e001ba18b8452903cd428c0bc926d9b0141bcb710e \
--hash=sha256:3e26ad9bc48d610bf6cc76c506b9e5ad9360ed7a945d9be3b5b2c8535a0145e3 \
--hash=sha256:a5f623aeaa24f71fce3177d7fee875371345eb9102b355b882243e33e04b7175 \
--hash=sha256:7b5e2acefd33c259c4a2e157119c4373c8773cf6793e225006a1649672ab47a6 \
--hash=sha256:67fa5f028e8a01e1d7944a9fb616d1d0510d5d38b0c41708310bd1bc45ae89f6 \
--hash=sha256:b1d381f58fcc3e63fcc0ea4f0a38335163883267f77e4c6e22d7a30877218a0e \
--hash=sha256:38d9759733aa04fb1697d717bfabbedb21398046bd07734be7cccc3d19ea8675 \
--hash=sha256:dfd0d464f3d86a1460683cd742306d1138b4e99b79094f4e07e1ca85ee267fe7 \
--hash=sha256:534e946bce61fd162af02bad7bfd2daec1521b71d27238869c23a672146c34a5 \
--hash=sha256:6ec829058785d028f467be70cd195cd0aaf1a763e4d09822584ede8c9eaa4b03 \
--hash=sha256:ade74f5e3a0fd17df5782896ddca7ddb998845a5f7cd4b0be771e1ffc3b9aa5b \
--hash=sha256:41358bfd24425c1673f184d7c26c6ae91943fe51dfecc3603b5e08187b4bcc55 \
--hash=sha256:6e56521538f19c4a6690f439fefed551f0b296bd785adc67c1777c348beb943d \
--hash=sha256:5b0f782f0e03555c55e37d93d7a57454efe7495dab33ba0ccd2dbe25fc50f05d \
--hash=sha256:490712b91c65988012e866c411a40cc65b595929ececf75eeb4c79fcc3bc80a6 \
--hash=sha256:34c22eb8c819d59cec4444d9eebe2e38b95d3dcdafe08965853f8799fd71161d \
--hash=sha256:2a906c3890da6a63224d551c2967413b8790a6357a80bf6b257c9a7978c2c42d \
--hash=sha256:36b16fecb10246e599f178dd74f313cbdc9f41c56e77d52100d1361eed24f51a \
--hash=sha256:a5edc58d631170de90e50adc2cc0248083541affef82f8cd93bea458e4d96db8 \
--hash=sha256:87c1b0496e8c87ec9db5383e30042357b4839b46c2d556abd49ec770ce2ad868 \
--hash=sha256:0a5f0e4747f31cff87d1eb32a6000bde1e603107f632ef4666be0dc065889c7a \
--hash=sha256:bf6005708fc2e2c89a083f258b97709559a95f9a7a03e59f805dd23c93bc3986 \
--hash=sha256:fc15874816b9320581133ddc2096b644582ab870cf6a6ed63684433e7af4b0d3 \
--hash=sha256:0b5e96e25e70917b28a5391c2ed3ffc6156513d3db0e1476c5253fcd50f7a944 \
--hash=sha256:ec9027d0beb785a35aa9951d14e06d48cfbf876d8ff67519403a2522b181943b \
--hash=sha256:9fbc0dee7ff5f15c4428775e6fa3ed20003140560ffa22b88326669d53b3c0f4 \
--hash=sha256:1104a8d47967a414a436007c52f533e933e5d52574cab407b1e49a4e9b5ddbd1 \
--hash=sha256:fc9fb11b65e7bc49f7f75aaba1b700f7181d95d4e151cf2f24d51bfd14410b77 \
--hash=sha256:317bd63870b4d875af3c1be1b19202de34c32623609ec803b81c99193a788c1e \
--hash=sha256:610807cea990fd545b1559466971649e69302c8a9472cefe1d6d48a1dee97440 \
--hash=sha256:09b738360af8cb2da275998a8bf79517a71225b0de41ab47339c2beebfff025f \
--hash=sha256:6a2ab9d089324d77bb81745b01f4aeffe4094306d939e92ba5e71e9a6b99b71e \
--hash=sha256:eed394099a7792834f0cb4a8f615319152b9d801444c1c9e1b1a2c36d2239f9e \
--hash=sha256:735e3b4ce9c0616e85f302f109bdc6e425ba1670a73f962c9f6b98a6d51b77c9 \
--hash=sha256:772057fba283c095db8c8ecde4634717a35c47061d24f889468dc67190327bcd \
--hash=sha256:13dbb5c7e8f3b6a2cf6e10b0948cacb2f4c9eb05029fe31c60592d08ac63180d \
--hash=sha256:718d7208b9c2d86aaf0294d9381a6acb0158b5ff0f3515902751404e318e02c9 \
--hash=sha256:5bee1b0cbfdb87686a7fb0e46f1d8bd34d52d6932c0723a86de1cc532b1aa489 \
--hash=sha256:e410cf3a2272d0a85526d700782a2fa92c1e304fdcc519ba74ac80b8297adf36 \
--hash=sha256:585ea241ee4961dc18a95e2f5581dbc26285fcf330e007459688096f76be8c42 \
--hash=sha256:a555e06566c6dc167fbcd0ad507ff05fd9328502aefc963cb0a0547cfe7f00db \
--hash=sha256:adaab25be351fff0d8a691c4f09153647804d09a87a4e4ea2c3f9fe9e8651851 \
--hash=sha256:82d16a64236970cb93c8d63ad18c5b9f138a704331e4b916b2737ddfad14e0c4 \
--hash=sha256:59e7da839a1238807226f7143c68a479dee09244d1b3cf8c134f2fce777d12d0 \
--hash=sha256:a1bbc4efa99ed1310b5009ce7f3a1784698082ed2c1ef3895332f5df9b3b92c2 \
--hash=sha256:0607ff0988ad7e173e5ddf7bf55ee65534bd18a5461183c33e8e41a59e89edf4 \
--hash=sha256:6c198bfc169419c09b85ab10cb0f572744e686f40d1e7f4ed09061284fc1303f \
--hash=sha256:a58d78653ae422df6837dd4ca0036610b8cb4962b5cfdbd337b7b24de9e5f98a \
--hash=sha256:e18281a7d80d76b66a9f9e68a98cf7e1d153182772400d9a9ce855264d7d0ce7 \
--hash=sha256:8e54945dd2eeb50925500957c7c579df3cd07c29db7810b83cf30495d79af267 \
--hash=sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60 \
--hash=sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24
outcome==1.1.0; python_version >= "3.7" and python_version < "4.0" \
--hash=sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958 \
--hash=sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967
pycparser==2.21; python_version >= "3.7" and python_full_version < "3.0.0" and os_name == "nt" and implementation_name != "pypy" and python_version < "4.0" or os_name == "nt" and implementation_name != "pypy" and python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" \
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
pyopenssl==21.0.0; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" \
--hash=sha256:8935bd4920ab9abfebb07c41a4f58296407ed77f04bd1a92914044b848ba1ed6 \
--hash=sha256:5e2d8c5e46d0d865ae933bef5230090bdaf5506281e9eec60fa250ee80600cb3
python-dateutil==2.8.2; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
selenium==4.1.0; python_version >= "3.7" and python_version < "4.0" \
--hash=sha256:27e7b64df961d609f3d57237caa0df123abbbe22d038f2ec9e332fb90ec1a939
six==1.16.0; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926
sniffio==1.2.0; python_version >= "3.7" and python_version < "4.0" \
--hash=sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663 \
--hash=sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de
sortedcontainers==2.4.0; python_version >= "3.7" and python_version < "4.0" \
--hash=sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 \
--hash=sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88
soupsieve==2.3.1; python_version >= "3.6" and python_full_version > "3.0.0" \
--hash=sha256:1a3cca2617c6b38c0343ed661b1fa5de5637f257d4fe22bd9f1338010a1efefb \
--hash=sha256:b8d49b1cd4f037c7082a9683dfa1801aa2597fb11c3a1155b7a5b94829b4f1f9
trio-websocket==0.9.2; python_version >= "3.7" and python_version < "4.0" \
--hash=sha256:a3d34de8fac26023eee701ed1e7bf4da9a8326b61a62934ec9e53b64970fd8fe \
--hash=sha256:5b558f6e83cc20a37c3b61202476c5295d1addf57bd65543364e0337e37ed2bc
trio==0.19.0; python_version >= "3.7" and python_version < "4.0" \
--hash=sha256:c27c231e66336183c484fbfe080fa6cc954149366c15dc21db8b7290081ec7b8 \
--hash=sha256:895e318e5ec5e8cea9f60b473b6edb95b215e82d99556a03eb2d20c5e027efe1
urllib3==1.26.8; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.7" \
--hash=sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed \
--hash=sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c
wsproto==1.0.0; python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.6.1" \
--hash=sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f \
--hash=sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38

View File

@ -1,19 +1,61 @@
import datetime import datetime
from nebula_rss import __version__, NebulaLoader from nebula_rss import __version__, NebulaLoader
from bs4 import BeautifulSoup
def test_version(): def test_version():
assert __version__ == '0.1.0' assert __version__ == '0.2.0'
def test_video_parsing(): def test_video_parsing():
example_div = '<div class="css-14ccti3"><a aria-hidden="true" tabindex="-1" class="css-cvinzg" href="/videos/hai-the-bug-that-created-free-public-wifi-networks-that-didnt-work"><div class="css-1ei3f96"><svg viewBox="0 0 2000 1125" class="css-hnyg4"></svg><div class="css-1i7faai"><picture class="css-0"><source srcset="https://images.watchnebula.com/p/dfbf8ec1-0573-41b0-a69e-ed773b32bfd4.jpeg?height=240&amp; 426w, https://images.watchnebula.com/p/dfbf8ec1-0573-41b0-a69e-ed773b32bfd4.jpeg?height=720&amp; 1280w, https://images.watchnebula.com/p/dfbf8ec1-0573-41b0-a69e-ed773b32bfd4.jpeg?height=1080&amp; 1920w" sizes="(max-width: 414px) 100vw, (max-width: 768px) and (min-width: 415px) 50vw, 440px" type="image/jpeg"><img src="https://images.watchnebula.com/p/dfbf8ec1-0573-41b0-a69e-ed773b32bfd4.jpeg?height=720&amp;" alt="The Bug That Created “Free Public Wifi” Networks That Didnt Work thumbnail" width="2000" height="1125" class="css-1u2fze8"></picture><div class="css-zazjdf"><span class="css-y4yfni">Video length:</span><time datetime="PT5M3S">5:03</time></div></div></div></a><div class="css-xzijep"><a class="css-bu30ts" href="/hai"><picture class="css-0"><source srcset="https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.webp?width=16&amp; 16w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.webp?width=32&amp; 32w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.webp?width=64&amp; 64w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.webp?width=128&amp; 128w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.webp?width=256&amp; 256w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.webp?width=512&amp; 512w" sizes="36px" type="image/webp"><source srcset="https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.jpeg?width=16&amp; 16w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.jpeg?width=32&amp; 32w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.jpeg?width=64&amp; 64w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.jpeg?width=128&amp; 128w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.jpeg?width=256&amp; 256w, https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.jpeg?width=512&amp; 512w" sizes="36px" type="image/jpeg"><img src="https://images.watchnebula.com/p/ba3e3488-6c9a-4bb1-a3f7-9ccc05352868.jpeg?width=64&amp;" alt="Half as Interesting avatar" width="2000" height="2000" class="css-izq1dd"></picture></a><a class="css-1eqy4pw" href="/videos/hai-the-bug-that-created-free-public-wifi-networks-that-didnt-work"><div class="css-1njioi">The Bug That Created “Free Public Wifi” Networks That Didnt Work</div><div class="css-4e1m5a"><span>Half as Interesting</span><span class="css-1go4ftc">•</span><span class="css-y4yfni">Video published:</span><time datetime="2022-01-06T15:39:39.000Z">5 days ago</time></div></a></div></div>' # noqa example_response = {
soup = BeautifulSoup(example_div, features='lxml') 'type': 'video_episode',
anchor = soup.div.a 'slug': 'wendover-electric-vehicles-battery-problem',
video = NebulaLoader._parse_anchor(anchor) 'title': "Electric Vehicles' Battery Problem",
assert video.title == 'The Bug That Created “Free Public Wifi” Networks That Didnt Work' 'description': 'Watch Extremities at http://youtube.com/extremities\n\nBuy a Wendover Productions t-shirt: https://standard.tv/collections/wendover-productions/products/wendover-productions-shirt\n\nSubscribe to Half as Interesting (The other channel from Wendover Productions): https://www.youtube.com/halfasinteresting\n\nYoutube: http://www.YouTube.com/WendoverProductions\nInstagram: http://Instagram.com/sam.from.wendover\nTwitter: http://www.Twitter.com/WendoverPro\nSponsorship Enquiries: wendover@standard.tv\nOther emails: sam@wendover.productions\nReddit: http://Reddit.com/r/WendoverProductions\n\nWriting by Sam Denby\nEditing by Alexander Williard\nAnimation by Josh Sherrington\nSound by Graham Haerther \nThumbnail by Simon Buckmaster\n\n[1] https://lighthouse.mq.edu.au/article/july-2020/please-explain-how-lithium-became-a-rock-star\n[2] https://www.forbes.com/sites/rrapier/2020/12/13/the-worlds-top-lithium-producers/?sh=378a13bb5bc6\n[3] https://www.statista.com/statistics/235323/lithium-batteries-top-manufacturers/\n[4] https://www.spglobal.com/platts/en/market-insights/latest-news/energy-transition/121421-commodities-2022-global-lithium-market-to-remain-tight-into-2022\n[5] https://tradingeconomics.com/commodity/cobalt\n[6] https://tradingeconomics.com/commodity/nickel\n[7] https://pubs.usgs.gov/periodicals/mcs2021/mcs2021-lithium.pdf\n[8] https://eplanning.blm.gov/public_projects/1503166/200352542/20030633/250036832/Thacker%20Pass_FEIS_Chapters1-6_508.pdf#page=57\n[9] https://www.nytimes.com/2021/05/06/business/lithium-mining-race.html\n[10] http://gbrw.org/wp-content/uploads/2021/02/Thacker-Pass-PR-final.pdf\n[11] https://www.sierranevadaally.org/2021/05/20/people-of-red-mountain-statement-of-opposition-to-lithium-nevada-corps-proposed-thacker-pass-open-pit-lithium-mine/\n[12] https://thisisreno.com/2021/11/judge-says-no-evidence-of-massacre-at-proposed-mine-site-tribes-say-otherwise/\n[13] https://www.statista.com/statistics/264928/cobalt-mine-production-by-country/\n[14] https://www.spglobal.com/platts/en/market-insights/latest-news/metals/022421-uk-cobalt-free-solid-state-battery-technology-claims-major-cost-efficiencies\n[15] https://www.latimes.com/business/story/2021-11-15/drilling-for-white-gold-is-happening-right-now-at-the-salton-sea', # noqa
assert video.creator == 'Half as Interesting' 'short_description': "Electric Vehicles' Battery Problem",
assert video.url == 'https://nebula.app/videos/hai-the-bug-that-created-free-public-wifi-networks-that-didnt-work' 'duration': 970,
assert video.release_at == datetime.datetime(2022, 1, 6, 15, 39, 39, tzinfo=datetime.timezone.utc) 'published_at': '2022-01-11T15:03:33Z',
'channel_slug': 'wendover',
'channel_slugs': ['wendover'],
'channel_title': 'Wendover',
'category_slugs': ['explainers'],
'assets': {
'channel_avatar': {
'16': {
'original': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.jpeg?width=16&',
'webp': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.webp?width=16&'
},
'32': {
'original': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.jpeg?width=32&',
'webp': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.webp?width=32&'
},
'64': {
'original': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.jpeg?width=64&',
'webp': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.webp?width=64&'
},
'128': {
'original': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.jpeg?width=128&',
'webp': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.webp?width=128&'
},
'256': {
'original': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.jpeg?width=256&',
'webp': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.webp?width=256&'
},
'512': {
'original': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.jpeg?width=512&',
'webp': 'https://images.watchnebula.com/p/e040f576-82c5-401d-a754-1600483dc673.webp?width=512&'
}
},
'thumbnail': {'240': {'original': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.jpeg?height=240&', 'webp': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.webp?height=240&'}, '480': {'original': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.jpeg?height=480&', 'webp': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.webp?height=480&'}, '720': {'original': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.jpeg?height=720&', 'webp': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.webp?height=720&'}, '1080': {'original': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.jpeg?height=1080&', 'webp': 'https://images.watchnebula.com/p/ffcd9296-2857-469d-9c00-1c7bace3407e.webp?height=1080&'}}}, # noqa
'attributes': ['free_sample_eligible'],
'share_url': 'https://nebula.app/videos/wendover-electric-vehicles-battery-problem/',
'channel': None,
'engagement': None,
'zype_id': '61dd99e519d76400018b94b0'
}
video = NebulaLoader._parse_api_response(example_response)
assert video.title == "Electric Vehicles' Battery Problem"
assert video.creator == 'Wendover'
assert video.url == 'https://nebula.app/videos/wendover-electric-vehicles-battery-problem/'
assert video.release_at == datetime.datetime(2022, 1, 11, 15, 3, 33, tzinfo=datetime.timezone.utc)
print(video) print(video)