def incompatible_validator(**kwargs):
    """
    Validate the incompatible parameters.

    Args:
        kwargs (str)
            Parameter need to do validate.

    Returns:
        None
    """
    given = 0
    for name, param in kwargs.items():
        if param is not None:
            given += 1
    params = ','.join(kwargs.keys())
    if given == 0:
        raise PyYouTubeException(
            ErrorMessage(status_code=ErrorCode.MISSING_PARAMS,
                         message=f'Specify at least one of {params}'))
    elif given > 1:
        raise PyYouTubeException(
            ErrorMessage(
                status_code=ErrorCode.INVALID_PARAMS,
                message=f'Incompatible parameters specified for {params}'))
    def get_comment_info(self, comment_id=None, return_json=False):
        """
        Args:
            comment_id (str, optional)
                Provide a comma-separated list of comment IDs or just a comment id
                for the resources that are being retrieved
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.Comment.
        Returns:
            The list data for you given comment id.
        """
        part = 'id,snippet'
        args = {
            'part': part,
        }
        if comment_id is not None:
            args['id'] = comment_id
        else:
            raise PyYouTubeException(
                ErrorMessage(status_code=10007,
                             message='Comment id must specified'))

        resp = self._request(resource='comments', args=args)
        data = self._parse_response(resp, api=True)
        if return_json:
            return data
        else:
            return [Comment.new_from_json_dict(item) for item in data]
    def refresh_token(self, refresh_token=None, return_json=False):
        """
        Refresh token by api return refresh token.
        Args:
            refresh_token (str)
                The refresh token which the api returns.
                If you not provide. will use saved token when do exchange token step retrieve.
            return_json (bool, optional):
                If True JSON data will be returned, instead of pyyoutube.AccessToken
        Return:
            Retrieved new access token's info,  pyyoutube.AccessToken instance.
        """
        if refresh_token is None:
            refresh_token = self._refresh_token

        if refresh_token is None:
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=10003,
                    message=
                    'You must provide a refresh token to get a new access token'
                ))
        kwargs = {
            'refresh_token': refresh_token,
            'client_id': self._client_id,
            'client_secret': self._client_secret,
            'grant_type': 'refresh_token'
        }
        return self._fetch_token(kwargs, return_json)
