Compare commits

..

4 Commits

Author SHA1 Message Date
c96edfb9db removed driver quitting 2022-01-14 05:54:22 +01:00
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
8 changed files with 120 additions and 809 deletions

View File

@ -5,8 +5,6 @@ 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
- Firefox: It should be fairly easy to switch to Chrome instead, `nebula_loader.py` has a few references to Firefox which one would need to alter
- [Geckodriver](https://github.com/mozilla/geckodriver/releases/) is needed to remote-control Firefox. The executable should be in your path, it's possible to specify the path to the binary in the config file. Replace with ChromeDriver for Chrome
- [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
@ -34,20 +32,4 @@ I have not tested this on windows, but it should work without issues.
Notes
=====
This is an extremely hacky solution and basically loads the Nebula homepage, logs in, goes to "My Library" and loads the list of videos. Naturally, this may break at any time, e.g. every time Nebula changes their layout slightly.
Right after finishing this, I found a way to directly load the list of videos:
curl 'https://content.watchnebula.com/library/video/?page=1' \
-X 'GET' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Origin: https://nebula.app' \
-H 'Referer: https://nebula.app/' \
-H 'Accept-Language: en-GB,en;q=0.9' \
-H 'Host: content.watchnebula.com' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15' \
-H 'Authorization: Bearer ADD_TOKEN_HERE' \
-H 'Connection: keep-alive' \
-H 'Nebula-Platform: web'
When I get around to implementing this (that is: logging in, reading the authorisation token, and then parsing the result) I might switch to this instead, should be more stable.
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": "",
"password": "",
"driver_path": null,
"last_generated_ts": 0,
"feed_cache_time_seconds": 3600,
"output_file": "feed.rss",

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-11T19:55:44.781950+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-11T19:55:44.782675+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-11T19:55:44.782661+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-11T19:55:44.782646+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-11T19:55:44.782631+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-11T19:55:44.782556+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-11T19:55:44.782541+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-11T19:55:44.782522+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-11T19:55:44.782507+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-11T19:55:44.782493+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-11T19:55:44.782478+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-11T19:55:44.782463+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-11T19:55:44.782445+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-11T19:55:44.782428+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-11T19:55:44.782412+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-11T19:55:44.782396+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-11T19:55:44.782378+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-11T19:55:44.782358+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-11T19:55:44.782340+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-11T19:55:44.782324+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-11T19:55:44.782305+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-11T19:55:44.782289+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-11T19:55:44.782272+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-11T19:55:44.782257+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-11T19:55:44.782241+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-11T19:55:44.782221+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-11T19:55:44.782204+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-11T19:55:44.782187+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-11T19:55:44.782167+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-11T19:55:44.782142+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-11T19:55:44.782069+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_loader import NebulaLoader

View File

@ -1,18 +1,9 @@
import datetime
import logging
import os
import re
import time
from typing import List, Optional
from selenium import webdriver
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
import requests
from nebula_rss import NebulaVideo
@ -26,77 +17,43 @@ class NebulaLoader:
):
self.username = username
self.password = password
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
self.session = requests.Session()
@staticmethod
def _parse_anchor(anchor) -> NebulaVideo:
info_div = anchor.next_sibling
details_anchor = info_div.find_all('a')[1]
divs = details_anchor.find_all('div')
title_div = divs[0]
details_div = divs[1]
creator = details_div.find('span').string
release_text = details_div.find('time').get('datetime')
release_date = datetime.datetime.fromisoformat(release_text.replace('Z', '+00:00'))
return NebulaVideo(
title=title_div.string,
creator=creator,
url='https://nebula.app' + anchor.get('href'),
release_at=release_date
)
def _parse_api_response(api_video) -> NebulaVideo:
title = api_video['title']
creator = api_video['channel_title']
url = api_video['share_url']
published_at = datetime.datetime.strptime(api_video['published_at'], "%Y-%m-%dT%H:%M:%S%z")
return NebulaVideo(title, creator, url, published_at)
def load_from_api(self):
api_base = 'https://api.watchnebula.com/api/v1'
user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)'\
'Version/15.2 Safari/605.1.15'
headers = {
'User-Agent': user_agent,
'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]:
videos = []
try:
videos = self._load()
finally:
self.driver.quit()
return videos
def _load(self) -> List[NebulaVideo]:
self.driver.get('https://nebula.app/login')
username_input = '//*[@name="email"]'
password_input = '//*[@name="password"]'
login_submit = '//*[@id="NebulaApp"]/div[2]/div[2]/div[1]/div/form/button'
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]
return self.load_from_api()

