Compare commits

..

6 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
9 changed files with 160 additions and 795 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

@ -1,7 +1,6 @@
{ {
"username": "", "username": "",
"password": "", "password": "",
"driver_path": null,
"last_generated_ts": 0, "last_generated_ts": 0,
"feed_cache_time_seconds": 3600, "feed_cache_time_seconds": 3600,
"output_file": "feed.rss", "output_file": "feed.rss",

View File

@ -28,4 +28,4 @@ if __name__ == '__main__':
output_file.write(feed.generate()) output_file.write(feed.generate())
last_generation_time = config['last_generated_ts'] = current_ts last_generation_time = config['last_generated_ts'] = current_ts
with open(config_file_path, 'w') as config_file: with open(config_file_path, 'w') as config_file:
json.dump(config, config_file) json.dump(config, config_file, indent=4)

View File

@ -1,400 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<id>https://phlaym.net/feeds/nebula.rss</id>
<title>Nebula subscriptions</title>
<updated>2022-01-11T15:58:08.097960+00:00</updated>
<link href="https://phlaym.net/feeds/nebula.rss" rel="self"/>
<generator uri="https://lkiesow.github.io/python-feedgen" version="0.9.0">python-feedgen</generator>
<logo>https://nebula.app/apple-touch-icon.png</logo>
<subtitle>Your subscribed videos</subtitle>
<entry>
<id>https://nebula.app/videos/sarah-z-what-went-wrong-with-dear-evan-hansen</id>
<title>What Went Wrong With Dear Evan Hansen</title>
<updated>2022-01-11T15:58:08.098619+00:00</updated>
<author>
<name>SarahZ</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/sarah-z-what-went-wrong-with-dear-evan-hansen" rel="alternate"/>
<link href="https://nebula.app/videos/sarah-z-what-went-wrong-with-dear-evan-hansen" rel="enclosure"/>
<summary>New video by SarahZ: What Went Wrong With Dear Evan Hansen</summary>
<published>2021-12-05T07:23:08+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/half-as-interesting-how-one-terrible-trader-bankrupted-barings-bank</id>
<title>How One Terrible Trader Bankrupted Barings Bank</title>
<updated>2022-01-11T15:58:08.098602+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/half-as-interesting-how-one-terrible-trader-bankrupted-barings-bank" rel="alternate"/>
<link href="https://nebula.app/videos/half-as-interesting-how-one-terrible-trader-bankrupted-barings-bank" rel="enclosure"/>
<summary>New video by Half as Interesting: How One Terrible Trader Bankrupted Barings Bank</summary>
<published>2021-12-07T18:15:58+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/legaleagle-real-lawyer-reacts-to-its-always-sunny-hero-or-hate-crime</id>
<title>Real Lawyer Reacts to It's Always Sunny (Hero or Hate Crime)</title>
<updated>2022-01-11T15:58:08.098585+00:00</updated>
<author>
<name>Legal Eagle</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/legaleagle-real-lawyer-reacts-to-its-always-sunny-hero-or-hate-crime" rel="alternate"/>
<link href="https://nebula.app/videos/legaleagle-real-lawyer-reacts-to-its-always-sunny-hero-or-hate-crime" rel="enclosure"/>
<summary>New video by Legal Eagle: Real Lawyer Reacts to It's Always Sunny (Hero or Hate Crime)</summary>
<published>2021-12-08T21:47:41+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/half-as-interesting-why-planes-fly-over-the-north-pole-but-not-the-south-pole</id>
<title>Why Planes Fly Over The North Pole But Not The South Pole</title>
<updated>2022-01-11T15:58:08.098568+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/half-as-interesting-why-planes-fly-over-the-north-pole-but-not-the-south-pole" rel="alternate"/>
<link href="https://nebula.app/videos/half-as-interesting-why-planes-fly-over-the-north-pole-but-not-the-south-pole" rel="enclosure"/>
<summary>New video by Half as Interesting: Why Planes Fly Over The North Pole But Not The South Pole</summary>
<published>2021-12-09T15:39:25+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/legaleagle-are-the-crumbley-parents-responsible-for-the-shooting-too</id>
<title>Are The Crumbley Parents Responsible for the Shooting Too?</title>
<updated>2022-01-11T15:58:08.098500+00:00</updated>
<author>
<name>Legal Eagle</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/legaleagle-are-the-crumbley-parents-responsible-for-the-shooting-too" rel="alternate"/>
<link href="https://nebula.app/videos/legaleagle-are-the-crumbley-parents-responsible-for-the-shooting-too" rel="enclosure"/>
<summary>New video by Legal Eagle: Are The Crumbley Parents Responsible for the Shooting Too?</summary>
<published>2021-12-11T04:38:06+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/people-make-games-roblox-pressured-us-to-delete-our-video-so-we-dug-deeper</id>
<title>Roblox Pressured Us to Delete Our Video. So We Dug Deeper.</title>
<updated>2022-01-11T15:58:08.098482+00:00</updated>
<author>
<name>People Make Games</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/people-make-games-roblox-pressured-us-to-delete-our-video-so-we-dug-deeper" rel="alternate"/>
<link href="https://nebula.app/videos/people-make-games-roblox-pressured-us-to-delete-our-video-so-we-dug-deeper" rel="enclosure"/>
<summary>New video by People Make Games: Roblox Pressured Us to Delete Our Video. So We Dug Deeper.</summary>
<published>2021-12-13T14:38:31+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/wendover-productions-how-airlines-quietly-became-banks</id>
<title>How Airlines Quietly Became Banks</title>
<updated>2022-01-11T15:58:08.098461+00:00</updated>
<author>
<name>Wendover</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/wendover-productions-how-airlines-quietly-became-banks" rel="alternate"/>
<link href="https://nebula.app/videos/wendover-productions-how-airlines-quietly-became-banks" rel="enclosure"/>
<summary>New video by Wendover: How Airlines Quietly Became Banks</summary>
<published>2021-12-14T15:35:32+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/uno-dos-of-trace-do-dads-even-matter</id>
<title>Do Dads Even Matter?</title>
<updated>2022-01-11T15:58:08.098444+00:00</updated>
<author>
<name>Uno Dos of Trace</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/uno-dos-of-trace-do-dads-even-matter" rel="alternate"/>
<link href="https://nebula.app/videos/uno-dos-of-trace-do-dads-even-matter" rel="enclosure"/>
<summary>New video by Uno Dos of Trace: Do Dads Even Matter?</summary>
<published>2021-12-15T22:31:16+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/half-as-interesting-why-sweden-is-moving-its-northernmost-town-2-miles-east</id>
<title>Why Sweden Is Moving Its Northernmost Town 2 Miles East</title>
<updated>2022-01-11T15:58:08.098427+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/half-as-interesting-why-sweden-is-moving-its-northernmost-town-2-miles-east" rel="alternate"/>
<link href="https://nebula.app/videos/half-as-interesting-why-sweden-is-moving-its-northernmost-town-2-miles-east" rel="enclosure"/>
<summary>New video by Half as Interesting: Why Sweden Is Moving Its Northernmost Town 2 Miles East</summary>
<published>2021-12-16T17:11:45+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/up-and-atom-this-paradox-proves-einsteins-special-relativity</id>
<title>This Paradox Proves Einstein's Special Relativity</title>
<updated>2022-01-11T15:58:08.098410+00:00</updated>
<author>
<name>Up and Atom</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/up-and-atom-this-paradox-proves-einsteins-special-relativity" rel="alternate"/>
<link href="https://nebula.app/videos/up-and-atom-this-paradox-proves-einsteins-special-relativity" rel="enclosure"/>
<summary>New video by Up and Atom: This Paradox Proves Einstein's Special Relativity</summary>
<published>2021-12-17T05:01:58+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/mia-mulder-were-elagabalus-and-queen-kristina-transgender-mia-mulder</id>
<title>Were Elagabalus And Queen Kristina Transgender? | Mia Mulder</title>
<updated>2022-01-11T15:58:08.098393+00:00</updated>
<author>
<name>Mia Mulder</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/mia-mulder-were-elagabalus-and-queen-kristina-transgender-mia-mulder" rel="alternate"/>
<link href="https://nebula.app/videos/mia-mulder-were-elagabalus-and-queen-kristina-transgender-mia-mulder" rel="enclosure"/>
<summary>New video by Mia Mulder: Were Elagabalus And Queen Kristina Transgender? | Mia Mulder</summary>
<published>2021-12-17T21:42:56+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/real-engineering-the-insane-engineering-of-the-james-webb-telescope</id>
<title>The Insane Engineering of the James Webb Telescope</title>
<updated>2022-01-11T15:58:08.098376+00:00</updated>
<author>
<name>Real Engineering</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/real-engineering-the-insane-engineering-of-the-james-webb-telescope" rel="alternate"/>
<link href="https://nebula.app/videos/real-engineering-the-insane-engineering-of-the-james-webb-telescope" rel="enclosure"/>
<summary>New video by Real Engineering: The Insane Engineering of the James Webb Telescope</summary>
<published>2021-12-18T18:04:38+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/real-science-the-insane-biology-of-the-orca</id>
<title>The Insane Biology of: The Orca</title>
<updated>2022-01-11T15:58:08.098357+00:00</updated>
<author>
<name>Real Science</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/real-science-the-insane-biology-of-the-orca" rel="alternate"/>
<link href="https://nebula.app/videos/real-science-the-insane-biology-of-the-orca" rel="enclosure"/>
<summary>New video by Real Science: The Insane Biology of: The Orca</summary>
<published>2021-12-18T23:34:11+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/techaltar-how-911-google-changed-cinema</id>
<title>How 9/11 &amp; Google Changed Cinema</title>
<updated>2022-01-11T15:58:08.098340+00:00</updated>
<author>
<name>TechAltar</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/techaltar-how-911-google-changed-cinema" rel="alternate"/>
<link href="https://nebula.app/videos/techaltar-how-911-google-changed-cinema" rel="enclosure"/>
<summary>New video by TechAltar: How 9/11 &amp; Google Changed Cinema</summary>
<published>2021-12-20T15:00:00+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/legaleagle-the-most-bizarre-legal-defenses-that-worked</id>
<title>The Most Bizarre Legal Defenses (That Worked!)</title>
<updated>2022-01-11T15:58:08.098323+00:00</updated>
<author>
<name>Legal Eagle</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/legaleagle-the-most-bizarre-legal-defenses-that-worked" rel="alternate"/>
<link href="https://nebula.app/videos/legaleagle-the-most-bizarre-legal-defenses-that-worked" rel="enclosure"/>
<summary>New video by Legal Eagle: The Most Bizarre Legal Defenses (That Worked!)</summary>
<published>2021-12-20T15:22:39+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/sarahz-why-the-mean-girls-musical-doesnt-work</id>
<title>Why The Mean Girls Musical Doesn't Work</title>
<updated>2022-01-11T15:58:08.098303+00:00</updated>
<author>
<name>SarahZ</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/sarahz-why-the-mean-girls-musical-doesnt-work" rel="alternate"/>
<link href="https://nebula.app/videos/sarahz-why-the-mean-girls-musical-doesnt-work" rel="enclosure"/>
<summary>New video by SarahZ: Why The Mean Girls Musical Doesn't Work</summary>
<published>2021-12-22T10:46:44+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/hai-why-almost-every-town-in-america-has-a-thai-restaurant</id>
<title>Why Almost Every Town In America Has a Thai Restaurant</title>
<updated>2022-01-11T15:58:08.098286+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/hai-why-almost-every-town-in-america-has-a-thai-restaurant" rel="alternate"/>
<link href="https://nebula.app/videos/hai-why-almost-every-town-in-america-has-a-thai-restaurant" rel="enclosure"/>
<summary>New video by Half as Interesting: Why Almost Every Town In America Has a Thai Restaurant</summary>
<published>2021-12-22T14:35:12+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/techaltar-the-phone-company-tier-list-2021</id>
<title>The phone company tier list - 2021</title>
<updated>2022-01-11T15:58:08.098268+00:00</updated>
<author>
<name>TechAltar</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/techaltar-the-phone-company-tier-list-2021" rel="alternate"/>
<link href="https://nebula.app/videos/techaltar-the-phone-company-tier-list-2021" rel="enclosure"/>
<summary>New video by TechAltar: The phone company tier list - 2021</summary>
<published>2021-12-23T13:42:02+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/hai-the-real-reason-nyc-is-always-covered-in-scaffolding</id>
<title>The Real Reason NYC Is Always Covered In Scaffolding</title>
<updated>2022-01-11T15:58:08.098248+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/hai-the-real-reason-nyc-is-always-covered-in-scaffolding" rel="alternate"/>
<link href="https://nebula.app/videos/hai-the-real-reason-nyc-is-always-covered-in-scaffolding" rel="enclosure"/>
<summary>New video by Half as Interesting: The Real Reason NYC Is Always Covered In Scaffolding</summary>
<published>2021-12-23T18:24:44+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/legaleagle-why-alex-jones-lost-the-sandy-hook-suits</id>
<title>Why Alex Jones Lost the Sandy Hook Suits</title>
<updated>2022-01-11T15:58:08.098231+00:00</updated>
<author>
<name>Legal Eagle</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/legaleagle-why-alex-jones-lost-the-sandy-hook-suits" rel="alternate"/>
<link href="https://nebula.app/videos/legaleagle-why-alex-jones-lost-the-sandy-hook-suits" rel="enclosure"/>
<summary>New video by Legal Eagle: Why Alex Jones Lost the Sandy Hook Suits</summary>
<published>2021-12-27T20:41:07+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/tracedominguez-are-lgbtq-better-parents</id>
<title>Are LGBTQ+ Better Parents?</title>
<updated>2022-01-11T15:58:08.098214+00:00</updated>
<author>
<name>Uno Dos of Trace</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/tracedominguez-are-lgbtq-better-parents" rel="alternate"/>
<link href="https://nebula.app/videos/tracedominguez-are-lgbtq-better-parents" rel="enclosure"/>
<summary>New video by Uno Dos of Trace: Are LGBTQ+ Better Parents?</summary>
<published>2021-12-28T01:06:45+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/wendover-the-news-you-missed-in-2021-from-every-country-in-the-world-part-1</id>
<title>The News You Missed in 2021, From Every Country in the World (Part 1)</title>
<updated>2022-01-11T15:58:08.098197+00:00</updated>
<author>
<name>Wendover</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/wendover-the-news-you-missed-in-2021-from-every-country-in-the-world-part-1" rel="alternate"/>
<link href="https://nebula.app/videos/wendover-the-news-you-missed-in-2021-from-every-country-in-the-world-part-1" rel="enclosure"/>
<summary>New video by Wendover: The News You Missed in 2021, From Every Country in the World (Part 1)</summary>
<published>2021-12-28T13:16:23+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/wendover-the-news-you-missed-in-2021-from-every-country-in-the-world-part-2</id>
<title>The News You Missed in 2021, From Every Country in the World (Part 2)</title>
<updated>2022-01-11T15:58:08.098179+00:00</updated>
<author>
<name>Wendover</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/wendover-the-news-you-missed-in-2021-from-every-country-in-the-world-part-2" rel="alternate"/>
<link href="https://nebula.app/videos/wendover-the-news-you-missed-in-2021-from-every-country-in-the-world-part-2" rel="enclosure"/>
<summary>New video by Wendover: The News You Missed in 2021, From Every Country in the World (Part 2)</summary>
<published>2021-12-28T13:29:12+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/tracedominguez-how-babies-rewire-your-brain</id>
<title>How Babies Rewire Your Brain</title>
<updated>2022-01-11T15:58:08.098162+00:00</updated>
<author>
<name>Uno Dos of Trace</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/tracedominguez-how-babies-rewire-your-brain" rel="alternate"/>
<link href="https://nebula.app/videos/tracedominguez-how-babies-rewire-your-brain" rel="enclosure"/>
<summary>New video by Uno Dos of Trace: How Babies Rewire Your Brain</summary>
<published>2021-12-29T13:59:00+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/tracedominguez-3-stereotypes-that-hurt-kids-and-how-to-stop-them</id>
<title>3 Stereotypes that Hurt Kids (and How to Stop Them)</title>
<updated>2022-01-11T15:58:08.098145+00:00</updated>
<author>
<name>Uno Dos of Trace</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/tracedominguez-3-stereotypes-that-hurt-kids-and-how-to-stop-them" rel="alternate"/>
<link href="https://nebula.app/videos/tracedominguez-3-stereotypes-that-hurt-kids-and-how-to-stop-them" rel="enclosure"/>
<summary>New video by Uno Dos of Trace: 3 Stereotypes that Hurt Kids (and How to Stop Them)</summary>
<published>2021-12-30T13:59:00+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/hai-who-officially-decides-what-time-it-is</id>
<title>Who Officially Decides What Time It Is?</title>
<updated>2022-01-11T15:58:08.098127+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/hai-who-officially-decides-what-time-it-is" rel="alternate"/>
<link href="https://nebula.app/videos/hai-who-officially-decides-what-time-it-is" rel="enclosure"/>
<summary>New video by Half as Interesting: Who Officially Decides What Time It Is?</summary>
<published>2021-12-31T15:59:55+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/hai-why-dont-artificial-flavors-taste-accurate</id>
<title>Why Dont Artificial Flavors Taste Accurate?</title>
<updated>2022-01-11T15:58:08.098108+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/hai-why-dont-artificial-flavors-taste-accurate" rel="alternate"/>
<link href="https://nebula.app/videos/hai-why-dont-artificial-flavors-taste-accurate" rel="enclosure"/>
<summary>New video by Half as Interesting: Why Dont Artificial Flavors Taste Accurate?</summary>
<published>2022-01-04T16:12:54+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/legaleagle-celebrities-sued-for-posting-photos-of-themselves</id>
<title>Celebrities Sued For Posting Photos of Themselves</title>
<updated>2022-01-11T15:58:08.098089+00:00</updated>
<author>
<name>Legal Eagle</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/legaleagle-celebrities-sued-for-posting-photos-of-themselves" rel="alternate"/>
<link href="https://nebula.app/videos/legaleagle-celebrities-sued-for-posting-photos-of-themselves" rel="enclosure"/>
<summary>New video by Legal Eagle: Celebrities Sued For Posting Photos of Themselves</summary>
<published>2022-01-04T22:12:45+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/hai-the-bug-that-created-free-public-wifi-networks-that-didnt-work</id>
<title>The Bug That Created “Free Public Wifi” Networks That Didnt Work</title>
<updated>2022-01-11T15:58:08.098065+00:00</updated>
<author>
<name>Half as Interesting</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/hai-the-bug-that-created-free-public-wifi-networks-that-didnt-work" rel="alternate"/>
<link href="https://nebula.app/videos/hai-the-bug-that-created-free-public-wifi-networks-that-didnt-work" rel="enclosure"/>
<summary>New video by Half as Interesting: The Bug That Created “Free Public Wifi” Networks That Didnt Work</summary>
<published>2022-01-06T15:39:39+00:00</published>
</entry>
<entry>
<id>https://nebula.app/videos/wendover-electric-vehicles-battery-problem</id>
<title>Electric Vehicles' Battery Problem</title>
<updated>2022-01-11T15:58:08.098012+00:00</updated>
<author>
<name>Wendover</name>
<email>Unknown</email>
</author>
<link href="https://nebula.app/videos/wendover-electric-vehicles-battery-problem" rel="alternate"/>
<link href="https://nebula.app/videos/wendover-electric-vehicles-battery-problem" rel="enclosure"/>
<summary>New video by Wendover: Electric Vehicles' Battery Problem</summary>
<published>2022-01-11T15:03:33+00:00</published>
</entry>
</feed>

View File

@ -1,4 +1,4 @@
__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

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]

334
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.8, <4" python-versions = ">=3.8, <4"
content-hash = "a5539b66162dc6e970156af8476cd35f92d70aa91166b89a3ff14de775dae24a" 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.8, <4" 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"

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)