Exemple #4
0
    def get_profile(self, access_token=None, return_json=False):
        """
        Get token user info.

        Args:
            access_token(str, optional)
                If you not provide api key, you can do authorization to get an access token.
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.UserProfile
        Returns:
            The data for you given access token's user info.
        """
        if access_token is None:
            access_token = self._access_token
        try:
            response = self.session.get(self.USER_INFO_URL,
                                        params={'access_token': access_token},
                                        timeout=self._timeout,
                                        proxies=self.proxies)
        except requests.HTTPError as e:
            raise PyYouTubeException(
                ErrorMessage(status_code=ErrorCode.HTTP_ERROR, message=e.args))
        data = self._parse_response(response)
        if return_json:
            return data
        else:
            return UserProfile.new_from_json_dict(data)
    def get_videos_info(self, video_ids=None, return_json=False):
        """
        Retrieve data from YouTube Data Api for video which you point.

        Args:
            video_ids (list)
                The video's ID list you want to get data.
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.Video
        Returns:
            The data for you given video.
        """

        if video_ids is None or not isinstance(video_ids, (list, tuple)):
            raise PyYouTubeException(
                ErrorMessage(status_code=10005,
                             message='Specify the id for the video.'))

        args = {
            'id': ','.join(video_ids),
            'part': 'id,snippet,contentDetails,statistics,status'
        }

        resp = self._request(resource='videos', method='GET', args=args)

        data = self._parse_response(resp, api=True)
        self.calc_quota(resource='videos',
                        parts=args['part'],
                        count=len(video_ids))
        if return_json:
            return data
        else:
            return [Video.new_from_json_dict(item) for item in data]
    def get_comment_thread_info(self,
                                comment_thread_id=None,
                                return_json=False):
        """
        Retrieve the comment thread info by single id.
        Refer: https://developers.google.com/youtube/v3/docs/commentThreads/list
        Args:
            comment_thread_id (str)
                The id parameter specifies a comma-separated list of comment thread IDs
                for the resources that should be retrieved.
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.CommentThread.
        Returns:
            The list data for you given comment thread.
        """
        part = 'id,snippet,replies'
        if comment_thread_id is None:
            raise PyYouTubeException(
                ErrorMessage(status_code=10005,
                             message='Must Specify the id for the video'))

        args = {'id': comment_thread_id, 'part': part}

        resp = self._request(resource='commentThreads', args=args)

        data = self._parse_response(resp, api=True)
        if return_json:
            return data
        else:
            return [CommentThread.new_from_json_dict(item) for item in data]
    def exchange_code_to_access_token(self,
                                      authorization_response,
                                      redirect_uri=None,
                                      return_json=False):
        """
        Use the google auth response to get access token

        Args:
            authorization_response (str)
                The response url for you give auth permission.
            redirect_uri (str, optional)
                The redirect url you have point when do authorization step.
                If you not provide will use default uri: http://127.0.0.1
            return_json (bool, optional):
                If True JSON data will be returned, instead of pyyoutube.AccessToken
        Return:
            Retrieved access token's info,  pyyoutube.AccessToken instance.
        """
        query = urlparse(authorization_response).query
        params = dict(parse_qsl(query))

        if 'code' not in params:
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=10002,
                    message="Missing code parameter in authorization response."
                ))

        if params.get('state', None) != self.DEFAULT_STATE:
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=10002,
                    message="Missing state parameter in authorization response."
                ))
        if redirect_uri is None:
            redirect_uri = self.DEFAULT_REDIRECT_URI

        kwargs = {
            'code': params['code'],
            'client_id': self._client_id,
            'client_secret': self._client_secret,
            'redirect_uri': redirect_uri,
            'grant_type': 'authorization_code'
        }

        return self._fetch_token(kwargs, return_json)
    def get_comments_by_parent(self,
                               parent_id=None,
                               limit=20,
                               count=20,
                               return_json=None):
        """
        Retrieve data from YouTube Data Api for top level comment which you point.
        Refer: https://developers.google.com/youtube/v3/docs/comments/list

        Args:
            parent_id (str, optional)
                Provide the ID of the comment for which replies should be retrieved.
                Now YouTube currently supports replies only for top-level comments
            limit (int, optional)
                Each request retrieve comments from data api.
                For comments, this should not be more than 100.
                Default is 20.
            count (int, optional)
                The count will retrieve comments data.
                Default is 20.
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.Comment.
        Returns:
            The list data for you given comment.
        """
        part = 'id,snippet'
        args = {
            'part': part,
            'maxResults': limit,
        }
        if parent_id is not None:
            args['parentId'] = parent_id
        else:
            raise PyYouTubeException(
                ErrorMessage(status_code=10007,
                             message='Parent comment id must specified'))

        comments = []
        next_page_token = None
        while True:
            _, next_page_token, data = self.paged_by_page_token(
                resource='comments',
                args=args,
                page_token=next_page_token,
            )
            items = self._parse_data(data)
            if return_json:
                comments += items
            else:
                comments += [
                    Comment.new_from_json_dict(item) for item in items
                ]
            if len(comments) >= count:
                break
            if next_page_token is None:
                break
        return comments[:count]
Exemple #9
0
    def testErrorMessage(self):
        response = ErrorMessage(status_code=ErrorCode.HTTP_ERROR,
                                message="error")

        ex = PyYouTubeException(response=response)

        self.assertEqual(ex.status_code, 10000)
        self.assertEqual(ex.message, "error")
        self.assertEqual(ex.error_type, "PyYouTubeException")