320
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]]
name = "atomicwrites"
version = "1.4.0"
@ -18,7 +10,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
name = "attrs"
version = "21.4.0"
description = "Classes Without Boilerplate"
category = "main"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
@ -28,21 +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_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 = "certifi"
version = "2021.10.8"
@ -52,15 +29,15 @@ optional = false
python-versions = "*"
[[package]]
name = "cffi"
version = "1.15.0"
description = "Foreign Function Interface for Python calling C code."
name = "charset-normalizer"
version = "2.0.10"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
python-versions = "*"
python-versions = ">=3.5.0"
[package.dependencies]
pycparser = "*"
[package.extras]
unicode_backport = ["unicodedata2"]
[[package]]
name = "colorama"
@ -70,25 +47,6 @@ category = "dev"
optional = false
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]]
name = "feedgen"
version = "0.9.0"
@ -101,14 +59,6 @@ python-versions = "*"
lxml = "*"
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]]
name = "idna"
version = "3.3"
@ -139,17 +89,6 @@ html5 = ["html5lib"]
htmlsoup = ["beautifulsoup4"]
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]]
name = "packaging"
version = "21.3"
@ -181,30 +120,6 @@ category = "dev"
optional = false
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]]
name = "pyparsing"
version = "3.0.6"
@ -249,17 +164,22 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
six = ">=1.5"
[[package]]
name = "selenium"
version = "4.1.0"
description = ""
name = "requests"
version = "2.27.1"
description = "Python HTTP for Humans."
category = "main"
optional = false
python-versions = "~=3.7"
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[package.dependencies]
trio = ">=0.17,<1.0"
trio-websocket = ">=0.9,<1.0"
urllib3 = {version = ">=1.26,<2.0", extras = ["secure"]}
certifi = ">=2017.4.17"
charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
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]]
name = "six"
@ -269,30 +189,6 @@ category = "main"
optional = false
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]]
name = "toml"
version = "0.10.2"
@ -301,36 +197,6 @@ category = "dev"
optional = false
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]]
name = "urllib3"
version = "1.26.8"
@ -339,38 +205,17 @@ category = "main"
optional = false
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]
brotli = ["brotlipy (>=0.6.0)"]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
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]
lock-version = "1.1"
python-versions = ">=3.8, <4"
content-hash = "ba3ecd85d591822347c2548818869e64748cef7a83caf43f656e036e739184be"
content-hash = "ca4f6c15a45ed5a3a8e516286424141af629a09a9b08fbc5fe694316f5a71725"
[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 = [
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
@ -379,99 +224,21 @@ attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
{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"},
]
certifi = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
]
cffi = [
{file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"},
{file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"},
{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"},
charset-normalizer = [
{file = "charset-normalizer-2.0.10.tar.gz", hash = "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd"},
{file = "charset_normalizer-2.0.10-py3-none-any.whl", hash = "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"},
]
colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{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 = [
{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 = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
@ -542,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.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 = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
@ -558,14 +321,6 @@ py = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{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 = [
{file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
{file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
@ -578,42 +333,19 @@ python-dateutil = [
{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"},
]
selenium = [
{file = "selenium-4.1.0-py3-none-any.whl", hash = "sha256:27e7b64df961d609f3d57237caa0df123abbbe22d038f2ec9e332fb90ec1a939"},
requests = [
{file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
{file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{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 = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{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 = [
{file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
{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]
name = "nebula-rss"
version = "0.1.0"
version = "0.2.0"
description = ""
authors = ["Max Nuding <max.nuding@icloud.com>"]
[tool.poetry.dependencies]
python = ">=3.8, <4"
selenium = "^4.1.0"
feedgen = "^0.9.0"
lxml = "^4.7.1"
beautifulsoup4 = "^4.10.0"
requests = "^2.27.1"
[tool.poetry.dev-dependencies]
pytest = "^6.2"

View File

@ -1,19 +1,61 @@
import datetime
from nebula_rss import __version__, NebulaLoader
from bs4 import BeautifulSoup
def test_version():
assert __version__ == '0.1.0'
assert __version__ == '0.2.0'
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
soup = BeautifulSoup(example_div, features='lxml')
anchor = soup.div.a
video = NebulaLoader._parse_anchor(anchor)
assert video.title == 'The Bug That Created “Free Public Wifi” Networks That Didnt Work'
assert video.creator == 'Half as Interesting'
assert video.url == 'https://nebula.app/videos/hai-the-bug-that-created-free-public-wifi-networks-that-didnt-work'
assert video.release_at == datetime.datetime(2022, 1, 6, 15, 39, 39, tzinfo=datetime.timezone.utc)
example_response = {
'type': 'video_episode',
'slug': 'wendover-electric-vehicles-battery-problem',
'title': "Electric Vehicles' Battery Problem",
'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
'short_description': "Electric Vehicles' Battery Problem",
'duration': 970,
'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)