Comments
This commit is contained in:
parent
fc8cc85a04
commit
896d3b0cf6
17 changed files with 286 additions and 108 deletions
12
piped_api/__init__.py
Normal file
12
piped_api/__init__.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
import typing as t
|
||||
|
||||
|
||||
from .client import PipedClient
|
||||
|
||||
from .models.comments import Comments
|
||||
|
||||
|
||||
|
||||
# Supress unused-import warnings:
|
||||
if t.TYPE_CHECKING:
|
||||
_ = [PipedClient, Comments]
|
64
piped_api/client.py
Normal file
64
piped_api/client.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
import typing as t
|
||||
|
||||
from requests import Session
|
||||
|
||||
from .models import BasePipedModel
|
||||
from .models.comments import Comments
|
||||
|
||||
|
||||
_MDL = t.TypeVar('_MDL', bound=BasePipedModel)
|
||||
|
||||
|
||||
|
||||
class PipedClient:
|
||||
"""
|
||||
An API client for [Piped](https://piped.kavin.rocks).
|
||||
"""
|
||||
|
||||
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`
|
||||
"""
|
||||
|
||||
json = self.session.get(f"{self.base_api_url}{uri}", **kwargs).json()
|
||||
|
||||
if as_model is not None:
|
||||
return as_model(json)
|
||||
|
||||
return json
|
||||
|
||||
|
||||
|
||||
def get_comments(self, video_id: str, nextpage: t.Optional[t.Dict[str, t.Optional[str]]]=None) -> Comments:
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
if nextpage is not None:
|
||||
return self._get_json(f"/nextpage/comments/{video_id}", Comments, params={"nextpage": nextpage})
|
||||
|
||||
else:
|
||||
return self._get_json(f"/comments/{video_id}", Comments)
|
15
piped_api/models/__init__.py
Normal file
15
piped_api/models/__init__.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import typing as t
|
||||
|
||||
|
||||
class BasePipedModel:
|
||||
"""
|
||||
Base class for all Piped models.
|
||||
"""
|
||||
|
||||
def __init__(self, data: t.Dict[str, t.Any]) -> None:
|
||||
"""
|
||||
### Parameters:
|
||||
- `data` - The JSON (`dict`) data to initialize the model with.
|
||||
"""
|
||||
|
||||
self.data = data
|
141
piped_api/models/comments.py
Normal file
141
piped_api/models/comments.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
import typing as t
|
||||
|
||||
from . import BasePipedModel
|
||||
|
||||
|
||||
class Comments(BasePipedModel):
|
||||
class Comment(BasePipedModel):
|
||||
@property
|
||||
def author(self) -> str:
|
||||
"""
|
||||
The name of the author of the comment
|
||||
"""
|
||||
|
||||
return self.data['author']
|
||||
|
||||
|
||||
@property
|
||||
def comment_id(self) -> str:
|
||||
"""
|
||||
The comment ID
|
||||
"""
|
||||
|
||||
return self.data['commentId']
|
||||
|
||||
|
||||
@property
|
||||
def comment_text(self) -> str:
|
||||
"""
|
||||
The text of the comment
|
||||
"""
|
||||
|
||||
return self.data['commentText']
|
||||
|
||||
|
||||
@property
|
||||
def commented_time(self) -> str:
|
||||
"""
|
||||
The time the comment was made (format: `'x y ago'`)
|
||||
"""
|
||||
|
||||
return self.data['commentedTime']
|
||||
|
||||
|
||||
@property
|
||||
def commentor_url(self) -> str:
|
||||
"""
|
||||
The URL of the channel that made the comment
|
||||
"""
|
||||
|
||||
return self.data['commentorUrl']
|
||||
|
||||
|
||||
@property
|
||||
def replies_page(self) -> t.Optional[str]:
|
||||
"""
|
||||
Same as `Comments.nextpage`, but to load replies.
|
||||
|
||||
`None` means that there are no replies.
|
||||
"""
|
||||
|
||||
return self.data['repliesPage']
|
||||
|
||||
|
||||
@property
|
||||
def hearted(self) -> bool:
|
||||
"""
|
||||
Whether or not the comment has been hearted
|
||||
"""
|
||||
|
||||
return self.data['hearted']
|
||||
|
||||
|
||||
@property
|
||||
def like_count(self) -> int:
|
||||
"""
|
||||
The number of likes the comment has
|
||||
"""
|
||||
|
||||
return self.data['likeCount']
|
||||
|
||||
|
||||
@property
|
||||
def pinned(self) -> bool:
|
||||
"""
|
||||
Whether or not the comment is pinned
|
||||
"""
|
||||
|
||||
return self.data['pinned']
|
||||
|
||||
|
||||
@property
|
||||
def thumbnail(self) -> str:
|
||||
"""
|
||||
The thumbnail of the commentor's channel
|
||||
"""
|
||||
|
||||
return self.data['thumbnail']
|
||||
|
||||
|
||||
@property
|
||||
def verified(self) -> bool:
|
||||
"""
|
||||
Whether or not the author of the comment is verified
|
||||
"""
|
||||
|
||||
return self.data['verified']
|
||||
|
||||
|
||||
|
||||
def get_comments(self) -> t.List[Comment]:
|
||||
"""
|
||||
Obtain a list of comments
|
||||
"""
|
||||
|
||||
return [self.Comment(comment_json) for comment_json in self.data['comments']]
|
||||
|
||||
|
||||
def __iter__(self) -> t.Iterator[Comment]:
|
||||
iter(self.get_comments())
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def disabled(self) -> bool:
|
||||
"""
|
||||
Whether or not the comments are disabled
|
||||
"""
|
||||
|
||||
return self.data['disabled']
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def nextpage(self) -> t.Optional[str]:
|
||||
"""
|
||||
A JSON encoded page, which is used for the nextpage endpoint.
|
||||
|
||||
If there is no nextpage data, this returns `None`.
|
||||
"""
|
||||
|
||||
return self.data['nextpage']
|
Loading…
Add table
Add a link
Reference in a new issue