Exemple #10
0
    def __init__(
        self,
        client_id=None,
        client_secret=None,
        api_key=None,
        access_token=None,
        timeout=None,
        proxies=None,
        quota=None,
    ):
        """
        This Api provide two method to work. Use api key or use access token.

        Args:
            client_id(str, optional)
                Your google app's ID.
            client_secret (str, optional)
                Your google app's secret.
            api_key(str, optional)
                The api key which you create from google api console.
            access_token(str, optional)
                If you not provide api key, you can do authorization to get an access token.
                If all api key and access token provided. Use access token first.
            timeout(int, optional)
                The request timeout.
            proxies(dict, optional)
                If you want use proxy, need point this param.
                param style like requests lib style.
            quota(int, optional)
                if your key has more quota. you can point this. Default is 10000

        Returns:
            YouTube Api instance.
        """
        self._client_id = client_id
        self._client_secret = client_secret
        self._api_key = api_key
        self._access_token = access_token
        self._timeout = timeout
        self.session = requests.Session()
        self.scope = None
        self.proxies = proxies

        self.quota = quota
        if self.quota is None:
            self.quota = self.DEFAULT_QUOTA
        self.used_quota = 0

        if not ((self._client_id and self._client_secret) or self._api_key
                or self._access_token):
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=ErrorCode.MISSING_PARAMS,
                    message='Must specify either client key info or api key.'))

        if self._timeout is None:
            self._timeout = self.DEFAULT_TIMEOUT
def enf_parts(resource: str,
              value: Optional[Union[str, list, tuple, set]],
              check=True):
    """
    Check to see if value type belong to correct type, and if resource support the given part.
    If it is, return api need value, otherwise, raise a PyYouTubeException.

    Args:
        resource (str):
            Name of the resource you want to retrieve.
        value (str, list, tuple, set, Optional):
            Value for the part.
        check (bool, optional):
            Whether check the resource properties.

    Returns:
        Api needed part string
    """
    if value is None:
        parts = RESOURCE_PARTS_MAPPING[resource]
    elif isinstance(value, str):
        parts = set(value.split(","))
    elif isinstance(value, (list, tuple, set)):
        parts = set(value)
    else:
        raise PyYouTubeException(
            ErrorMessage(
                status_code=ErrorCode.INVALID_PARAMS,
                message=
                f"Parameter (parts) must be single str,comma-separated str,list,tuple or set",
            ))
    # check parts whether support.
    if check:
        support_parts = RESOURCE_PARTS_MAPPING[resource]
        if not support_parts.issuperset(parts):
            not_support_parts = ",".join(parts.difference(support_parts))
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=ErrorCode.INVALID_PARAMS,
                    message=
                    f"Parts {not_support_parts} for resource {resource} not support",
                ))
    return ",".join(parts)
Exemple #12
0
 def get_video_seconds_duration(self):
     if not self.duration:
         return None
     try:
         seconds = isodate.parse_duration(self.duration).total_seconds()
     except ISO8601Error as e:
         raise PyYouTubeException(
             ErrorMessage(status_code=ErrorCode.INVALID_PARAMS,
                          message=e.args[0]))
     else:
         return int(seconds)
def enf_comma_separated(
    field: str,
    value: Optional[Union[str, list, tuple, set]],
):
    """
    Check to see if field's value type belong to correct type.
    If it is, return api need value, otherwise, raise a PyYouTubeException.

    Args:
        field (str):
            Name of the field you want to do check.
        value (str, list, tuple, set, Optional)
            Value for the field.

    Returns:
        Api needed string
    """
    if value is None:
        return None
    try:
        if isinstance(value, str):
            return value
        elif isinstance(value, (list, tuple, set)):
            if isinstance(value, set):
                logging.warning(f"Note: The order of the set is unreliable.")
            return ",".join(value)
        else:
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=ErrorCode.INVALID_PARAMS,
                    message=
                    f"Parameter ({field}) must be single str,comma-separated str,list,tuple or set",
                ))
    except (TypeError, ValueError):
        raise PyYouTubeException(
            ErrorMessage(
                status_code=ErrorCode.INVALID_PARAMS,
                message=
                f"Parameter ({field}) must be single str,comma-separated str,list,tuple or set",
            ))
    def get_profile(self, return_json=False):
        """

        """
        if self._access_token is None:
            raise PyYouTubeException(
                ErrorMessage(status_code=10005,
                             message='Get profile Must need access token.'))
        try:
            response = self.session.get(
                'https://www.googleapis.com/oauth2/v1/userinfo',
                params={'access_token': self._access_token},
                timeout=self._timeout,
                proxies=self.proxies)
        except requests.HTTPError as e:
            raise PyYouTubeException(
                ErrorMessage(status_code=10000, message=e.read()))
        data = self._parse_response(response)
        if return_json:
            return data
        else:
            return UserProfile.new_from_json_dict(data)
 def _parse_data(data):
     """
     Parse resp data
     Args:
         data (dict)
             The response data by response.json()
     Return:
          response's items
     """
     items = data['items']
     if isinstance(items, dict) or len(items) == 0:
         raise PyYouTubeException(
             ErrorMessage(status_code=10002,
                          message='Response data not have items.'))
     else:
         return items
