| | """Library specific exception definitions.""" |
| | from typing import Pattern, Union |
| | import logging |
| |
|
| |
|
| | logger = logging.getLogger(__name__) |
| |
|
| | class PytubeFixError(Exception): |
| | """Base pytubefix exception that all others inherit. |
| | |
| | This is done to not pollute the built-in exceptions, which *could* result |
| | in unintended errors being unexpectedly and incorrectly handled within |
| | implementers code. |
| | """ |
| | |
| |
|
| | class MaxRetriesExceeded(PytubeFixError): |
| | """Maximum number of retries exceeded.""" |
| |
|
| |
|
| | class HTMLParseError(PytubeFixError): |
| | """HTML could not be parsed""" |
| |
|
| |
|
| | class ExtractError(PytubeFixError): |
| | """Data extraction based exception.""" |
| |
|
| | class SABRError(PytubeFixError): |
| | def __init__(self, msg: str): |
| | self.msg = msg |
| | super().__init__(self.msg) |
| |
|
| | @property |
| | def error_string(self): |
| | return self.msg |
| |
|
| | class RegexMatchError(ExtractError): |
| | """Regex pattern did not return any matches.""" |
| |
|
| | def __init__(self, caller: str, pattern: Union[str, Pattern]): |
| | """ |
| | :param str caller: |
| | Calling function |
| | :param str pattern: |
| | Pattern that failed to match |
| | """ |
| | super().__init__( |
| | f"{caller}: could not find match for {pattern}") |
| |
|
| |
|
| | self.caller = caller |
| | self.pattern = pattern |
| |
|
| |
|
| | class InterpretationError(PytubeFixError): |
| | def __init__(self, js_url: str): |
| | self.js_url = js_url |
| | super().__init__(self.error_string) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'Error interpreting player js: {self.js_url}' |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| |
|
| | class VideoUnavailable(PytubeFixError): |
| | """ |
| | Base video error. |
| | |
| | This is the base error type for all video errors. |
| | |
| | Call this if you can't group the error by known error type and it is not important to the developer. |
| | """ |
| |
|
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.error_string) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} is unavailable' |
| |
|
| | |
| |
|
| | class VideoPrivate(VideoUnavailable): |
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} is a private video' |
| |
|
| |
|
| | class MembersOnly(VideoUnavailable): |
| | """Video is members-only. |
| | |
| | YouTube has special videos that are only viewable to users who have |
| | subscribed to a content creator. |
| | ref: https://support.google.com/youtube/answer/7544492?hl=en |
| | """ |
| |
|
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} is a members-only video' |
| |
|
| |
|
| | class VideoRegionBlocked(VideoUnavailable): |
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} is not available in your region' |
| |
|
| | class BotDetection(VideoUnavailable): |
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return ( |
| | f'{self.video_id} This request was detected as a bot. Use `use_po_token=True` or switch to WEB client to view. ' |
| | f'See more details at https://github.com/JuanBindez/pytubefix/pull/209') |
| |
|
| |
|
| | class PoTokenRequired(VideoUnavailable): |
| | def __init__(self, video_id: str, client_name: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | :param str client_name: |
| | A YouTube client identifier. |
| | """ |
| | self.video_id = video_id |
| | self.client_name = client_name |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return ( |
| | f'{self.video_id} The {self.client_name} client requires PoToken to obtain functional streams, ' |
| | f'See more details at https://github.com/JuanBindez/pytubefix/pull/209') |
| |
|
| |
|
| | class LoginRequired(VideoUnavailable): |
| | def __init__(self, video_id: str, reason: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | self.reason = reason |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return ( |
| | f'{self.video_id} requires login to view, YouTube reason: {self.reason}') |
| |
|
| | |
| |
|
| | class RecordingUnavailable(VideoUnavailable): |
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} does not have a live stream recording available' |
| |
|
| |
|
| | class LiveStreamError(VideoUnavailable): |
| | """Video is a live stream.""" |
| |
|
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} is streaming live and cannot be loaded' |
| |
|
| |
|
| | class LiveStreamOffline(VideoUnavailable): |
| | """The live will start soon""" |
| |
|
| | def __init__(self, video_id: str, reason: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | :param str reason: |
| | reason for the error |
| | """ |
| | self.video_id = video_id |
| | self.reason = reason |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} {self.reason}' |
| |
|
| | |
| |
|
| | class AgeRestrictedError(VideoUnavailable): |
| | """Video is age restricted, and cannot be accessed without OAuth.""" |
| |
|
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| | |
| | @property |
| | def error_string(self): |
| | return f"{self.video_id} is age restricted, and can't be accessed without logging in." |
| |
|
| |
|
| | class AgeCheckRequiredError(VideoUnavailable): |
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f"{self.video_id} has age restrictions and cannot be accessed without confirmation." |
| |
|
| |
|
| | class AgeCheckRequiredAccountError(VideoUnavailable): |
| | def __init__(self, video_id: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return ( |
| | f"{self.video_id} may be inappropriate for " |
| | f"some users. Sign in to your primary account to confirm your age.") |
| |
|
| |
|
| | class InnerTubeResponseError(VideoUnavailable): |
| | def __init__(self, video_id: str, client: str): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | """ |
| | self.video_id = video_id |
| | self.client = client |
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return ( |
| | f"{self.video_id} : {self.client} client did not receive a response from YouTube") |
| |
|
| | |
| |
|
| |
|
| | class UnknownVideoError(VideoUnavailable): |
| | """Unknown video error.""" |
| |
|
| | def __init__(self, video_id: str, status: str = None, reason: str = None, developer_message: str = None): |
| | """ |
| | :param str video_id: |
| | A YouTube video identifier. |
| | :param str status: |
| | The status code of the response. |
| | :param str reason: |
| | The reason for the error. |
| | :param str developer_message: |
| | The message from the developer. |
| | """ |
| | self.video_id = video_id |
| | self.status = status |
| | self.reason = reason |
| | self.developer_message = developer_message |
| |
|
| | logger.warning('Unknown Video Error') |
| | logger.warning(f'Video ID: {self.video_id}') |
| | logger.warning(f'Status: {self.status}') |
| | logger.warning(f'Reason: {self.reason}') |
| | logger.warning(f'Developer Message: {self.developer_message}') |
| | logger.warning( |
| | 'Please open an issue at ' |
| | 'https://github.com/JuanBindez/pytubefix/issues ' |
| | 'and provide the above log output.' |
| | ) |
| |
|
| | super().__init__(self.video_id) |
| |
|
| | @property |
| | def error_string(self): |
| | return f'{self.video_id} has an unknown error, check logs for more info [Status: {self.status}] [Reason: {self.reason}]' |
| |
|