python-piped-api-client/piped_api/client.py

134 lines
4.9 KiB
Python
Raw Normal View History

2022-02-26 09:35:58 +00:00
import typing as t
from requests import Session
from .models import BasePipedModel
from .models.comments import Comments
2022-02-26 18:02:26 +00:00
from .models.videos import Video
2022-02-27 17:08:39 +00:00
from .models.channels import Channel
2022-02-26 09:35:58 +00:00
2022-02-26 18:02:26 +00:00
_MDL = t.TypeVar('_MDL', bound=t.Type[BasePipedModel])
2022-02-26 09:35:58 +00:00
2022-02-27 17:20:42 +00:00
class APIError(Exception): """Raised when an API call fails"""
2022-02-26 09:35:58 +00:00
class PipedClient:
"""
An API client for [Piped](https://piped.kavin.rocks).
2022-02-27 17:20:42 +00:00
See also [Piped API docs](https://piped-docs.kavin.rocks/docs)
2022-02-26 09:35:58 +00:00
"""
def __init__(self, base_api_url: str='https://pipedapi.kavin.rocks', session: t.Type[Session]=Session()) -> None:
"""
### Parameters:
- `base_api_url` - The base URL to the instance's API. Trailing slashes will be stripped.
- `session` - A class/subclass of `requests.Session` to use for all requests.
For example, you could use [requests-cache](https://pypi.org/project/requests-cache/) to make all requests cacheable.
"""
self.base_api_url = base_api_url.strip("/")
self.session = session
def _get_json(self, uri: str, as_model: t.Optional[_MDL]=None, **kwargs) -> t.Union[_MDL, t.Dict[str, t.Any]]:
"""
Obtains JSON data from specific URI of the Piped API.
### Parameters:
- `uri` - The URI to get JSON data from
- `as_model` - The `BasePipedModel` to load the JSON data into. If this is `None`, the JSON data is returned as a `dict`.
- `**kwargs` - Additional keyword arguments to pass to `requests.Session.get`
"""
2022-02-27 17:20:42 +00:00
json: dict = self.session.get(f"{self.base_api_url}{uri}", **kwargs).json()
if json.get('error', None) is not None:
raise APIError(f"Error: {json['error']}")
2022-02-26 09:35:58 +00:00
if as_model is not None:
return as_model(json)
return json
2022-02-27 17:08:39 +00:00
def get_comments(self, video_id: str, nextpage: t.Optional[t.Dict[str, t.Optional[str]]]=None, **kwargs) -> Comments:
2022-02-26 09:35:58 +00:00
"""
Gets a list of comments for a specific video.
### Parameters:
- `video_id` - The ID of the video to get comments for
- `nextpage` - Nextpage data, obtained from `.models.comments.Comments.nextpage` property. If this is `None`, the first page of comments is returned.
There are often 20 comments per page.
2022-02-27 17:08:39 +00:00
- `**kwargs` - Additional keyword arguments to pass to `requests.Session.get`
2022-02-26 09:35:58 +00:00
"""
2022-02-27 17:08:39 +00:00
kw = kwargs.copy()
2022-02-26 09:35:58 +00:00
if nextpage is not None:
2022-02-27 17:20:42 +00:00
kw.update({'params': {'nextpage': nextpage}})
2022-02-27 17:08:39 +00:00
return self._get_json(f"/nextpage/comments/{video_id}", Comments, **kw)
2022-02-26 09:35:58 +00:00
else:
2022-02-27 17:08:39 +00:00
return self._get_json(f"/comments/{video_id}", Comments, **kw)
2022-02-26 18:02:26 +00:00
2022-02-27 17:08:39 +00:00
def get_video(self, video_id: str, **kwargs) -> Video:
2022-02-26 18:02:26 +00:00
"""
Gets information about a specific video.
### Parameters:
- `video_id` - The ID of the video to get information for
2022-02-27 17:08:39 +00:00
- `**kwargs` - Additional keyword arguments to pass to `requests.Session.get`
2022-02-26 18:02:26 +00:00
"""
2022-02-27 17:08:39 +00:00
return self._get_json(f"/streams/{video_id}", Video, **kwargs)
2022-02-27 07:40:58 +00:00
2022-02-27 17:08:39 +00:00
def get_trending(self, country_code: str='US', **kwargs) -> t.List[Video.RelatedStream]:
2022-02-27 07:40:58 +00:00
"""
Obtains trending videos for a specific country. If there are no trending videos (or `country_code` is invalid),
an empty list is returned.
### Parameters:
- `country_code` - The country code ([ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements)) to get trending videos for. This is automatically capitalized by this package,
since Piped for some reason doesn't accept lowercase country codes. Note: countries such as China or North Korea don't have trending videos, so they will always return an empty list.
2022-02-27 17:08:39 +00:00
- `**kwargs` - Additional keyword arguments to pass to `requests.Session.get`
"""
kw = kwargs.copy()
kw.update({'params': {'region': country_code.upper()}})
return [Video.RelatedStream(trending_video) for trending_video in self._get_json(f"/trending", **kw)]
2022-02-27 17:20:42 +00:00
def get_channel_by_id(self, channel_id: str, **kwargs) -> Channel:
2022-02-27 17:08:39 +00:00
"""
2022-02-27 17:20:42 +00:00
Gets information about a specific channel by its ID.
2022-02-27 17:08:39 +00:00
### Parameters:
- `channel_id` - The ID of the channel to get information for
- `**kwargs` - Additional keyword arguments to pass to `requests.Session.get`
2022-02-27 07:40:58 +00:00
"""
2022-02-27 17:20:42 +00:00
return self._get_json(f"/channel/{channel_id}", Channel, **kwargs)
def get_channel_by_name(self, channel_name: str, **kwargs) -> Channel:
"""
Gets information about a specific channel by its name.
### Parameters:
- `channel_name` - The name of the channel to get information for
- `**kwargs` - Additional keyword arguments to pass to `requests.Session.get`
"""
return self._get_json(f"/c/{channel_name}", Channel, **kwargs)