Exemple #16
0
 def string_to_datetime(
         dt_str: Optional[str]) -> Optional[datetime.datetime]:
     """
     Convert datetime string to datetime instance.
     original string format is YYYY-MM-DDThh:mm:ss.sZ.
     :return:
     """
     if not dt_str:
         return None
     try:
         r = isodate.parse_datetime(dt_str)
     except ISO8601Error as e:
         raise PyYouTubeException(
             ErrorMessage(status_code=ErrorCode.INVALID_PARAMS,
                          message=e.args[0]))
     else:
         return r
    def get_channel_info(self,
                         channel_id=None,
                         channel_name=None,
                         return_json=False):
        """
        Retrieve data from YouTube Data API for channel which you given.

        Args:
            channel_id (str, optional)
                The id for youtube channel. Id always likes: UCLA_DiR1FfKNvjuUpBHmylQ
            channel_name (str, optional)
                The name for youtube channel.
                If id and name all given, will use id first.
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.Channel
        Returns:
            The data for you given channel.
        """
        if channel_name is not None:
            args = {
                'forUsername': channel_name,
                'part': 'id,snippet,contentDetails,statistics'
            }
        elif channel_id is not None:
            args = {
                'id': channel_id,
                'part': 'id,snippet,contentDetails,statistics,status'
            }
        else:
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=10005,
                    message='Specify at least one of channel id or username'))

        resp = self._request(resource='channels', method='GET', args=args)

        data = self._parse_response(resp, api=True)
        self.calc_quota(resource='channels', parts=args['part'])
        if return_json:
            return data
        else:
            return Channel.new_from_json_dict(data[0])
    def get_authorization_url(self, redirect_uri=None, scope=None, **kwargs):
        """
        Build authorization url to do authorize.

        Args:
            redirect_uri(str, optional)
                The uri you have set on your google app authorized uri.
                if you not provide, will use default uri: 'http://127.0.0.1'
                Must this uri in you app's authorized uri list.
            scope (list, optional)
                The scope you want give permission.
                If you not provide, will use default scope.
            kwargs(dict, optional)
                Some other params you want provide.
        Returns:
            The uri you can open on browser to do authorize.
        """
        if redirect_uri is None:
            redirect_uri = self.DEFAULT_REDIRECT_URI

        self.scope = scope
        if self.scope is None:
            self.scope = self.DEFAULT_SCOPE
        try:
            scope = ' '.join(self.scope)
        except TypeError:
            raise PyYouTubeException(
                ErrorMessage(status_code=10001,
                             message='scope need a list type.'))

        authorization_kwargs = {
            'client_id': self._client_id,
            'redirect_uri': redirect_uri,
            'scope': scope,
            'access_type': 'offline',
            'response_type': 'code',
            'state': self.DEFAULT_STATE,
        }
        if kwargs:
            authorization_kwargs.update(kwargs)

        return self.AUTHORIZATION_URL + '?' + urlencode(authorization_kwargs)
