mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-08 08:21:26 +01:00
Compare commits
No commits in common. "68a14d1859e359d0d85f6df0d3d40bd4e18dfda6" and "a7acbd0f9b251d12acf7488f819bee57e49662dc" have entirely different histories.
68a14d1859
...
a7acbd0f9b
|
@ -1,11 +1,10 @@
|
|||
import itertools
|
||||
import json
|
||||
import urllib.error
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..networking.exceptions import HTTPError
|
||||
from ..utils import (
|
||||
ExtractorError,
|
||||
int_or_none,
|
||||
make_archive_id,
|
||||
parse_iso8601,
|
||||
smuggle_url,
|
||||
|
@ -30,12 +29,15 @@ class NebulaBaseIE(InfoExtractor):
|
|||
'https://nebula.tv/auth/login/', None,
|
||||
'Logging in to Nebula', 'Login failed',
|
||||
data=json.dumps({'email': username, 'password': password}).encode(),
|
||||
headers={'content-type': 'application/json'})
|
||||
headers={
|
||||
'content-type': 'application/json',
|
||||
'cookie': '' # 'sessionid' cookie causes 403
|
||||
})
|
||||
except ExtractorError as e:
|
||||
if isinstance(e.cause, HTTPError) and e.cause.status == 400:
|
||||
if isinstance(e.cause, urllib.error.HTTPError) and e.cause.status == 400:
|
||||
raise ExtractorError('Login failed: Invalid username or password', expected=True)
|
||||
raise
|
||||
self._api_token = traverse_obj(response, ('key', {str}))
|
||||
self._api_token = response.get('key')
|
||||
if not self._api_token:
|
||||
raise ExtractorError('Login failed: No token')
|
||||
|
||||
|
@ -45,10 +47,10 @@ class NebulaBaseIE(InfoExtractor):
|
|||
try:
|
||||
return self._download_json(*args, **kwargs)
|
||||
except ExtractorError as e:
|
||||
if not isinstance(e.cause, HTTPError) or e.cause.status not in (401, 403):
|
||||
if not isinstance(e.cause, urllib.error.HTTPError) or e.cause.status not in (401, 403):
|
||||
raise
|
||||
self.to_screen(
|
||||
f'Reauthorizing with Nebula and retrying, because last API call resulted in error {e.cause.status}')
|
||||
self.to_screen(f'Reautherizing with Nebula and retrying, '
|
||||
f'because last API call resulted in error {e.cause.status}')
|
||||
self._real_initialize()
|
||||
if self._token:
|
||||
kwargs.setdefault('headers', {})['Authorization'] = f'Bearer {self._token}'
|
||||
|
@ -63,37 +65,38 @@ class NebulaBaseIE(InfoExtractor):
|
|||
headers={'Authorization': f'Token {self._api_token}'} if self._api_token else None,
|
||||
note='Authorizing to Nebula', data=b'')['token']
|
||||
|
||||
def _extract_formats(self, content_id, slug):
|
||||
for retry in (False, True):
|
||||
try:
|
||||
fmts, subs = self._extract_m3u8_formats_and_subtitles(
|
||||
f'https://content.api.nebula.app/{content_id.split(":")[0]}s/{content_id}/manifest.m3u8',
|
||||
slug, 'mp4', query={
|
||||
'token': self._token,
|
||||
'app_version': '23.10.0',
|
||||
'platform': 'ios',
|
||||
})
|
||||
return {'formats': fmts, 'subtitles': subs}
|
||||
except ExtractorError as e:
|
||||
if isinstance(e.cause, HTTPError) and e.cause.status == 401:
|
||||
self.raise_login_required()
|
||||
if not retry and isinstance(e.cause, HTTPError) and e.cause.status == 403:
|
||||
self.to_screen('Reauthorizing with Nebula and retrying, because fetching video resulted in error')
|
||||
self._real_initialize()
|
||||
continue
|
||||
def _extract_formats(self, content_id, slug, fatal=False):
|
||||
api_path = 'lessons' if content_id.startswith('lesson:') else 'video_episodes'
|
||||
try:
|
||||
fmts, subs = self._extract_m3u8_formats_and_subtitles(
|
||||
f'https://content.api.nebula.app/{api_path}/{content_id}/manifest.m3u8',
|
||||
slug, 'mp4', query={
|
||||
'token': self._token,
|
||||
'app_version': '23.10.0',
|
||||
'platform': 'ios',
|
||||
})
|
||||
except ExtractorError as e:
|
||||
if isinstance(e.cause, urllib.error.HTTPError) and e.cause.status == 401:
|
||||
self.raise_login_required('This video is only available for users with an active subscription')
|
||||
if fatal or not isinstance(e.cause, urllib.error.HTTPError) or e.cause.status != 403:
|
||||
raise
|
||||
self.to_screen('Reautherizing with Nebula and retrying, because fetching video resulted in error')
|
||||
self._real_initialize()
|
||||
return self._extract_formats(content_id, slug, fatal=True)
|
||||
|
||||
return {'formats': fmts, 'subtitles': subs}
|
||||
|
||||
def _extract_video_metadata(self, episode):
|
||||
channel_url = traverse_obj(
|
||||
episode, (('channel_slug', 'class_slug'), {lambda x: urljoin('https://nebula.tv/', x)}), get_all=False)
|
||||
return {
|
||||
'id': episode['id'].partition(':')[2],
|
||||
'id': episode['id'].split(':', 1)[-1],
|
||||
**traverse_obj(episode, {
|
||||
'display_id': 'slug',
|
||||
'title': 'title',
|
||||
'description': 'description',
|
||||
'timestamp': ('published_at', {parse_iso8601}),
|
||||
'duration': ('duration', {int_or_none}),
|
||||
'duration': 'duration',
|
||||
'channel_id': 'channel_slug',
|
||||
'uploader_id': 'channel_slug',
|
||||
'channel': 'channel_title',
|
||||
|
@ -101,7 +104,7 @@ class NebulaBaseIE(InfoExtractor):
|
|||
'series': 'channel_title',
|
||||
'creator': 'channel_title',
|
||||
'thumbnail': ('images', 'thumbnail', 'src', {url_or_none}),
|
||||
'episode_number': ('order', {int_or_none}),
|
||||
'episode_number': 'order',
|
||||
# Old code was wrongly setting extractor_key from NebulaSubscriptionsIE
|
||||
'_old_archive_ids': ('zype_id', {lambda x: [
|
||||
make_archive_id(NebulaIE, x), make_archive_id(NebulaSubscriptionsIE, x)] if x else None}),
|
||||
|
@ -236,7 +239,6 @@ class NebulaIE(NebulaBaseIE):
|
|||
|
||||
|
||||
class NebulaClassIE(NebulaBaseIE):
|
||||
IE_NAME = 'nebula:class'
|
||||
_VALID_URL = rf'{_BASE_URL_RE}/(?P<id>[-\w]+)/(?P<ep>\d+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://nebula.tv/copyright-for-fun-and-profit/14',
|
||||
|
@ -358,7 +360,7 @@ class NebulaChannelIE(NebulaBaseIE):
|
|||
if not next_url:
|
||||
break
|
||||
|
||||
def _generate_class_entries(self, channel):
|
||||
def _generate_playlist_entries_class(self, channel):
|
||||
for lesson in channel['lessons']:
|
||||
metadata = self._extract_video_metadata(lesson)
|
||||
yield self.url_result(smuggle_url(
|
||||
|
@ -372,7 +374,7 @@ class NebulaChannelIE(NebulaBaseIE):
|
|||
collection_slug, note='Retrieving channel')
|
||||
|
||||
if channel.get('type') == 'class':
|
||||
entries = self._generate_class_entries(channel)
|
||||
entries = self._generate_playlist_entries_class(channel)
|
||||
else:
|
||||
entries = self._generate_playlist_entries(channel['id'], collection_slug)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user