|
|
|
@ -1,13 +1,19 @@
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from typing import TYPE_CHECKING, AsyncGenerator, Literal
|
|
|
|
|
from typing import TYPE_CHECKING, AsyncGenerator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from mipac.abstract.action import AbstractAction
|
|
|
|
|
from mipac.errors.base import ParameterError
|
|
|
|
|
from mipac.file import MiFile
|
|
|
|
|
from mipac.http import HTTPClient, Route
|
|
|
|
|
from mipac.models.channel import Channel
|
|
|
|
|
from mipac.models.lite.channel import ChannelLite
|
|
|
|
|
from mipac.models.drive import File
|
|
|
|
|
from mipac.models.poll import MiPoll
|
|
|
|
|
from mipac.types.channel import IChannel
|
|
|
|
|
from mipac.types.note import INote, INoteVisibility
|
|
|
|
|
from mipac.types.reaction import IReactionAcceptance
|
|
|
|
|
from mipac.utils.util import credentials_required
|
|
|
|
|
from mipac.models.note import Note
|
|
|
|
|
from mipac.utils.pagination import Pagination
|
|
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
@ -22,423 +28,524 @@ class ClientChannelActions(AbstractAction):
|
|
|
|
|
self._session: HTTPClient = session
|
|
|
|
|
self._client: ClientManager = client
|
|
|
|
|
|
|
|
|
|
async def favorite(self, channel_id: str | None = None):
|
|
|
|
|
"""
|
|
|
|
|
Favorite a channel.
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def send(
|
|
|
|
|
self,
|
|
|
|
|
text: str | None = None,
|
|
|
|
|
visibility: INoteVisibility = "public",
|
|
|
|
|
visible_user_ids: list[str] | None = None,
|
|
|
|
|
cw: str | None = None,
|
|
|
|
|
local_only: bool = False,
|
|
|
|
|
reaction_acceptance: IReactionAcceptance = None,
|
|
|
|
|
extract_mentions: bool = True, # 元は noExtractMentions
|
|
|
|
|
extract_hashtags: bool = True, # 元は noExtractHashtags
|
|
|
|
|
extract_emojis: bool = True, # 元は noExtractEmojis
|
|
|
|
|
reply_id: str | None = None,
|
|
|
|
|
renote_id: str | None = None,
|
|
|
|
|
files: list[MiFile | File | str] | None = None,
|
|
|
|
|
poll: MiPoll | None = None,
|
|
|
|
|
*,
|
|
|
|
|
channel_id: str | None = None,
|
|
|
|
|
) -> Note:
|
|
|
|
|
"""Send a note
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/notes/create`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str, optional, by default None
|
|
|
|
|
Channel id
|
|
|
|
|
text : str, optional
|
|
|
|
|
Text of the note, by default None
|
|
|
|
|
visibility : INoteVisibility, optional
|
|
|
|
|
Visibility of the note, by default "public"
|
|
|
|
|
visible_user_ids : list[str], optional
|
|
|
|
|
Visible user IDs, by default None
|
|
|
|
|
cw : str, optional
|
|
|
|
|
CW of the note, by default None
|
|
|
|
|
local_only : bool, optional
|
|
|
|
|
Whether the note is local only, by default False
|
|
|
|
|
reaction_acceptance : IReactionAcceptance, optional
|
|
|
|
|
Reaction acceptance of the note, by default None
|
|
|
|
|
extract_mentions : bool, optional
|
|
|
|
|
Whether to extract mentions, by default True
|
|
|
|
|
extract_hashtags : bool, optional
|
|
|
|
|
Whether to extract hashtags, by default True
|
|
|
|
|
extract_emojis : bool, optional
|
|
|
|
|
Whether to extract emojis, by default True
|
|
|
|
|
reply_id : str, optional
|
|
|
|
|
Reply ID, by default None
|
|
|
|
|
renote_id : str, optional
|
|
|
|
|
Renote ID, by default None
|
|
|
|
|
files : list[MiFile | File | str], optional
|
|
|
|
|
Files, by default None
|
|
|
|
|
poll : MiPoll, optional
|
|
|
|
|
Poll, by default None
|
|
|
|
|
channel_id : str, optional
|
|
|
|
|
ID of the channel, by default None
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
bool
|
|
|
|
|
True if success else False
|
|
|
|
|
Note
|
|
|
|
|
Created note
|
|
|
|
|
"""
|
|
|
|
|
channel_id = self._channel_id or channel_id
|
|
|
|
|
if channel_id is None:
|
|
|
|
|
raise Exception()
|
|
|
|
|
|
|
|
|
|
res: bool = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/favorite"), auth=True, json={"channelId": channel_id}
|
|
|
|
|
channel_id = channel_id or self._channel_id
|
|
|
|
|
return await self._client.note.action.send(
|
|
|
|
|
text=text,
|
|
|
|
|
cw=cw,
|
|
|
|
|
files=files,
|
|
|
|
|
poll=poll,
|
|
|
|
|
visibility=visibility,
|
|
|
|
|
visible_user_ids=visible_user_ids,
|
|
|
|
|
reaction_acceptance=reaction_acceptance,
|
|
|
|
|
extract_mentions=extract_mentions,
|
|
|
|
|
extract_hashtags=extract_hashtags,
|
|
|
|
|
extract_emojis=extract_emojis,
|
|
|
|
|
reply_id=reply_id,
|
|
|
|
|
renote_id=renote_id,
|
|
|
|
|
channel_id=channel_id,
|
|
|
|
|
local_only=local_only,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def follow(self, *, channel_id: str | None = None) -> bool:
|
|
|
|
|
"""Follow a channel
|
|
|
|
|
|
|
|
|
|
async def unfavorite(self, channel_id: str | None = None):
|
|
|
|
|
"""
|
|
|
|
|
Unfavorite a channel.
|
|
|
|
|
Endpoint: `/api/channels/follow`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str, optional, by default None
|
|
|
|
|
Channel id
|
|
|
|
|
channel_id : str, optional
|
|
|
|
|
ID of the channel, by default None
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
bool
|
|
|
|
|
True if success else False
|
|
|
|
|
Whether the channel is followed
|
|
|
|
|
"""
|
|
|
|
|
channel_id = self._channel_id or channel_id
|
|
|
|
|
if channel_id is None:
|
|
|
|
|
raise Exception()
|
|
|
|
|
channel_id = channel_id or self._channel_id
|
|
|
|
|
data = {"channelId": channel_id}
|
|
|
|
|
|
|
|
|
|
res: bool = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/unfavorite"), auth=True, json={"channelId": channel_id}
|
|
|
|
|
Route("POST", "/api/channels/follow"), json=data, auth=True, lower=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
async def follow(self, channel_id: str | None = None) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Follow a channel.
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def unfollow(self, *, channel_id: str | None = None) -> bool:
|
|
|
|
|
"""Unfollow a channel
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/channels/unfollow`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str, optional, by default None
|
|
|
|
|
Channel id
|
|
|
|
|
channel_id : str, optional
|
|
|
|
|
ID of the channel, by default None
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
bool
|
|
|
|
|
True if success else False
|
|
|
|
|
Whether the channel is unfollowed
|
|
|
|
|
"""
|
|
|
|
|
channel_id = self._channel_id or channel_id
|
|
|
|
|
if channel_id is None:
|
|
|
|
|
raise ParameterError("required channel_id")
|
|
|
|
|
channel_id = channel_id or self._channel_id
|
|
|
|
|
data = {"channelId": channel_id}
|
|
|
|
|
|
|
|
|
|
res: bool = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/follow"), auth=True, json={"channelId": channel_id}
|
|
|
|
|
Route("POST", "/api/channels/unfollow"), json=data, auth=True, lower=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
async def unfollow(self, channel_id: str | None = None) -> bool:
|
|
|
|
|
"""
|
|
|
|
|
Unfollow a channel.
|
|
|
|
|
async def timeline(
|
|
|
|
|
self,
|
|
|
|
|
limit: int = 10,
|
|
|
|
|
since_id: str | None = None,
|
|
|
|
|
until_id: str | None = None,
|
|
|
|
|
since_date: int | None = None,
|
|
|
|
|
until_date: int | None = None,
|
|
|
|
|
*,
|
|
|
|
|
channel_id: str | None = None,
|
|
|
|
|
) -> list[Note]:
|
|
|
|
|
"""Get the timeline of a channel
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/channels/timeline`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str, optional, by default None
|
|
|
|
|
Channel id
|
|
|
|
|
limit : int, optional
|
|
|
|
|
Limit, by default 10
|
|
|
|
|
since_id : str, optional
|
|
|
|
|
Since ID, by default None
|
|
|
|
|
until_id : str, optional
|
|
|
|
|
Until ID, by default None
|
|
|
|
|
since_date : int, optional
|
|
|
|
|
Since date, by default None
|
|
|
|
|
until_date : int, optional
|
|
|
|
|
Until date, by default None
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
bool
|
|
|
|
|
True if success else False
|
|
|
|
|
list[Note]
|
|
|
|
|
List of notes
|
|
|
|
|
"""
|
|
|
|
|
channel_id = self._channel_id or channel_id
|
|
|
|
|
if channel_id is None:
|
|
|
|
|
raise ParameterError("required channel_id")
|
|
|
|
|
channel_id = channel_id or self._channel_id
|
|
|
|
|
data = {
|
|
|
|
|
"channelId": channel_id,
|
|
|
|
|
"limit": limit,
|
|
|
|
|
"sinceId": since_id,
|
|
|
|
|
"untilId": until_id,
|
|
|
|
|
"sinceDate": since_date,
|
|
|
|
|
"untilDate": until_date,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res: bool = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/unfollow"), auth=True, json={"channelId": channel_id}
|
|
|
|
|
raw_notes: list[INote] = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/timeline"), json=data, auth=True, lower=True
|
|
|
|
|
)
|
|
|
|
|
return [Note(raw_note=raw_note, client=self._client) for raw_note in raw_notes]
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
async def update(
|
|
|
|
|
async def get_all_timeline(
|
|
|
|
|
self,
|
|
|
|
|
name: str | None = None,
|
|
|
|
|
description: str | None = None,
|
|
|
|
|
banner_id: str | None = None,
|
|
|
|
|
is_archived: bool | None = None,
|
|
|
|
|
pinned_note_ids: list[str] | None = None,
|
|
|
|
|
color: str | None = None,
|
|
|
|
|
since_id: str | None = None,
|
|
|
|
|
until_id: str | None = None,
|
|
|
|
|
since_date: int | None = None,
|
|
|
|
|
until_date: int | None = None,
|
|
|
|
|
*,
|
|
|
|
|
channel_id: str | None = None,
|
|
|
|
|
) -> Channel:
|
|
|
|
|
"""
|
|
|
|
|
Update a channel.
|
|
|
|
|
) -> AsyncGenerator[Note, None]:
|
|
|
|
|
"""Get all notes in the timeline of a channel
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
name : str, optional, by default None
|
|
|
|
|
Channel name
|
|
|
|
|
description : str, optional, by default None
|
|
|
|
|
Channel description
|
|
|
|
|
banner_id : str, optional, by default None
|
|
|
|
|
Channel banner id
|
|
|
|
|
is_archived : bool, optional, by default None
|
|
|
|
|
Channel is archived
|
|
|
|
|
pinned_note_ids : list[str], optional, by default None
|
|
|
|
|
Channel pinned note ids
|
|
|
|
|
color : str, optional, by default None
|
|
|
|
|
Channel color
|
|
|
|
|
channel_id : str, optional, by default None
|
|
|
|
|
Channel id
|
|
|
|
|
since_id : str, optional
|
|
|
|
|
Since ID, by default None
|
|
|
|
|
until_id : str, optional
|
|
|
|
|
Until ID, by default None
|
|
|
|
|
since_date : int, optional
|
|
|
|
|
Since date, by default None
|
|
|
|
|
until_date : int, optional
|
|
|
|
|
Until date, by default None
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
Channel
|
|
|
|
|
Channel
|
|
|
|
|
AsyncGenerator[Note, None]
|
|
|
|
|
Async generator of notes
|
|
|
|
|
"""
|
|
|
|
|
channel_id = self._channel_id or channel_id
|
|
|
|
|
if channel_id is None:
|
|
|
|
|
raise ParameterError("required channel_id")
|
|
|
|
|
|
|
|
|
|
body = {
|
|
|
|
|
channel_id = channel_id or self._channel_id
|
|
|
|
|
data = {
|
|
|
|
|
"channelId": channel_id,
|
|
|
|
|
"name": name,
|
|
|
|
|
"description": description,
|
|
|
|
|
"bannerId": banner_id,
|
|
|
|
|
"isArchived": is_archived,
|
|
|
|
|
"pinnedNoteIds": pinned_note_ids,
|
|
|
|
|
"color": color,
|
|
|
|
|
"sinceId": since_id,
|
|
|
|
|
"untilId": until_id,
|
|
|
|
|
"sinceDate": since_date,
|
|
|
|
|
"untilDate": until_date,
|
|
|
|
|
}
|
|
|
|
|
res: IChannel = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/update"), auth=True, json=body
|
|
|
|
|
pagination = Pagination[INote](
|
|
|
|
|
self._session, Route("POST", "/api/channels/timeline"), auth=True, json=data
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return Channel(res, client=self._client)
|
|
|
|
|
|
|
|
|
|
async def archive(self, channel_id: str | None = None) -> Channel:
|
|
|
|
|
"""
|
|
|
|
|
Archive a channel.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str, optional, by default None
|
|
|
|
|
Channel id
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
Channel
|
|
|
|
|
Channel
|
|
|
|
|
"""
|
|
|
|
|
channel_id = self._channel_id or channel_id
|
|
|
|
|
if channel_id is None:
|
|
|
|
|
raise ParameterError("required channel_id")
|
|
|
|
|
while pagination.is_final is False:
|
|
|
|
|
raw_notes: list[INote] = await pagination.next()
|
|
|
|
|
for raw_note in raw_notes:
|
|
|
|
|
yield Note(raw_note=raw_note, client=self._client)
|
|
|
|
|
|
|
|
|
|
res = await self.update(channel_id=channel_id, is_archived=True)
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
class ChannelActions(ClientChannelActions):
|
|
|
|
|
def __init__(
|
|
|
|
|
self, channel_id: str | None = None, *, session: HTTPClient, client: ClientManager
|
|
|
|
|
):
|
|
|
|
|
super().__init__(channel_id=channel_id, session=session, client=client)
|
|
|
|
|
|
|
|
|
|
async def unarchive(self, channel_id: str | None = None) -> Channel:
|
|
|
|
|
"""
|
|
|
|
|
Unarchive a channel.
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def send(
|
|
|
|
|
self,
|
|
|
|
|
channel_id: str,
|
|
|
|
|
text: str | None = None,
|
|
|
|
|
visibility: INoteVisibility = "public",
|
|
|
|
|
visible_user_ids: list[str] | None = None,
|
|
|
|
|
cw: str | None = None,
|
|
|
|
|
local_only: bool = False,
|
|
|
|
|
reaction_acceptance: IReactionAcceptance = None,
|
|
|
|
|
extract_mentions: bool = True, # 元は noExtractMentions
|
|
|
|
|
extract_hashtags: bool = True, # 元は noExtractHashtags
|
|
|
|
|
extract_emojis: bool = True, # 元は noExtractEmojis
|
|
|
|
|
reply_id: str | None = None,
|
|
|
|
|
renote_id: str | None = None,
|
|
|
|
|
files: list[MiFile | File | str] | None = None,
|
|
|
|
|
poll: MiPoll | None = None,
|
|
|
|
|
) -> Note:
|
|
|
|
|
"""Send a note
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/notes/create`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str, optional, by default None
|
|
|
|
|
Channel id
|
|
|
|
|
text : str, optional
|
|
|
|
|
Text of the note, by default None
|
|
|
|
|
visibility : INoteVisibility, optional
|
|
|
|
|
Visibility of the note, by default "public"
|
|
|
|
|
visible_user_ids : list[str], optional
|
|
|
|
|
Visible user IDs, by default None
|
|
|
|
|
cw : str, optional
|
|
|
|
|
CW of the note, by default None
|
|
|
|
|
local_only : bool, optional
|
|
|
|
|
Whether the note is local only, by default False
|
|
|
|
|
reaction_acceptance : IReactionAcceptance, optional
|
|
|
|
|
Reaction acceptance of the note, by default None
|
|
|
|
|
extract_mentions : bool, optional
|
|
|
|
|
Whether to extract mentions, by default True
|
|
|
|
|
extract_hashtags : bool, optional
|
|
|
|
|
Whether to extract hashtags, by default True
|
|
|
|
|
extract_emojis : bool, optional
|
|
|
|
|
Whether to extract emojis, by default True
|
|
|
|
|
reply_id : str, optional
|
|
|
|
|
Reply ID, by default None
|
|
|
|
|
renote_id : str, optional
|
|
|
|
|
Renote ID, by default None
|
|
|
|
|
files : list[MiFile | File | str], optional
|
|
|
|
|
Files, by default None
|
|
|
|
|
poll : MiPoll, optional
|
|
|
|
|
Poll, by default None
|
|
|
|
|
channel_id : str, optional
|
|
|
|
|
ID of the channel, by default None
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
Channel
|
|
|
|
|
Channel
|
|
|
|
|
Note
|
|
|
|
|
Created note
|
|
|
|
|
"""
|
|
|
|
|
channel_id = self._channel_id or channel_id
|
|
|
|
|
if channel_id is None:
|
|
|
|
|
raise ParameterError("required channel_id")
|
|
|
|
|
|
|
|
|
|
res = await self.update(channel_id=channel_id, is_archived=False)
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChannelActions(ClientChannelActions):
|
|
|
|
|
def __init__(
|
|
|
|
|
self, channel_id: str | None = None, *, session: HTTPClient, client: ClientManager
|
|
|
|
|
):
|
|
|
|
|
super().__init__(channel_id=channel_id, session=session, client=client)
|
|
|
|
|
return await super().send(
|
|
|
|
|
text=text,
|
|
|
|
|
cw=cw,
|
|
|
|
|
files=files,
|
|
|
|
|
poll=poll,
|
|
|
|
|
visibility=visibility,
|
|
|
|
|
visible_user_ids=visible_user_ids,
|
|
|
|
|
reaction_acceptance=reaction_acceptance,
|
|
|
|
|
extract_mentions=extract_mentions,
|
|
|
|
|
extract_hashtags=extract_hashtags,
|
|
|
|
|
extract_emojis=extract_emojis,
|
|
|
|
|
reply_id=reply_id,
|
|
|
|
|
renote_id=renote_id,
|
|
|
|
|
channel_id=channel_id,
|
|
|
|
|
local_only=local_only,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def create(
|
|
|
|
|
self,
|
|
|
|
|
name: str,
|
|
|
|
|
color: str,
|
|
|
|
|
description: str | None = None,
|
|
|
|
|
banner_id: str | None = None,
|
|
|
|
|
color: str = "#000",
|
|
|
|
|
) -> ChannelLite:
|
|
|
|
|
"""
|
|
|
|
|
Create a channel.
|
|
|
|
|
is_sensitive: bool | None = None,
|
|
|
|
|
allow_renote_to_external: bool | None = None,
|
|
|
|
|
) -> Channel:
|
|
|
|
|
"""Create a channel
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/channels/create`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
name : str
|
|
|
|
|
Channel name.
|
|
|
|
|
description : str, optional, by default None
|
|
|
|
|
Channel description
|
|
|
|
|
banner_id : str, optional, by default None
|
|
|
|
|
Channel banner id
|
|
|
|
|
color : str, optional, by default '#000'
|
|
|
|
|
Channel color
|
|
|
|
|
Name of the channel
|
|
|
|
|
color : str
|
|
|
|
|
Color of the channel
|
|
|
|
|
description : str, optional
|
|
|
|
|
Description of the channel, by default None
|
|
|
|
|
banner_id : str, optional
|
|
|
|
|
Banner ID of the channel, by default None
|
|
|
|
|
is_sensitive : bool, optional
|
|
|
|
|
Whether the channel is sensitive, by default None
|
|
|
|
|
allow_renote_to_external : bool, optional
|
|
|
|
|
Whether the channel allows renote to external, by default None
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
Channel
|
|
|
|
|
ChannelLite
|
|
|
|
|
Created channel
|
|
|
|
|
"""
|
|
|
|
|
body = {"name": name, "description": description, "bannerId": banner_id, "color": color}
|
|
|
|
|
res: IChannel = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/create"), auth=True, json=body
|
|
|
|
|
data = {
|
|
|
|
|
"name": name,
|
|
|
|
|
"color": color,
|
|
|
|
|
"description": description,
|
|
|
|
|
"banner_id": banner_id,
|
|
|
|
|
"is_sensitive": is_sensitive,
|
|
|
|
|
"allow_renote_to_external": allow_renote_to_external,
|
|
|
|
|
}
|
|
|
|
|
raw_channel: IChannel = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/create"),
|
|
|
|
|
json=data,
|
|
|
|
|
auth=True,
|
|
|
|
|
lower=True,
|
|
|
|
|
remove_none=False,
|
|
|
|
|
)
|
|
|
|
|
return Channel(raw_channel=raw_channel, client=self._client)
|
|
|
|
|
|
|
|
|
|
return ChannelLite(res, client=self._client)
|
|
|
|
|
async def featured(self) -> list[Channel]:
|
|
|
|
|
"""Get featured channels
|
|
|
|
|
|
|
|
|
|
async def get_featured(self) -> list[Channel]:
|
|
|
|
|
"""
|
|
|
|
|
Get featured channels.
|
|
|
|
|
Endpoint: `/api/channels/featured`
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
list[Channel]
|
|
|
|
|
Channel
|
|
|
|
|
List of featured channels
|
|
|
|
|
"""
|
|
|
|
|
res: list[IChannel] = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/featured"), auth=True
|
|
|
|
|
|
|
|
|
|
raw_channels: list[IChannel] = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/featured"), auth=True, lower=True
|
|
|
|
|
)
|
|
|
|
|
return [Channel(i, client=self._client) for i in res]
|
|
|
|
|
return [
|
|
|
|
|
Channel(raw_channel=raw_channel, client=self._client) for raw_channel in raw_channels
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
async def get_followed(
|
|
|
|
|
self,
|
|
|
|
|
since_id: str | None = None,
|
|
|
|
|
until_id: str | None = None,
|
|
|
|
|
limit: int = 10,
|
|
|
|
|
*,
|
|
|
|
|
get_all: bool = False,
|
|
|
|
|
) -> AsyncGenerator[Channel, None]:
|
|
|
|
|
"""
|
|
|
|
|
Get followed channels.
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def follow(self, channel_id: str) -> bool:
|
|
|
|
|
"""Follow a channel
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/channels/follow`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
since_id : str, optional, by default None
|
|
|
|
|
Since id
|
|
|
|
|
until_id : str, optional, by default None
|
|
|
|
|
Until id
|
|
|
|
|
limit : int, optional, by default 10
|
|
|
|
|
Limit
|
|
|
|
|
get_all : bool, optional, by default False
|
|
|
|
|
Get all channels flag
|
|
|
|
|
|
|
|
|
|
Yields
|
|
|
|
|
channel_id : str
|
|
|
|
|
ID of the channel
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
AsyncGenerator[Channel, None]
|
|
|
|
|
Channel
|
|
|
|
|
bool
|
|
|
|
|
Whether the channel is followed
|
|
|
|
|
"""
|
|
|
|
|
if limit > 100:
|
|
|
|
|
raise ParameterError("limit must be less than 100")
|
|
|
|
|
return await super().follow(channel_id=channel_id)
|
|
|
|
|
|
|
|
|
|
if get_all:
|
|
|
|
|
limit = 100
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def followed(
|
|
|
|
|
self, since_id: str | None = None, until_id: str | None = None, limit: int = 5
|
|
|
|
|
) -> list[Channel]:
|
|
|
|
|
"""Get followed channels
|
|
|
|
|
|
|
|
|
|
body = {"sinceId": since_id, "untilId": until_id, "limit": limit}
|
|
|
|
|
Endpoint: `/api/channels/followed`
|
|
|
|
|
|
|
|
|
|
pagination = Pagination[IChannel](
|
|
|
|
|
self._session, Route("POST", "/api/channels/followed"), auth=True, json=body
|
|
|
|
|
)
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
since_id : str, optional
|
|
|
|
|
Since ID, by default None
|
|
|
|
|
until_id : str, optional
|
|
|
|
|
Until ID, by default None
|
|
|
|
|
limit : int, optional
|
|
|
|
|
Limit, by default 5
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
raw_channels = await pagination.next()
|
|
|
|
|
for raw_channel in raw_channels:
|
|
|
|
|
yield Channel(raw_channel, client=self._client)
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
list[Channel]
|
|
|
|
|
List of followed channels
|
|
|
|
|
"""
|
|
|
|
|
data = {"sinceId": since_id, "untilId": until_id, "limit": limit}
|
|
|
|
|
|
|
|
|
|
if get_all is False or pagination.is_final:
|
|
|
|
|
break
|
|
|
|
|
raw_channels: list[IChannel] = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/followed"), auth=True, json=data
|
|
|
|
|
)
|
|
|
|
|
return [
|
|
|
|
|
Channel(raw_channel=raw_channel, client=self._client) for raw_channel in raw_channels
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
async def get_owned(
|
|
|
|
|
self, since_id: str | None = None, until_id: str | None = None, *, get_all: bool = False
|
|
|
|
|
) -> AsyncGenerator[Channel, None]:
|
|
|
|
|
"""
|
|
|
|
|
Get owned channels.
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def owned(
|
|
|
|
|
self, since_id: str | None = None, until_id: str | None = None, limit: int = 5
|
|
|
|
|
) -> list[Channel]:
|
|
|
|
|
"""Get owned channels
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/channels/owned`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
since_id : str, optional, by default None
|
|
|
|
|
Since id
|
|
|
|
|
until_id : str, optional, by default None
|
|
|
|
|
Until id
|
|
|
|
|
get_all : bool, optional, by default False
|
|
|
|
|
Get all channels flag
|
|
|
|
|
|
|
|
|
|
Yields
|
|
|
|
|
------
|
|
|
|
|
AsyncGenerator[Channel, None]
|
|
|
|
|
Channel
|
|
|
|
|
since_id : str, optional
|
|
|
|
|
Since ID, by default None
|
|
|
|
|
until_id : str, optional
|
|
|
|
|
Until ID, by default None
|
|
|
|
|
limit : int, optional
|
|
|
|
|
Limit, by default 5
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
list[Channel]
|
|
|
|
|
List of owned channels
|
|
|
|
|
"""
|
|
|
|
|
body = {"sinceId": since_id, "untilId": until_id}
|
|
|
|
|
data = {"sinceId": since_id, "untilId": until_id, "limit": limit}
|
|
|
|
|
|
|
|
|
|
pagination = Pagination[IChannel](
|
|
|
|
|
self._session, Route("POST", "/api/channels/owned"), auth=True, json=body
|
|
|
|
|
raw_channels: list[IChannel] = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/owned"), auth=True, json=data
|
|
|
|
|
)
|
|
|
|
|
return [
|
|
|
|
|
Channel(raw_channel=raw_channel, client=self._client) for raw_channel in raw_channels
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
raw_channels = await pagination.next()
|
|
|
|
|
for raw_channel in raw_channels:
|
|
|
|
|
yield Channel(raw_channel, client=self._client)
|
|
|
|
|
async def show(self, channel_id: str) -> Channel:
|
|
|
|
|
"""Show a channel
|
|
|
|
|
|
|
|
|
|
if get_all is False or pagination.is_final:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
async def get(self, channel_id: str) -> Channel:
|
|
|
|
|
"""
|
|
|
|
|
Get a channel.
|
|
|
|
|
Endpoint: `/api/channels/show`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str
|
|
|
|
|
Channel id
|
|
|
|
|
ID of the channel
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
Channel
|
|
|
|
|
Channel
|
|
|
|
|
"""
|
|
|
|
|
res: IChannel = await self._session.request(
|
|
|
|
|
raw_channel: IChannel = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/show"), auth=True, json={"channelId": channel_id}
|
|
|
|
|
)
|
|
|
|
|
return Channel(res, client=self._client)
|
|
|
|
|
return Channel(raw_channel=raw_channel, client=self._client)
|
|
|
|
|
|
|
|
|
|
async def get_my_favorite(self) -> list[Channel]:
|
|
|
|
|
"""
|
|
|
|
|
Get my favorite channels.
|
|
|
|
|
@credentials_required
|
|
|
|
|
async def unfollow(self, channel_id: str) -> bool:
|
|
|
|
|
"""Unfollow a channel
|
|
|
|
|
|
|
|
|
|
Endpoint: `/api/channels/unfollow`
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
channel_id : str
|
|
|
|
|
ID of the channel
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
list[Channel]
|
|
|
|
|
Channel
|
|
|
|
|
bool
|
|
|
|
|
Whether the channel is unfollowed
|
|
|
|
|
"""
|
|
|
|
|
res: list[IChannel] = await self._session.request(
|
|
|
|
|
Route("POST", "/api/channels/my-favorites"), auth=True
|
|
|
|
|
)
|
|
|
|
|
return [Channel(i, client=self._client) for i in res]
|
|
|
|
|
return await super().unfollow(channel_id=channel_id)
|
|
|
|
|
|
|
|
|
|
async def search(
|
|
|
|
|
async def get_all_timeline(
|
|
|
|
|
self,
|
|
|
|
|
query: str,
|
|
|
|
|
type: Literal["nameAndDescription", "nameOnly"] = "nameAndDescription",
|
|
|
|
|
channel_id: str,
|
|
|
|
|
since_id: str | None = None,
|
|
|
|
|
until_id: str | None = None,
|
|
|
|
|
limit: int = 5,
|
|
|
|
|
get_all: bool = False,
|
|
|
|
|
) -> AsyncGenerator[Channel, None]:
|
|
|
|
|
"""
|
|
|
|
|
Search channels.
|
|
|
|
|
since_date: int | None = None,
|
|
|
|
|
until_date: int | None = None,
|
|
|
|
|
) -> AsyncGenerator[Note, None]:
|
|
|
|
|
"""Get all notes in the timeline of a channel
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
query : str
|
|
|
|
|
Search query
|
|
|
|
|
type : Literal['nameAndDescription', 'nameOnly'], optional, by default 'nameAndDescription'
|
|
|
|
|
Search type
|
|
|
|
|
since_id : str, optional, by default None
|
|
|
|
|
Since id
|
|
|
|
|
until_id : str, optional, by default None
|
|
|
|
|
Until id
|
|
|
|
|
limit : int, optional, by default 5
|
|
|
|
|
Limit
|
|
|
|
|
get_all : bool, optional, by default False
|
|
|
|
|
Get all channels flag
|
|
|
|
|
|
|
|
|
|
Yields
|
|
|
|
|
------
|
|
|
|
|
AsyncGenerator[Channel, None]
|
|
|
|
|
Channel
|
|
|
|
|
"""
|
|
|
|
|
if limit > 100:
|
|
|
|
|
raise ParameterError("limit must be less than 100")
|
|
|
|
|
|
|
|
|
|
if get_all:
|
|
|
|
|
limit = 100
|
|
|
|
|
|
|
|
|
|
body = {
|
|
|
|
|
"query": query,
|
|
|
|
|
"type": type,
|
|
|
|
|
"sinceId": since_id,
|
|
|
|
|
"untilId": until_id,
|
|
|
|
|
"limit": limit,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pagination = Pagination[IChannel](
|
|
|
|
|
self._session, Route("POST", "/api/channels/search"), auth=True, json=body
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
raw_channels = await pagination.next()
|
|
|
|
|
for raw_channel in raw_channels:
|
|
|
|
|
yield Channel(raw_channel, client=self._client)
|
|
|
|
|
channel_id : str
|
|
|
|
|
ID of the channel
|
|
|
|
|
since_id : str, optional
|
|
|
|
|
Since ID, by default None
|
|
|
|
|
until_id : str, optional
|
|
|
|
|
Until ID, by default None
|
|
|
|
|
since_date : int, optional
|
|
|
|
|
Since date, by default None
|
|
|
|
|
until_date : int, optional
|
|
|
|
|
Until date, by default None
|
|
|
|
|
|
|
|
|
|
if get_all is False or pagination.is_final:
|
|
|
|
|
break
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
AsyncGenerator[Note, None]
|
|
|
|
|
Async generator of notes
|
|
|
|
|
"""
|
|
|
|
|
async for i in super().get_all_timeline(
|
|
|
|
|
since_id=since_id,
|
|
|
|
|
until_id=until_id,
|
|
|
|
|
since_date=since_date,
|
|
|
|
|
until_date=until_date,
|
|
|
|
|
channel_id=channel_id,
|
|
|
|
|
):
|
|
|
|
|
yield i
|
|
|
|
|