Exemple #19
0
def get_video_duration(duration: str) -> int:
    """
    Parse video ISO 8601 duration to seconds.
    Refer: https://developers.google.com/youtube/v3/docs/videos#contentDetails.duration

    Args:
        duration(str)
            Videos ISO 8601 duration. Like: PT14H23M42S
    Returns:
        integer for seconds.
    """
    try:
        seconds = isodate.parse_duration(duration).total_seconds()
        return int(seconds)
    except ISO8601Error as e:
        raise PyYouTubeException(
            ErrorMessage(
                status_code=10001,
                message=
                f'Exception in convert video duration: {duration}. errors: {e}'
            ))
def comma_separated_validator(**kwargs):
    """
    Validate the param layout whether comma-separated string.

    Args:
        kwargs (str)
            Parameter need to do validate.

    Returns:
        None
    """
    for name, param in kwargs.items():
        if param is not None:
            try:
                param.split(',')
            except AttributeError:
                raise PyYouTubeException(
                    ErrorMessage(
                        status_code=ErrorCode.INVALID_PARAMS,
                        message=
                        f'Parameter {name} must be str or comma-separated list str'
                    ))
def parts_validator(resource: str, parts: str):
    """
    Validate the resource whether support the parts.

    Args:
        resource (str)
            The YouTube resource string.
        parts (str)
            Parts need to do validate.
    Returns:
        True or False
    """
    if parts is not None:
        support_parts = RESOURCE_PARTS_MAPPING[resource]
        parts = set(parts.split(','))
        if not support_parts.issuperset(parts):
            not_support_parts = ','.join(parts.difference(support_parts))
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=ErrorCode.INVALID_PARAMS,
                    message=
                    f'Part {not_support_parts} for resource {resource} not support'
                ))
    def _fetch_token(self, params, return_json=False):
        """
        Use the google auth response to get access token

        Args:
            params (dict)
                The params to get access token.
            return_json (bool, optional):
                If True JSON data will be returned, instead of pyyoutube.AccessToken
        Return:
            Retrieved access token's info,  pyyoutube.AccessToken instance.
        """
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        try:
            response = self.session.post(self.EXCHANGE_ACCESS_TOKEN_URL,
                                         data=params,
                                         headers=headers,
                                         timeout=self._timeout,
                                         proxies=self.proxies)
        except requests.HTTPError as e:
            raise PyYouTubeException(
                ErrorMessage(status_code=10000, message=e.read()))
        data = self._parse_response(response)

        access_token = data['access_token']
        self._access_token = access_token
        # once get the refresh token. This token can be use long time.
        # refer: https://developers.google.com/identity/protocols/OAuth2
        refresh_token = data.get('refresh_token')
        if refresh_token is not None:
            self._refresh_token = refresh_token

        if return_json:
            return data
        else:
            return AccessToken.new_from_json_dict(data)
