From e926603df45071da5c6ddccb35b0094888a7f744 Mon Sep 17 00:00:00 2001 From: Danipulok Date: Tue, 14 Jan 2025 01:27:26 +0200 Subject: [PATCH 1/2] refactor(client): add `_url` & `_ajax_url` helper methods --- pixivpy3/aapi.py | 100 ++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/pixivpy3/aapi.py b/pixivpy3/aapi.py index a2d4d6fc..b9c8c911 100644 --- a/pixivpy3/aapi.py +++ b/pixivpy3/aapi.py @@ -65,24 +65,34 @@ def set_api_proxy(self, proxy_hosts: str = "http://app-api.pixivlite.com") -> No """Set proxy hosts: eg pixivlite.com""" self.hosts = proxy_hosts + def _url(self, endpoint: str) -> str: + return f"{self.hosts}{endpoint}" + + @classmethod + def _ajax_url(cls, endpoint: str) -> str: + return f"https://www.pixiv.net{endpoint}" + # Check auth and set BearerToken to headers def no_auth_requests_call( self, - method: str, + method: Literal["GET", "POST"], url: str, headers: ParamDict = None, params: ParamDict = None, data: ParamDict = None, req_auth: bool = True, ) -> Response: + # `mypy` doesn't allow type overwriting, must add `_` suffix headers_ = CaseInsensitiveDict(headers or {}) + if self.hosts != "https://app-api.pixiv.net": - headers_["host"] = "app-api.pixiv.net" - if "user-agent" not in headers_: + headers_["Host"] = "app-api.pixiv.net" + + if "User-Agent" not in headers_: # Set User-Agent if not provided - headers_["app-os"] = "ios" - headers_["app-os-version"] = "14.6" - headers_["user-agent"] = "PixivIOSApp/7.13.3 (iOS 14.6; iPhone13,2)" + headers_["App-OS"] = "ios" + headers_["App-OS-Version"] = "14.6" + headers_["User-Agent"] = "PixivIOSApp/7.13.3 (iOS 14.6; iPhone13,2)" if not req_auth: return self.requests_call(method, url, headers_, params, data) @@ -132,7 +142,7 @@ def user_detail( filter: _FILTER = "for_ios", req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/detail" % self.hosts + url = self._url("/v1/user/detail") params = { "user_id": user_id, "filter": filter, @@ -150,7 +160,7 @@ def user_illusts( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/illusts" % self.hosts + url = self._url("/v1/user/illusts") params = { "user_id": user_id, "filter": filter, @@ -173,7 +183,7 @@ def user_bookmarks_illust( tag: str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/bookmarks/illust" % self.hosts + url = self._url("/v1/user/bookmarks/illust") params = { "user_id": user_id, "restrict": restrict, @@ -196,7 +206,7 @@ def user_bookmarks_novel( tag: str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/bookmarks/novel" % self.hosts + url = self._url("/v1/user/bookmarks/novel") params = { "user_id": user_id, "restrict": restrict, @@ -216,7 +226,7 @@ def user_related( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/related" % self.hosts + url = self._url("/v1/user/related") params = { "filter": filter, # Pixiv warns to put seed_user_id at the end -> put offset here @@ -232,7 +242,7 @@ def user_recommended( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/recommended" % self.hosts + url = self._url("/v1/user/recommended") params = { "filter": filter, } @@ -250,7 +260,7 @@ def illust_follow( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v2/illust/follow" % self.hosts + url = self._url("/v2/illust/follow") params: dict[str, str | int] = { "restrict": restrict, } @@ -261,7 +271,7 @@ def illust_follow( # 作品详情 (类似PAPI.works(),iOS中未使用) def illust_detail(self, illust_id: int | str, req_auth: bool = True) -> ParsedJson: - url = "%s/v1/illust/detail" % self.hosts + url = self._url("/v1/illust/detail") params = { "illust_id": illust_id, } @@ -276,7 +286,7 @@ def illust_comments( include_total_comments: str | bool | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/illust/comments" % self.hosts + url = self._url("/v1/illust/comments") params = { "illust_id": illust_id, } @@ -297,7 +307,7 @@ def illust_related( viewed: str | list[str] | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v2/illust/related" % self.hosts + url = self._url("/v2/illust/related") params: dict[str, Any] = { "illust_id": illust_id, "filter": filter, @@ -331,9 +341,9 @@ def illust_recommended( req_auth: bool = True, ) -> ParsedJson: if req_auth: - url = "%s/v1/illust/recommended" % self.hosts + url = self._url("/v1/illust/recommended") else: - url = "%s/v1/illust/recommended-nologin" % self.hosts + url = self._url("/v1/illust/recommended-nologin") params: dict[str, Any] = { "content_type": content_type, "include_ranking_label": self.format_bool(include_ranking_label), @@ -373,7 +383,7 @@ def novel_comments( include_total_comments: str | bool | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/novel/comments" % self.hosts + url = self._url("/v1/novel/comments") params = { "novel_id": novel_id, } @@ -396,7 +406,7 @@ def novel_recommended( include_privacy_policy: str | list[int | str] | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/novel/recommended" % self.hosts + url = self._url("/v1/novel/recommended") params: dict[str, Any] = { "include_ranking_label": self.format_bool(include_ranking_label), "filter": filter, @@ -431,7 +441,7 @@ def illust_ranking( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/illust/ranking" % self.hosts + url = self._url("/v1/illust/ranking") params: dict[str, Any] = { "mode": mode, "filter": filter, @@ -445,7 +455,7 @@ def illust_ranking( # 趋势标签 (Search - tags) def trending_tags_illust(self, filter: _FILTER = "for_ios", req_auth: bool = True) -> ParsedJson: - url = "%s/v1/trending-tags/illust" % self.hosts + url = self._url("/v1/trending-tags/illust") params = { "filter": filter, } @@ -474,7 +484,7 @@ def search_illust( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/search/illust" % self.hosts + url = self._url("/v1/search/illust") params: dict[str, Any] = { "word": word, "search_target": search_target, @@ -517,7 +527,7 @@ def search_novel( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/search/novel" % self.hosts + url = self._url("/v1/search/novel") params: dict[str, Any] = { "word": word, "search_target": search_target, @@ -546,7 +556,7 @@ def search_user( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/search/user" % self.hosts + url = self._url("/v1/search/user") params: dict[str, Any] = { "word": word, "sort": sort, @@ -561,7 +571,7 @@ def search_user( # 作品收藏详情 def illust_bookmark_detail(self, illust_id: int | str, req_auth: bool = True) -> ParsedJson: - url = "%s/v2/illust/bookmark/detail" % self.hosts + url = self._url("/v2/illust/bookmark/detail") params = { "illust_id": illust_id, } @@ -576,7 +586,7 @@ def illust_bookmark_add( tags: str | list[str] | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v2/illust/bookmark/add" % self.hosts + url = self._url("/v2/illust/bookmark/add") data = { "illust_id": illust_id, "restrict": restrict, @@ -591,7 +601,7 @@ def illust_bookmark_add( # 删除收藏 def illust_bookmark_delete(self, illust_id: int | str, req_auth: bool = True) -> ParsedJson: - url = "%s/v1/illust/bookmark/delete" % self.hosts + url = self._url("/v1/illust/bookmark/delete") data = { "illust_id": illust_id, } @@ -605,21 +615,21 @@ def user_follow_add( restrict: _RESTRICT = "public", req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/follow/add" % self.hosts + url = self._url("/v1/user/follow/add") data = {"user_id": user_id, "restrict": restrict} r = self.no_auth_requests_call("POST", url, data=data, req_auth=req_auth) return self.parse_result(r) # 取消关注用户 def user_follow_delete(self, user_id: int | str, req_auth: bool = True) -> ParsedJson: - url = "%s/v1/user/follow/delete" % self.hosts + url = self._url("/v1/user/follow/delete") data = {"user_id": user_id} r = self.no_auth_requests_call("POST", url, data=data, req_auth=req_auth) return self.parse_result(r) # 设置用户选项中是否展现AI生成作品 def user_edit_ai_show_settings(self, setting: _BOOL, req_auth: bool = True) -> ParsedJson: - url = "%s/v1/user/ai-show-settings/edit" % self.hosts + url = self._url("/v1/user/ai-show-settings/edit") data = {"show_ai": setting} r = self.no_auth_requests_call("POST", url, data=data, req_auth=req_auth) return self.parse_result(r) @@ -632,7 +642,7 @@ def user_bookmark_tags_illust( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/bookmark-tags/illust" % self.hosts + url = self._url("/v1/user/bookmark-tags/illust") params: dict[str, Any] = { "user_id": user_id, "restrict": restrict, @@ -650,7 +660,7 @@ def user_following( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/following" % self.hosts + url = self._url("/v1/user/following") params = { "user_id": user_id, "restrict": restrict, @@ -669,7 +679,7 @@ def user_follower( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/follower" % self.hosts + url = self._url("/v1/user/follower") params = { "user_id": user_id, "filter": filter, @@ -687,7 +697,7 @@ def user_mypixiv( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/mypixiv" % self.hosts + url = self._url("/v1/user/mypixiv") params = { "user_id": user_id, } @@ -705,7 +715,7 @@ def user_list( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v2/user/list" % self.hosts + url = self._url("/v2/user/list") params = { "user_id": user_id, "filter": filter, @@ -718,7 +728,7 @@ def user_list( # 获取ugoira信息 def ugoira_metadata(self, illust_id: int | str, req_auth: bool = True) -> ParsedJson: - url = "%s/v1/ugoira/metadata" % self.hosts + url = self._url("/v1/ugoira/metadata") params = { "illust_id": illust_id, } @@ -734,7 +744,7 @@ def user_novels( offset: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/user/novels" % self.hosts + url = self._url("/v1/user/novels") params = { "user_id": user_id, "filter": filter, @@ -752,7 +762,7 @@ def novel_series( last_order: str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v2/novel/series" % self.hosts + url = self._url("/v2/novel/series") params = { "series_id": series_id, "filter": filter, @@ -764,7 +774,7 @@ def novel_series( # 小说详情 def novel_detail(self, novel_id: int | str, req_auth: bool = True) -> ParsedJson: - url = "%s/v2/novel/detail" % self.hosts + url = self._url("/v2/novel/detail") params = { "novel_id": novel_id, } @@ -778,7 +788,7 @@ def novel_new( max_novel_id: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/novel/new" % self.hosts + url = self._url("/v1/novel/new") params: dict[str, Any] = { "filter": filter, } @@ -795,7 +805,7 @@ def novel_follow( offset: int | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/novel/follow" % self.hosts + url = self._url("/v1/novel/follow") params: dict[str, Any] = {"restrict": restrict, "offset": offset} r = self.no_auth_requests_call("GET", url, params=params, req_auth=req_auth) return self.parse_result(r) @@ -804,7 +814,7 @@ def novel_follow( # raw=True, return html content directly def webview_novel(self, novel_id: int | str, raw: bool = False, req_auth: bool = True) -> ParsedJson: # change new endpoint due to #337 - url = "%s/webview/v2/novel" % self.hosts + url = self._url("/webview/v2/novel") params = { "id": novel_id, "viewer_version": "20221031_ai", @@ -836,7 +846,7 @@ def illust_new( max_illust_id: int | str | None = None, req_auth: bool = True, ) -> ParsedJson: - url = "%s/v1/illust/new" % self.hosts + url = self._url("/v1/illust/new") params: dict[str, Any] = { "content_type": content_type, "filter": filter, @@ -848,7 +858,7 @@ def illust_new( # 特辑详情 (无需登录,调用Web API) def showcase_article(self, showcase_id: int | str) -> ParsedJson: - url = "https://www.pixiv.net/ajax/showcase/article" + url = self._ajax_url("/ajax/showcase/article") # Web API,伪造Chrome的User-Agent headers = { "User-Agent": ( From ca1caf9154e56c1a365f8182dd68483060db775e Mon Sep 17 00:00:00 2001 From: Danipulok Date: Wed, 15 Jan 2025 11:22:48 +0200 Subject: [PATCH 2/2] remove `_ajax_url` --- pixivpy3/aapi.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pixivpy3/aapi.py b/pixivpy3/aapi.py index 08a58663..2f76ff28 100644 --- a/pixivpy3/aapi.py +++ b/pixivpy3/aapi.py @@ -71,10 +71,6 @@ def set_api_proxy(self, proxy_hosts: str = "http://app-api.pixivlite.com") -> No def _url(self, endpoint: str) -> str: return f"{self.hosts}{endpoint}" - @classmethod - def _ajax_url(cls, endpoint: str) -> str: - return f"https://www.pixiv.net{endpoint}" - # Check auth and set BearerToken to headers def no_auth_requests_call( self, @@ -871,7 +867,7 @@ def illust_new( # 特辑详情 (无需登录,调用Web API) def showcase_article(self, showcase_id: int | str) -> ParsedJson: - url = self._ajax_url("/ajax/showcase/article") + url = "https://www.pixiv.net/ajax/showcase/article" # Web API,伪造Chrome的User-Agent headers = { "User-Agent": (