From 9d562eed2a862949705b1270c096360a8ed68ed5 Mon Sep 17 00:00:00 2001 From: yupix Date: Mon, 19 Feb 2024 15:55:51 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20note=E5=91=A8=E3=82=8A=E3=82=92?= =?UTF-8?q?=E5=86=8D=E5=AE=9F=E8=A3=85=20progress=20#124?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mipac/actions/note.py | 1039 +++++++++++++++++++++++++++------------ mipac/manager/client.py | 3 - mipac/manager/note.py | 13 +- 3 files changed, 725 insertions(+), 330 deletions(-) diff --git a/mipac/actions/note.py b/mipac/actions/note.py index 05cdb14..fcd222e 100644 --- a/mipac/actions/note.py +++ b/mipac/actions/note.py @@ -86,15 +86,12 @@ def create_note_body( return remove_dict_empty(body) -class ClientNoteActions(AbstractAction): +class SharedNoteActions(AbstractAction): def __init__( self, - note_id: str | None = None, - *, session: HTTPClient, client: ClientManager, ): - self._note_id: str | None = note_id self._session: HTTPClient = session self._client: ClientManager = client @@ -104,16 +101,9 @@ class ClientNoteActions(AbstractAction): limit: int = 100, since_id: str | None = None, untilId: str | None = None, - note_id: str | None = None, + *, + note_id: str, ) -> list[Note]: - if limit > 100: - raise ValueError("limit は100以下である必要があります") - - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = { "noteId": note_id, "limit": limit, @@ -132,7 +122,8 @@ class ClientNoteActions(AbstractAction): limit: int = 100, since_id: str | None = None, untilId: str | None = None, - note_id: str | None = None, + *, + note_id: str, ) -> list[Note]: """Get children of the note. update the cache of the :py:meth:`mipac.actions.note.ClientNoteActions.get_children` method @@ -155,7 +146,6 @@ class ClientNoteActions(AbstractAction): list[Note] Children of the note """ - note_id = note_id or self._note_id return await self.get_children( limit=limit, since_id=since_id, untilId=untilId, note_id=note_id ) @@ -164,8 +154,9 @@ class ClientNoteActions(AbstractAction): self, since_id: str | None = None, untilId: str | None = None, - note_id: str | None = None, - ) -> AsyncGenerator[Note, None]: + *, + note_id: str, + ) -> AsyncGenerator[Note, None]: # TODO: limitをサポートする """Get all children of the note Endpoint: `/api/notes/children` @@ -186,11 +177,6 @@ class ClientNoteActions(AbstractAction): """ limit = 100 - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = { "noteId": note_id, "limit": limit, @@ -207,7 +193,7 @@ class ClientNoteActions(AbstractAction): for note in res_notes: yield Note(note, self._client) - async def get_clips(self, note_id: str | None = None) -> list[Clip]: + async def get_clips(self, *, note_id: str) -> list[Clip]: """Get the clips of the note Endpoint: `/api/notes/clips` @@ -222,12 +208,6 @@ class ClientNoteActions(AbstractAction): list[Clip] Clips of the note """ - - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = {"noteId": note_id} res: list[IClip] = await self._session.request( Route("POST", "/api/notes/clips"), json=data, auth=True @@ -235,7 +215,7 @@ class ClientNoteActions(AbstractAction): return [Clip(clip, client=self._client) for clip in res] async def get_conversation( - self, limit: int = 10, offset: int = 0, *, note_id: str | None = None + self, limit: int = 10, offset: int = 0, *, note_id: str ) -> list[Note]: """Get the conversation of the note @@ -255,18 +235,13 @@ class ClientNoteActions(AbstractAction): list[Note] Notes of the conversation """ - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = {"noteId": note_id, "limit": limit, "offset": offset} res: list[INote] = await self._session.request( Route("POST", "/api/notes/conversation"), json=data, auth=True ) return [Note(note, client=self._client) for note in res] - async def delete(self, *, note_id: str | None = None) -> bool: + async def delete(self, *, note_id: str) -> bool: """Delete a note Endpoint: `/api/notes/delete` @@ -281,12 +256,6 @@ class ClientNoteActions(AbstractAction): bool success or not """ - - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = {"noteId": note_id} res = await self._session.request(Route("POST", "/api/notes/delete"), json=data, auth=True) return bool(res) @@ -298,13 +267,8 @@ class ClientNoteActions(AbstractAction): since_id: str | None = None, until_id: str | None = None, *, - note_id: str | None = None, + note_id: str, ) -> list[NoteReaction]: - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - return await self._client.note.reaction.action.get_reactions( type=type, note_id=note_id, limit=limit, since_id=since_id, until_id=until_id ) @@ -316,13 +280,8 @@ class ClientNoteActions(AbstractAction): since_id: str | None = None, until_id: str | None = None, *, - note_id: str | None = None, + note_id: str, ) -> list[NoteReaction]: - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - return await self._client.note.reaction.action.fetch_reactions( note_id=note_id, type=type, limit=limit, since_id=since_id, until_id=until_id ) @@ -333,7 +292,7 @@ class ClientNoteActions(AbstractAction): since_id: str | None = None, until_id: str | None = None, *, - note_id: str | None = None, + note_id: str, ) -> list[Note]: """Get renote of the note @@ -355,11 +314,6 @@ class ClientNoteActions(AbstractAction): list[Note] Renotes of the note """ - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = { "noteId": note_id, "limit": limit, @@ -378,7 +332,7 @@ class ClientNoteActions(AbstractAction): until_id: str | None = None, limit: int = 10, *, - note_id: str | None = None, + note_id: str, ) -> list[Note]: """Get replies to the note @@ -400,8 +354,6 @@ class ClientNoteActions(AbstractAction): list[Note] replies """ - note_id = note_id or self._note_id - data = { "noteId": note_id, "sinceId": since_id, @@ -418,7 +370,7 @@ class ClientNoteActions(AbstractAction): since_id: str | None = None, until_id: str | None = None, *, - note_id: str | None = None, + note_id: str, ) -> AsyncGenerator[Note, None]: """Get replies to the note @@ -441,11 +393,6 @@ class ClientNoteActions(AbstractAction): limit = 100 - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - body = {"noteId": note_id, "sinceId": since_id, "untilId": until_id, "limit": limit} pagination = Pagination[INote]( @@ -461,7 +408,7 @@ class ClientNoteActions(AbstractAction): break @cache(group="get_note_state") - async def get_state(self, note_id: str | None = None) -> NoteState: + async def get_state(self, *, note_id: str) -> NoteState: """Get the state of the note Endpoint: `/api/notes/state` @@ -476,11 +423,6 @@ class ClientNoteActions(AbstractAction): NoteState Note state """ - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = {"noteId": note_id} res: INoteState = await self._session.request( Route("POST", "/api/notes/state"), auth=True, json=data @@ -488,7 +430,7 @@ class ClientNoteActions(AbstractAction): return NoteState(res) @cache(group="get_note_state", override=True) - async def fetch_state(self, note_id: str | None = None) -> NoteState: + async def fetch_state(self, *, note_id: str) -> NoteState: """Get the state of the note. update the cache of the :py:meth:`mipac.actions.note.ClientNoteActions.get_state` method @@ -505,10 +447,9 @@ class ClientNoteActions(AbstractAction): NoteState Note state """ - note_id = note_id or self._note_id return await self.get_state(note_id=note_id) - async def add_clips(self, clip_id: str, note_id: str | None = None) -> bool: + async def add_clips(self, clip_id: str, *, note_id: str) -> bool: """Add a note to the clip Endpoint: `/api/clips/add-note` @@ -525,18 +466,12 @@ class ClientNoteActions(AbstractAction): bool success or not """ - - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = {"noteId": note_id, "clipId": clip_id} return bool( await self._session.request(Route("POST", "/api/clips/add-note"), json=data, auth=True) ) - async def create_renote(self, note_id: str | None = None) -> Note: + async def create_renote(self, *, note_id: str) -> Note: """Renote a note Endpoint: `/api/notes/create` @@ -551,12 +486,6 @@ class ClientNoteActions(AbstractAction): Note Renoted note """ - - note_id = self._note_id or note_id - - if note_id is None: - raise ValueError("note_id is required") - body = create_note_body(renote_id=note_id) res: ICreatedNote = await self._session.request( Route("POST", "/api/notes/create"), @@ -581,7 +510,7 @@ class ClientNoteActions(AbstractAction): files: list[MiFile | File | str] | None = None, poll: MiPoll | None = None, *, - renote_id: str | None = None, + renote_id: str, ): """Renote a note @@ -613,7 +542,6 @@ class ClientNoteActions(AbstractAction): The ID list of files to be attached poll : MiPoll | None, default=None """ - renote_id = renote_id or self._note_id body = create_note_body( text=text, @@ -653,13 +581,9 @@ class ClientNoteActions(AbstractAction): extract_emojis: bool = True, files: list[MiFile | File | str] | None = None, poll: MiPoll | None = None, - reply_id: str | None = None, + *, + reply_id: str, ) -> Note: - reply_id = reply_id or self._note_id - - if reply_id is None: - raise ValueError("reply_id is required") - body = create_note_body( text=text, visibility=visibility, @@ -695,7 +619,8 @@ class ClientNoteActions(AbstractAction): extract_emojis: bool = True, files: list[MiFile | File | str] | None = None, poll: MiPoll | None = None, - note_id: str | None = None, + *, + note_id: str, ) -> Note: """Create a note quote. @@ -726,12 +651,6 @@ class ClientNoteActions(AbstractAction): note_id: str | None, default=None Note IDs to target for renote and citations """ - - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - body = create_note_body( text=content, visibility=visibility, @@ -758,8 +677,9 @@ class ClientNoteActions(AbstractAction): @cache(group="translate_note") async def translate( self, - note_id: str | None = None, target_lang: str = "en-US", + *, + note_id: str, ) -> NoteTranslateResult: """Translate a note @@ -777,11 +697,6 @@ class ClientNoteActions(AbstractAction): NoteTranslateResult Translated result """ - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - data = {"noteId": note_id, "targetLang": target_lang} res: INoteTranslateResult = await self._session.request( Route("POST", "/api/notes/translate"), json=data, auth=True @@ -790,7 +705,7 @@ class ClientNoteActions(AbstractAction): return NoteTranslateResult(res) APIError(f"Translate Error: {res}", res if isinstance(res, int) else 204).raise_error() - async def un_renote(self, note_id: str | None = None) -> bool: + async def un_renote(self, *, note_id: str) -> bool: """Releases the note renote for the specified Id Parameters @@ -803,11 +718,6 @@ class ClientNoteActions(AbstractAction): bool Whether the release was successful """ - note_id = note_id or self._note_id - - if note_id is None: - raise ValueError("note_id is required") - body = {"noteId": note_id} res: bool = await self._session.request( Route("POST", "/api/notes/unrenote"), auth=True, json=body @@ -815,197 +725,748 @@ class ClientNoteActions(AbstractAction): return res -class NoteActions(ClientNoteActions): +class ClientNoteActions(SharedNoteActions): def __init__( self, - note_id: str | None = None, + note_id: str, *, session: HTTPClient, client: ClientManager, ): - super().__init__(note_id=note_id, session=session, client=client) - - async def create( - self, - visibility: INoteVisibility = "public", - visible_user_ids: list[str] | None = None, - cw: str | None = None, - local_only: bool = False, - reaction_acceptance: IReactionAcceptance | None = None, - no_extrace_mentions: bool = False, - no_extract_hashtags: bool = False, - no_extract_emojis: bool = False, - reply_id: str | None = None, - renote_id: str | None = None, - channel_id: str | None = None, - text: str | None = None, - file_ids: list[MiFile | File | str] | None = None, - media_ids: list[str] | None = None, - poll: MiPoll | None = None, - ) -> Note: - data = create_note_body( - text=text, - visibility=visibility, - visible_user_ids=visible_user_ids, - cw=cw, - local_only=local_only, - reaction_acceptance=reaction_acceptance, - extract_mentions=not no_extrace_mentions, - extract_hashtags=not no_extract_hashtags, - extract_emojis=not no_extract_emojis, - reply_id=reply_id, - renote_id=renote_id, - channel_id=channel_id, - files=file_ids, - media_ids=media_ids, - poll=poll, - ) - - raw_created_note: ICreatedNote = await self._session.request( - Route("POST", "/api/notes/create"), - auth=True, - json=data, - ) - - return Note(raw_note=raw_created_note["created_note"], client=self._client) + super().__init__(session, client) + self._note_id: str = note_id @override async def get_children( self, - note_id: str, limit: int = 100, since_id: str | None = None, untilId: str | None = None, + *, + note_id: str | None = None, ) -> list[Note]: + note_id = note_id or self._note_id + return await super().get_children( - note_id=note_id, limit=limit, since_id=since_id, untilId=untilId + limit=limit, since_id=since_id, untilId=untilId, note_id=note_id ) @override async def fetch_children( self, - note_id: str, limit: int = 100, since_id: str | None = None, untilId: str | None = None, + *, + note_id: str | None = None, ) -> list[Note]: - return await super().fetch_children( - note_id=note_id, limit=limit, since_id=since_id, untilId=untilId - ) - - @override - async def get_all_children( - self, note_id: str, since_id: str | None = None, untilId: str | None = None - ) -> AsyncGenerator[Note, None] | list[Note]: - async for i in super().get_all_children( - note_id=note_id, since_id=since_id, untilId=untilId - ): - yield i - - @override - async def get_clips(self, note_id: str) -> list[Clip]: - return await super().get_clips(note_id=note_id) - - @override - async def get_conversation(self, note_id: str, limit: int = 10, offset: int = 0) -> list[Note]: - return await super().get_conversation(note_id=note_id, limit=limit, offset=offset) - - @override - async def delete(self, note_id: str) -> bool: - return await super().delete(note_id=note_id) - - async def get_featured( - self, limit: int = 10, until_id: str | None = None, channel_id: str | None = None - ): - """Get featured notes + """Get children of the note. + update the cache of the :py:meth:`mipac.actions.note.ClientNoteActions.get_children` method - Endpoint: `/api/notes/featured` + Endpoint: `/api/notes/children` Parameters ---------- - limit : int, default=10 + limit : int, default=100 limit - until_id : str | None, default=None + since_id : str | None, default=None + Since ID + untilId : str | None, default=None Until ID - channel_id : str | None, default=None - channel id + note_id : str | None, default=None + note id Returns ------- list[Note] - featured notes + Children of the note """ - data = {"limit": limit, "untilId": until_id, "channelId": channel_id} - res: list[INote] = await self._session.request( - Route("POST", "/api/notes/featured"), json=data + note_id = note_id or self._note_id + return await super().fetch_children( + limit=limit, since_id=since_id, untilId=untilId, note_id=note_id ) - return [Note(note, client=self._client) for note in res] - async def get_global_time_line( + @override + async def get_all_children( self, - with_files: bool = False, - with_renotes: bool = True, - limit: int = 10, since_id: str | None = None, - until_id: str | None = None, - since_date: int | None = None, - until_date: int | None = None, - ): - """Get global timeline + untilId: str | None = None, + *, + note_id: str | None = None, + ) -> AsyncGenerator[Note, None]: # TODO: limitをサポート + """Get all children of the note - Endpoint: `/api/notes/global-timeline` + Endpoint: `/api/notes/children` Parameters ---------- - with_files : bool, default=False - Whether to include files - with_renotes : bool, default=True - Whether to include renote - limit : int, default=10 - limit since_id : str | None, default=None Since ID - until_id : str | None, default=None + untilId : str | None, default=None Until ID - since_date : int | None, default=None - Since date - until_date : int | None, default=None - Until date + note_id : str | None, default=None + note id Returns ------- - list[Note] - global timeline + AsyncGenerator[Note, None] + Children of the note """ - data = { - "withFiles": with_files, - "withRenotes": with_renotes, - "limit": limit, - "sinceId": since_id, - "untilId": until_id, - "sinceDate": since_date, - "untilDate": until_date, - } - res: list[INote] = await self._session.request( - Route("POST", "/api/notes/global-timeline"), json=data - ) - return [Note(note, client=self._client) for note in res] + note_id = note_id or self._note_id - async def get_hybird_time_line( - self, - limit: int = 10, - since_id: str | None = None, - until_id: str | None = None, - allow_partial: bool = False, - include_my_rnotes: bool = True, - include_renoted_my_notes: bool = True, - include_local_renotes: bool = True, - with_files: bool = False, - with_renotes: bool = True, - with_replies: bool = False, - ): - data = { - "limit": limit, + async for i in super().get_all_children( + since_id=since_id, untilId=untilId, note_id=note_id + ): + yield i + + @override + async def get_clips(self, *, note_id: str | None = None) -> list[Clip]: + """Get the clips of the note + + Endpoint: `/api/notes/clips` + + Parameters + ---------- + note_id : str | None, default=None + note id + + Returns + ------- + list[Clip] + Clips of the note + """ + + note_id = note_id or self._note_id + + return await super().get_clips(note_id=note_id) + + @override + async def get_conversation( + self, limit: int = 10, offset: int = 0, *, note_id: str | None = None + ) -> list[Note]: + """Get the conversation of the note + + Endpoint: `/api/notes/conversation` + + Parameters + ---------- + limit : int, default=10 + limit + offset : int, default=0 + offset + note_id : str | None, default=None + note id + + Returns + ------- + list[Note] + Notes of the conversation + """ + note_id = note_id or self._note_id + + return await super().get_conversation(limit=limit, offset=offset, note_id=note_id) + + @override + async def delete(self, *, note_id: str | None = None) -> bool: + """Delete a note + + Endpoint: `/api/notes/delete` + + Parameters + ---------- + note_id : str | None, default=None + note id + + Returns + ------- + bool + success or not + """ + note_id = note_id or self._note_id + + return await super().delete(note_id=note_id) + + @override + async def get_reactions( + self, + type: str | None = None, + limit: int = 10, + since_id: str | None = None, + until_id: str | None = None, + *, + note_id: str | None = None, + ) -> list[NoteReaction]: + note_id = note_id or self._note_id + + return await super().get_reactions( + type=type, + limit=limit, + since_id=since_id, + until_id=until_id, + note_id=note_id, + ) + + @override + async def fetch_reactions( + self, + type: str | None = None, + limit: int = 10, + since_id: str | None = None, + until_id: str | None = None, + *, + note_id: str | None = None, + ) -> list[NoteReaction]: + note_id = note_id or self._note_id + + return await super().fetch_reactions( + type=type, + limit=limit, + since_id=since_id, + until_id=until_id, + note_id=note_id, + ) + + @override + async def get_renotes( + self, + limit: int = 10, + since_id: str | None = None, + until_id: str | None = None, + *, + note_id: str | None = None, + ) -> list[Note]: + """Get renote of the note + + Endpoint: `/api/notes/renotes` + + Parameters + ---------- + limit : int, default=10 + limit + since_id : str | None, default=None + Since ID + until_id : str | None, default=None + Until ID + note_id : str | None, default=None + note id + + Returns + ------- + list[Note] + Renotes of the note + """ + note_id = note_id or self._note_id + + return await super().get_renotes( + limit=limit, since_id=since_id, until_id=until_id, note_id=note_id + ) + + @override + async def get_replies( + self, + since_id: str | None = None, + until_id: str | None = None, + limit: int = 10, + *, + note_id: str | None = None, + ) -> list[Note]: + """Get replies to the note + + Endpoint: `/api/notes/replies` + + Parameters + --------- + since_id : str | None, default=None + since id + until_id : str | None, default=None + until id + limit : int, default=10 + limit + note_id: str | None, default=None + note id + + Returns + ------- + list[Note] + replies + """ + note_id = note_id or self._note_id + + return await super().get_replies( + since_id=since_id, until_id=until_id, limit=limit, note_id=note_id + ) + + async def get_all_replies( + self, + since_id: str | None = None, + until_id: str | None = None, + *, + note_id: str | None = None, + ) -> AsyncGenerator[Note, None]: # TODO: limitをサポート + """Get replies to the note + + Endpoint: `/api/notes/replies` + + Parameters + --------- + since_id : str | None, default=None + since id + until_id : str | None, default=None + until id + note_id: str | None, default=None + note id + + Returns + ------- + AsyncGenerator[Note, None] + replies + """ + note_id = note_id or self._note_id + + async for i in super().get_all_replies( + since_id=since_id, until_id=until_id, note_id=note_id + ): + yield i + + @override + async def get_state(self, *, note_id: str | None = None) -> NoteState: + """Get the state of the note + + Endpoint: `/api/notes/state` + + Parameters + ---------- + note_id : str | None, default=None + note id + + Returns + ------- + NoteState + Note state + """ + note_id = note_id or self._note_id + + return await super().get_state(note_id=note_id) + + @override + async def fetch_state(self, *, note_id: str | None = None) -> NoteState: + """Get the state of the note. + + update the cache of the :py:meth:`mipac.actions.note.ClientNoteActions.get_state` method + + Endpoint: `/api/notes/state` + + Parameters + ---------- + note_id : str | None, default=None + note id + + Returns + ------- + NoteState + Note state + """ + note_id = note_id or self._note_id + return await super().fetch_state(note_id=note_id) + + async def add_clips(self, clip_id: str, *, note_id: str | None = None) -> bool: + """Add a note to the clip + + Endpoint: `/api/clips/add-note` + + Parameters + ---------- + note_id : str | None, default=None + note id + clip_id : str + clip id + + Returns + ------- + bool + success or not + """ + + note_id = note_id or self._note_id + + return await super().add_clips(clip_id=clip_id, note_id=note_id) + + @override + async def create_renote(self, *, note_id: str | None = None) -> Note: + """Renote a note + + Endpoint: `/api/notes/create` + + Parameters + ---------- + note_id : str | None, default=None + note id + + Returns + ------- + Note + Renoted note + """ + + note_id = note_id or self._note_id + + return await super().create_renote(note_id=note_id) + + @override + async def renote( + 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, + extract_hashtags: bool = True, + extract_emojis: bool = True, + channel_id: str | None = None, + files: list[MiFile | File | str] | None = None, + poll: MiPoll | None = None, + *, + renote_id: str | None = None, + ): + """Renote a note + + Endpoint: `/api/notes/create` + + Parameters + ---------- + text : str | None, default=None + text + visibility : INoteVisibility, default='public' + Disclosure range + visible_user_ids : list[str] | None, default=None + List of users to be published + cw : str | None, default=None + Text to be displayed when warning is given + local_only : bool, default=False + Whether to show only locally or not + reaction_acceptance : IReactionAcceptance, default=None + Reaction acceptance setting + extract_mentions : bool, default=True + Whether to expand the mention + extract_hashtags : bool, default=True + Whether to expand the hashtag + extract_emojis : bool, default=True + Whether to expand the emojis + channel_id : str | None, default=None + Channel ID + files : list[MiFile | File | str] | None, default=None + The ID list of files to be attached + poll : MiPoll | None, default=None + """ + renote_id = renote_id or self._note_id + + return await super().renote( + text=text, + visibility=visibility, + visible_user_ids=visible_user_ids, + cw=cw, + local_only=local_only, + reaction_acceptance=reaction_acceptance, + extract_mentions=extract_mentions, + extract_hashtags=extract_hashtags, + extract_emojis=extract_emojis, + channel_id=channel_id, + files=files, + poll=poll, + renote_id=renote_id, + ) + + @override + async def reply( + 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, + extract_hashtags: bool = True, + extract_emojis: bool = True, + files: list[MiFile | File | str] | None = None, + poll: MiPoll | None = None, + *, + reply_id: str | None = None, + ) -> Note: + reply_id = reply_id or self._note_id + + return await super().reply( + text=text, + visibility=visibility, + visible_user_ids=visible_user_ids, + cw=cw, + local_only=local_only, + reaction_acceptance=reaction_acceptance, + extract_mentions=extract_mentions, + extract_hashtags=extract_hashtags, + extract_emojis=extract_emojis, + files=files, + poll=poll, + reply_id=reply_id, + ) + + @override + async def create_quote( + self, + content: 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, + extract_hashtags: bool = True, + extract_emojis: bool = True, + files: list[MiFile | File | str] | None = None, + poll: MiPoll | None = None, + *, + note_id: str | None = None, + ) -> Note: + """Create a note quote. + + Endpoint: `/api/notes/create` + + Parameters + ---------- + content: str | None, default=None + text + visibility: INoteVisibility, default='public' + Disclosure range + visible_user_ids: list[str] | None, default=None + List of users to be published + cw: str | None, default=None + Text to be displayed when warning is given + local_only: bool, default=False + Whether to show only locally or not + extract_mentions: bool, default=True + Whether to expand the mention + extract_hashtags: bool, default=True + Whether to expand the hashtag + extract_emojis: bool, default=True + Whether to expand the emojis + files: list[MiFile | File | str] | None, default=None + The ID list of files to be attached + poll: MiPoll | None, default=None + Questionnaire to be created + note_id: str | None, default=None + Note IDs to target for renote and citations + """ + + note_id = note_id or self._note_id + + return await super().create_quote( + content=content, + visibility=visibility, + visible_user_ids=visible_user_ids, + cw=cw, + local_only=local_only, + reaction_acceptance=reaction_acceptance, + extract_mentions=extract_mentions, + extract_hashtags=extract_hashtags, + extract_emojis=extract_emojis, + files=files, + poll=poll, + note_id=note_id, + ) + + @override + async def translate( + self, + target_lang: str = "en-US", + *, + note_id: str | None = None, + ) -> NoteTranslateResult: + """Translate a note + + Endpoint: `/api/notes/translate` + + Parameters + ---------- + note_id : str | None, default=None + Note ID to target for translation + target_lang : str, default='en' + Target language + + Returns + ------- + NoteTranslateResult + Translated result + """ + note_id = note_id or self._note_id + + return await super().translate(target_lang=target_lang, note_id=note_id) + + @override + async def un_renote(self, *, note_id: str | None = None) -> bool: + """Releases the note renote for the specified Id + + Parameters + ---------- + note_id : str | None, optional + Target note Id., by default None + + Returns + ------- + bool + Whether the release was successful + """ + note_id = note_id or self._note_id + + return await super().un_renote(note_id=note_id) + + +class NoteActions(SharedNoteActions): + def __init__( + self, + *, + session: HTTPClient, + client: ClientManager, + ): + super().__init__(session=session, client=client) + + async def create( + self, + visibility: INoteVisibility = "public", + visible_user_ids: list[str] | None = None, + cw: str | None = None, + local_only: bool = False, + reaction_acceptance: IReactionAcceptance | None = None, + no_extrace_mentions: bool = False, + no_extract_hashtags: bool = False, + no_extract_emojis: bool = False, + reply_id: str | None = None, + renote_id: str | None = None, + channel_id: str | None = None, + text: str | None = None, + file_ids: list[MiFile | File | str] | None = None, + media_ids: list[str] | None = None, + poll: MiPoll | None = None, + ) -> Note: + data = create_note_body( + text=text, + visibility=visibility, + visible_user_ids=visible_user_ids, + cw=cw, + local_only=local_only, + reaction_acceptance=reaction_acceptance, + extract_mentions=not no_extrace_mentions, + extract_hashtags=not no_extract_hashtags, + extract_emojis=not no_extract_emojis, + reply_id=reply_id, + renote_id=renote_id, + channel_id=channel_id, + files=file_ids, + media_ids=media_ids, + poll=poll, + ) + + raw_created_note: ICreatedNote = await self._session.request( + Route("POST", "/api/notes/create"), + auth=True, + json=data, + ) + + return Note(raw_note=raw_created_note["created_note"], client=self._client) + + async def get_featured( + self, limit: int = 10, until_id: str | None = None, channel_id: str | None = None + ): + """Get featured notes + + Endpoint: `/api/notes/featured` + + Parameters + ---------- + limit : int, default=10 + limit + until_id : str | None, default=None + Until ID + channel_id : str | None, default=None + channel id + + Returns + ------- + list[Note] + featured notes + """ + data = {"limit": limit, "untilId": until_id, "channelId": channel_id} + res: list[INote] = await self._session.request( + Route("POST", "/api/notes/featured"), json=data + ) + return [Note(note, client=self._client) for note in res] + + async def get_global_time_line( + self, + with_files: bool = False, + with_renotes: bool = True, + limit: int = 10, + since_id: str | None = None, + until_id: str | None = None, + since_date: int | None = None, + until_date: int | None = None, + ): + """Get global timeline + + Endpoint: `/api/notes/global-timeline` + + Parameters + ---------- + with_files : bool, default=False + Whether to include files + with_renotes : bool, default=True + Whether to include renote + limit : int, default=10 + limit + since_id : str | None, default=None + Since ID + until_id : str | None, default=None + Until ID + since_date : int | None, default=None + Since date + until_date : int | None, default=None + Until date + + Returns + ------- + list[Note] + global timeline + """ + data = { + "withFiles": with_files, + "withRenotes": with_renotes, + "limit": limit, + "sinceId": since_id, + "untilId": until_id, + "sinceDate": since_date, + "untilDate": until_date, + } + res: list[INote] = await self._session.request( + Route("POST", "/api/notes/global-timeline"), json=data + ) + return [Note(note, client=self._client) for note in res] + + async def get_hybird_time_line( + self, + limit: int = 10, + since_id: str | None = None, + until_id: str | None = None, + allow_partial: bool = False, + include_my_rnotes: bool = True, + include_renoted_my_notes: bool = True, + include_local_renotes: bool = True, + with_files: bool = False, + with_renotes: bool = True, + with_replies: bool = False, + ): + data = { + "limit": limit, "sinceId": since_id, "untilId": until_id, "allowPartial": allow_partial, @@ -1092,68 +1553,6 @@ class NoteActions(ClientNoteActions): return [Note(note, client=self._client) for note in res] - @override - async def get_reactions( - self, - note_id: str, - type: str | None = None, - limit: int = 10, - since_id: str | None = None, - until_id: str | None = None, - ) -> list[NoteReaction]: - return await super().get_reactions( - note_id=note_id, type=type, limit=limit, since_id=since_id, until_id=until_id - ) - - @override - async def fetch_reactions( - self, - note_id: str, - type: str | None = None, - limit: int = 10, - since_id: str | None = None, - until_id: str | None = None, - ) -> list[NoteReaction]: - return await super().fetch_reactions( - note_id=note_id, type=type, limit=limit, since_id=since_id, until_id=until_id - ) - - @override - async def get_renotes( - self, - note_id: str, - limit: int = 10, - since_id: str | None = None, - until_id: str | None = None, - ) -> list[Note]: - return await super().get_renotes( - note_id=note_id, limit=limit, since_id=since_id, until_id=until_id - ) - - @override - async def get_replies( - self, - note_id: str, - since_id: str | None = None, - until_id: str | None = None, - limit: int = 10, - ) -> list[Note]: - return await super().get_replies( - note_id=note_id, since_id=since_id, until_id=until_id, limit=limit - ) - - @override - async def get_all_replies( - self, - note_id: str, - since_id: str | None = None, - until_id: str | None = None, - ) -> AsyncGenerator[Note, None]: - async for i in super().get_all_replies( - note_id=note_id, since_id=since_id, until_id=until_id - ): - yield i - async def search_by_tag( self, tag: str, diff --git a/mipac/manager/client.py b/mipac/manager/client.py index 355609d..be2f982 100644 --- a/mipac/manager/client.py +++ b/mipac/manager/client.py @@ -61,9 +61,6 @@ class ClientManager: def _create_user_instance(self, user: PartialUser) -> UserManager: return UserManager(session=self.__session, client=self) - def _create_note_instance(self, note_id: str) -> NoteManager: - return NoteManager(note_id, session=self.__session, client=self) - def _create_client_channel_manager(self, channel_id: str) -> ClientChannelManager: return ClientChannelManager(channel_id=channel_id, session=self.__session, client=self) diff --git a/mipac/manager/note.py b/mipac/manager/note.py index 7977e39..b6d3327 100644 --- a/mipac/manager/note.py +++ b/mipac/manager/note.py @@ -25,28 +25,27 @@ class ClientNoteManager(AbstractManager): self.poll: ClientPollManager = ClientPollManager( note_id=note_id, session=session, client=client ) - - @property - def action(self) -> ClientNoteActions: - return ClientNoteActions( + self.__action: ClientNoteActions = ClientNoteActions( note_id=self.__note_id, session=self.__session, client=self.__client, ) + @property + def action(self) -> ClientNoteActions: + return self.__action + class NoteManager(AbstractManager): """User behavior for notes""" - def __init__(self, note_id: str | None = None, *, session: HTTPClient, client: ClientManager): - self.__note_id: str | None = note_id + def __init__(self, *, session: HTTPClient, client: ClientManager): self.__session: HTTPClient = session self.__client: ClientManager = client self.reaction: ReactionManager = ReactionManager(session=session, client=client) self.favorite = FavoriteManager(session=session, client=client) self.poll: PollManager = PollManager(session=session, client=client) self.__action: NoteActions = NoteActions( - note_id=self.__note_id, session=self.__session, client=self.__client, ) # property側で生成するとcacheが効かなくなる