Exemple #23
0
    def _request(self,
                 resource,
                 method=None,
                 args=None,
                 post_args=None,
                 enforce_auth=True):
        """
        Main request sender.

        Args:
            resource(str)
                Resource field is which type data you want to retrieve.
                Such as channels,videos and so on.
            method(str, optional)
                The method this request to send request.
                Default is 'GET'
            args(dict, optional)
                The url params for this request.
            post_args(dict, optional)
                The Post params for this request.
            enforce_auth(bool, optional)
                Whether use google credentials
        Returns:
            response
        """
        if method is None:
            method = 'GET'

        if args is None:
            args = dict()

        if post_args is not None:
            method = 'POST'

        key = None
        access_token = None
        if self._api_key is not None:
            key = 'key'
            access_token = self._api_key
        if self._access_token is not None:
            key = 'access_token'
            access_token = self._access_token
        if access_token is None and enforce_auth:
            raise PyYouTubeException(
                ErrorMessage(status_code=ErrorCode.MISSING_PARAMS,
                             message='You must provide your credentials.'))

        if enforce_auth:
            if method == 'POST' and key not in post_args:
                post_args[key] = access_token
            elif method == 'GET' and key not in args:
                args[key] = access_token

        try:
            response = self.session.request(method=method,
                                            url=self.BASE_URL + resource,
                                            timeout=self._timeout,
                                            params=args,
                                            data=post_args,
                                            proxies=self.proxies)
        except requests.HTTPError as e:
            raise PyYouTubeException(
                ErrorMessage(status_code=ErrorCode.HTTP_ERROR, message=e.args))
        else:
            return response
    def get_playlist_item(self,
                          playlist_id=None,
                          playlist_item_id=None,
                          summary=True,
                          count=5,
                          limit=5,
                          return_json=False):
        """
        Retrieve channel playlistItems info.
        Provide two methods: by playlist ID, or by playlistItem id (ids)

        Args:
            playlist_id (str, optional)
                If provide channel id, this will return pointed playlist's item info.
            playlist_item_id (str,list optional)
                If provide this. will return those playlistItem's info.
            summary (bool, optional)
                 If True will return playlist item summary of metadata.
                 Notice this depend on your query.
            count (int, optional)
                The count will retrieve playlist items data.
                Default is 5.
            limit (int, optional)
                Each request retrieve playlistItems from data api.
                For playlistItem, this should not be more than 50.
                Default is 5
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.PlayListItem
        Returns:
            return tuple.
            (playlistItem data, playlistItem summary)
        """
        part = 'id,snippet,contentDetails,status'
        args = {'part': part, 'maxResults': limit}
        if playlist_id is not None:
            args['playlistId'] = playlist_id
        elif playlist_item_id is not None:
            if isinstance(playlist_item_id, str):
                p_id = playlist_item_id
            elif isinstance(playlist_item_id, (list, tuple)):
                p_id = ','.join(playlist_item_id)
            else:
                raise PyYouTubeException(
                    ErrorMessage(
                        status_code=10007,
                        message='PlaylistItem must be single id or id list.'))
            args['id'] = p_id
        else:
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=10005,
                    message=
                    'Specify at least one of channel id or playlist id(id list)'
                ))

        playlist_items = []
        playlist_items_summary = None
        next_page_token = None
        while True:
            prev_page_token, next_page_token, data = self.paged_by_page_token(
                resource='playlistItems',
                args=args,
                page_token=next_page_token,
            )
            items = self._parse_data(data)
            if return_json:
                playlist_items += items
            else:
                playlist_items += [
                    PlaylistItem.new_from_json_dict(item) for item in items
                ]
            if summary:
                playlist_items_summary = data.get('pageInfo', {})
            if next_page_token is None:
                break
            if len(playlist_items) >= count:
                break
        return playlist_items[:count], playlist_items_summary
    def get_comment_threads(self,
                            all_to_channel_id=None,
                            channel_id=None,
                            video_id=None,
                            order='time',
                            limit=20,
                            count=20,
                            return_json=False):
        """
        Retrieve the comment thread info by single id.
        Refer: https://developers.google.com/youtube/v3/docs/commentThreads/list
        Args:
            all_to_channel_id (str, optional)
                If you provide channel id by this parameter.
                Will return all comment threads associated with the specified channel.
                The response can include comments about the channel or about the channel's videos.
            channel_id (str, optional)
                If you provide channel id by this parameter.
                Will return comment threads containing comments about the specified channel.
                But not include comments about the channel's videos.
            video_id (str, optional)
                If you provide video id by this parameter.
                Will return comment threads containing comments about the specified video.
            order (str, optional)
                Provide the response order type. Valid value are: time, relevance.
                Default is time. order by the commented time.
            limit (int, optional)
                Each request retrieve comment threads from data api.
                For comment threads, this should not be more than 100.
                Default is 20.
            count (int, optional)
                The count will retrieve comment threads data.
                Default is 20.
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.CommentThread.
        Returns:
            The list data for you given comment thread.
        """
        part = 'id,snippet,replies'
        args = {'part': part, 'maxResults': limit}
        if all_to_channel_id is not None:
            args['allThreadsRelatedToChannelId'] = all_to_channel_id
        elif channel_id is not None:
            args['channelId'] = channel_id
        elif video_id is not None:
            args['videoId'] = video_id
        else:
            raise PyYouTubeException(
                ErrorMessage(
                    status_code=10007,
                    message=
                    'Target id must specify. either of all_to_channel_id, channel_id,video_id'
                ))

        if order not in ['time', 'relevance']:
            raise PyYouTubeException(
                ErrorMessage(status_code=10007,
                             message='Order type must be time or relevance.'))

        comment_threads = []
        next_page_token = None
        while True:
            _, next_page_token, data = self.paged_by_page_token(
                resource='commentThreads',
                args=args,
                page_token=next_page_token,
            )
            items = self._parse_data(data)
            if return_json:
                comment_threads += items
            else:
                comment_threads += [
                    CommentThread.new_from_json_dict(item) for item in items
                ]
            if next_page_token is None:
                break
            if len(comment_threads) >= count:
                break
        return comment_threads[:count]
Exemple #26
0
    def get_comment_threads(self,
                            all_to_channel_id=None,
                            channel_id=None,
                            video_id=None,
                            parts=None,
                            order='time',
                            search_term=None,
                            limit=20,
                            count=20,
                            return_json=False):
        """
        Retrieve the comment thread info by single id.

        Refer: https://developers.google.com/youtube/v3/docs/commentThreads/list

        Args:
            all_to_channel_id (str, optional)
                If you provide channel id by this parameter.
                Will return all comment threads associated with the specified channel.
                The response can include comments about the channel or about the channel's videos.
            channel_id (str, optional)
                If you provide channel id by this parameter.
                Will return comment threads containing comments about the specified channel.
                But not include comments about the channel's videos.
            video_id (str, optional)
                If you provide video id by this parameter.
                Will return comment threads containing comments about the specified video.
            parts (str, optional)
                Comma-separated list of one or more commentThreads resource properties.
                If not provided. will use default public properties.
            order (str, optional)
                Provide the response order type. Valid value are: time, relevance.
                Default is time. order by the commented time.
            search_term (str, optional)
                If you provide this. Only return the comments that contain the search terms.
            limit (int, optional)
                Each request retrieve comment threads from data api.
                For comment threads, this should not be more than 100.
                Default is 20.
            count (int, optional)
                The count will retrieve comment threads data.
                Default is 20.
            return_json(bool, optional)
                The return data type. If you set True JSON data will be returned.
                False will return pyyoutube.CommentThread.
        Returns:
            The list data for you given comment thread.
        """

        comma_separated_validator(parts=parts)
        incompatible_validator(all_to_channel_id=all_to_channel_id,
                               channel_id=channel_id,
                               video_id=video_id)
        if parts is None:
            parts = constants.COMMENT_THREAD_RESOURCE_PROPERTIES
            parts = ','.join(parts)
        else:
            parts_validator('commentThreads', parts=parts)

        args = {'part': parts, 'maxResults': limit}
        if all_to_channel_id is not None:
            args['allThreadsRelatedToChannelId'] = all_to_channel_id
        elif channel_id is not None:
            args['channelId'] = channel_id
        elif video_id is not None:
            args['videoId'] = video_id

        if order not in ['time', 'relevance']:
            raise PyYouTubeException(
                ErrorMessage(status_code=ErrorCode.INVALID_PARAMS,
                             message='Order type must be time or relevance.'))

        if search_term is not None:
            args['searchTerms'] = search_term

        comment_threads = []
        next_page_token = None
        while True:
            _, next_page_token, data = self.paged_by_page_token(
                resource='commentThreads',
                args=args,
                page_token=next_page_token,
            )
            items = self._parse_data(data)
            if return_json:
                comment_threads += items
            else:
                comment_threads += [
                    CommentThread.new_from_json_dict(item) for item in items
                ]
            if next_page_token is None:
                break
            if len(comment_threads) >= count:
                break
        return comment_threads[:count]