simple-rule34 0.1.6.1__tar.gz → 1.0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simple_rule34-1.0.0.0/PKG-INFO +20 -0
- simple_rule34-1.0.0.0/pyproject.toml +27 -0
- simple_rule34-1.0.0.0/src/SimpleRule34/__init__.py +1 -0
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/src/SimpleRule34/exceptions.py +0 -8
- simple_rule34-1.0.0.0/src/SimpleRule34/main.py +207 -0
- simple_rule34-1.0.0.0/src/SimpleRule34/types.py +125 -0
- simple_rule34-1.0.0.0/src/SimpleRule34/utils.py +31 -0
- simple_rule34-1.0.0.0/src/simple_rule34.egg-info/PKG-INFO +20 -0
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/src/simple_rule34.egg-info/SOURCES.txt +1 -1
- simple_rule34-1.0.0.0/src/simple_rule34.egg-info/requires.txt +3 -0
- simple_rule34-1.0.0.0/tests/test.py +20 -0
- simple_rule34-0.1.6.1/PKG-INFO +0 -58
- simple_rule34-0.1.6.1/pyproject.toml +0 -65
- simple_rule34-0.1.6.1/src/SimpleRule34/Rule34.py +0 -151
- simple_rule34-0.1.6.1/src/SimpleRule34/__init__.py +0 -1
- simple_rule34-0.1.6.1/src/SimpleRule34/types.py +0 -62
- simple_rule34-0.1.6.1/src/SimpleRule34/utils.py +0 -22
- simple_rule34-0.1.6.1/src/simple_rule34.egg-info/PKG-INFO +0 -58
- simple_rule34-0.1.6.1/src/simple_rule34.egg-info/requires.txt +0 -41
- simple_rule34-0.1.6.1/tests/test.py +0 -40
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/LICENSE +0 -0
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/README.md +0 -0
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/setup.cfg +0 -0
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/src/__init__.py +0 -0
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/src/simple_rule34.egg-info/dependency_links.txt +0 -0
- {simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/src/simple_rule34.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simple_rule34
|
|
3
|
+
Version: 1.0.0.0
|
|
4
|
+
Summary: Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
5
|
+
Author-email: StarMan12 <author@example.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/SyperAlexKomp/simple-rule34-api
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/SyperAlexKomp/simple-rule34-api/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: aiofiles~=25.1.0
|
|
15
|
+
Requires-Dist: aiohttp~=3.12.15
|
|
16
|
+
Requires-Dist: pydantic~=2.12.5
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# rule34-simple-api
|
|
20
|
+
Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "simple_rule34"
|
|
7
|
+
version = "1.0.0.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name="StarMan12", email="author@example.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "Simple api wrapper of rule34.xxx for python with asynchronous support"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
]
|
|
19
|
+
dependencies = [
|
|
20
|
+
'aiofiles~=25.1.0',
|
|
21
|
+
'aiohttp~=3.12.15',
|
|
22
|
+
'pydantic~=2.12.5'
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
"Homepage" = "https://github.com/SyperAlexKomp/simple-rule34-api"
|
|
27
|
+
"Bug Tracker" = "https://github.com/SyperAlexKomp/simple-rule34-api/issues"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .main import Rule34Api
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import xml.etree.ElementTree as ET
|
|
3
|
+
|
|
4
|
+
from .types import *
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Rule34BaseApi:
|
|
8
|
+
_header = {'User-Agent': 'rule34-simple-api (Request)'}
|
|
9
|
+
_url = f"https://api.rule34.xxx/index.php"
|
|
10
|
+
|
|
11
|
+
def __init__(self, user_id: int, api_key: str, **kwargs):
|
|
12
|
+
self._params = {
|
|
13
|
+
'user_id': user_id,
|
|
14
|
+
'api_key': api_key,
|
|
15
|
+
'page': "dapi",
|
|
16
|
+
'q': "index",
|
|
17
|
+
**kwargs,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async def _get(self, json_: bool = True, **params) -> dict | str:
|
|
21
|
+
"""
|
|
22
|
+
Raw request method
|
|
23
|
+
|
|
24
|
+
:return:
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# API allow boolean values only in 0/1 format, so we need to convert default boolean to this format
|
|
28
|
+
json_parsed = 1 if json_ else 0
|
|
29
|
+
|
|
30
|
+
async with aiohttp.ClientSession(headers=self._header) as session:
|
|
31
|
+
async with session.get(self._url, params={**self._params, **params, 'json': json_parsed}) as response:
|
|
32
|
+
if not response.ok:
|
|
33
|
+
raise ApiException(await response.text())
|
|
34
|
+
|
|
35
|
+
# Used for handling XML response
|
|
36
|
+
if not json_:
|
|
37
|
+
return await response.text()
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
return await response.json()
|
|
41
|
+
except json.decoder.JSONDecodeError:
|
|
42
|
+
raise ApiException(await response.text())
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Rule34PostApi(Rule34BaseApi):
|
|
46
|
+
def __init__(self, user_id: int, api_key: str, **kwargs):
|
|
47
|
+
super().__init__(user_id, api_key, **kwargs)
|
|
48
|
+
self._params['s'] = "post"
|
|
49
|
+
|
|
50
|
+
async def get(self, id: int) -> Rule34Post:
|
|
51
|
+
"""
|
|
52
|
+
Method used to obtain a post by its ID
|
|
53
|
+
|
|
54
|
+
:param id: Post ID
|
|
55
|
+
:return: Post
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
post = await self._get(id=id)
|
|
59
|
+
return Rule34Post(**post[0])
|
|
60
|
+
|
|
61
|
+
async def get_count(self, tags: list[str] = None) -> int:
|
|
62
|
+
"""
|
|
63
|
+
Method used to get amount of all posts based on given tags.
|
|
64
|
+
This value also includes deleted posts, actual amount of posts may be less.
|
|
65
|
+
|
|
66
|
+
:param tags: List of tags
|
|
67
|
+
:return: Amount of posts
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
if tags is None:
|
|
71
|
+
tags = []
|
|
72
|
+
|
|
73
|
+
xml_data = await self._get(json_=False, tags=" ".join(tags))
|
|
74
|
+
xml_root = ET.fromstring(xml_data)
|
|
75
|
+
|
|
76
|
+
return int(xml_root.get('count'))
|
|
77
|
+
|
|
78
|
+
async def get_list(self, amount: int = 1000, page: int = 0, tags: list[str] = None,
|
|
79
|
+
forbidden_tags: list[str] = None) -> list[Rule34Post]:
|
|
80
|
+
"""
|
|
81
|
+
Method used to obtain list of posts based on given tags.
|
|
82
|
+
|
|
83
|
+
:param amount: Amount of posts that will be searched with this request
|
|
84
|
+
:param page: Page number
|
|
85
|
+
:param tags: List of tags
|
|
86
|
+
:param forbidden_tags: List of tags posts with whom will be removed from list. When you specify forbidden tags returned amount of posts may be less than specified in amount value.
|
|
87
|
+
:return: List of posts
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
if tags is None:
|
|
91
|
+
tags = []
|
|
92
|
+
if forbidden_tags is None:
|
|
93
|
+
forbidden_tags = []
|
|
94
|
+
|
|
95
|
+
if amount > 1000:
|
|
96
|
+
raise ValueError(f"The max size of request is 1000 when you tried to request {amount}")
|
|
97
|
+
|
|
98
|
+
raw_list = await self._get(limit=amount, pid=page, tags=" ".join(tags))
|
|
99
|
+
post_list = [Rule34Post(**data) for data in raw_list]
|
|
100
|
+
|
|
101
|
+
# Fast return if not sort is needed
|
|
102
|
+
if len(forbidden_tags) < 1:
|
|
103
|
+
return post_list
|
|
104
|
+
|
|
105
|
+
sorted_post_list = []
|
|
106
|
+
for post in post_list:
|
|
107
|
+
if any(tag in forbidden_tags for tag in post.tags):
|
|
108
|
+
pass
|
|
109
|
+
else:
|
|
110
|
+
sorted_post_list.append(post)
|
|
111
|
+
|
|
112
|
+
return sorted_post_list
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class Rule34CommentsApi(Rule34BaseApi):
|
|
116
|
+
def __init__(self, user_id: int, api_key: str, **kwargs):
|
|
117
|
+
super().__init__(user_id, api_key, **kwargs)
|
|
118
|
+
self._params['s'] = "comment"
|
|
119
|
+
|
|
120
|
+
async def get(self, post_id: int) -> list[Rule34Comment]:
|
|
121
|
+
"""
|
|
122
|
+
Method used to obtain list of comments based on given post id.
|
|
123
|
+
|
|
124
|
+
:param post_id: Post ID
|
|
125
|
+
:return: List of comments
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
xml_data = await self._get(post_id=post_id, json_=False)
|
|
129
|
+
xml_root = ET.fromstring(xml_data)
|
|
130
|
+
|
|
131
|
+
return [Rule34Comment(**comment_e.attrib) for comment_e in xml_root.findall("comment")]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class Rule34TagsApi(Rule34BaseApi):
|
|
135
|
+
def __init__(self, user_id: int, api_key: str, **kwargs):
|
|
136
|
+
super().__init__(user_id, api_key, **kwargs)
|
|
137
|
+
self._params['s'] = "tag"
|
|
138
|
+
|
|
139
|
+
async def get(self, id: int) -> Rule34Tag | None:
|
|
140
|
+
"""
|
|
141
|
+
Method used to obtain a tag data by its ID
|
|
142
|
+
|
|
143
|
+
:param id: Tag ID
|
|
144
|
+
:return: Tag
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
xml_data = await self._get(id=id, json_=False)
|
|
148
|
+
xml_root = ET.fromstring(xml_data)
|
|
149
|
+
|
|
150
|
+
raw_tag_data = xml_root.find("tag")
|
|
151
|
+
if raw_tag_data is None:
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
return Rule34Tag(**raw_tag_data.attrib)
|
|
155
|
+
|
|
156
|
+
async def get_list(self, amount: int = 100, page: int = 0) -> list[Rule34Tag]:
|
|
157
|
+
"""
|
|
158
|
+
Method used to obtain given amount of tags.
|
|
159
|
+
|
|
160
|
+
:param amount: Amount of tags you want to obtain
|
|
161
|
+
:return: List of tags
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
xml_data = await self._get(json_=False, limit=amount, pid=page)
|
|
165
|
+
xml_root = ET.fromstring(xml_data)
|
|
166
|
+
|
|
167
|
+
return [Rule34Tag(**tag_e.attrib) for tag_e in xml_root.findall("tag")]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class Rule34AutocompleteApi(Rule34BaseApi):
|
|
171
|
+
def __init__(self, user_id: int, api_key: str, **kwargs):
|
|
172
|
+
super().__init__(user_id, api_key, **kwargs)
|
|
173
|
+
self._url = "https://api.rule34.xxx/autocomplete.php"
|
|
174
|
+
self._params = {}
|
|
175
|
+
|
|
176
|
+
async def search(self, text: str) -> list[Rule34Autocomplete]:
|
|
177
|
+
return [Rule34Autocomplete(**data) for data in eval(await self._get(json_=False, q=text))]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class Rule34Api:
|
|
181
|
+
def __init__(self, user_id: int, api_key: str, **kwargs):
|
|
182
|
+
"""
|
|
183
|
+
After 13.07.2025 you need to use API key and user id to access the API.
|
|
184
|
+
More info: https://discord.com/channels/336564284207267850/497927834241859586/1393885318477906021
|
|
185
|
+
|
|
186
|
+
:param user_id: User ID
|
|
187
|
+
:param api_key: API Key
|
|
188
|
+
:param kwargs: Any other parameters that you want to pass to ANY requests. (No use cases, but may be used if any other global params will be added in the future)
|
|
189
|
+
"""
|
|
190
|
+
self._user_id = user_id
|
|
191
|
+
self._api_key = api_key
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def post(self) -> Rule34PostApi:
|
|
195
|
+
return Rule34PostApi(user_id=self._user_id, api_key=self._api_key)
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def comments(self) -> Rule34CommentsApi:
|
|
199
|
+
return Rule34CommentsApi(user_id=self._user_id, api_key=self._api_key)
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def tags(self) -> Rule34TagsApi:
|
|
203
|
+
return Rule34TagsApi(user_id=self._user_id, api_key=self._api_key)
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def autocomplete(self) -> Rule34AutocompleteApi:
|
|
207
|
+
return Rule34AutocompleteApi(user_id=self._user_id, api_key=self._api_key)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import typing
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import aiofiles
|
|
9
|
+
import aiohttp
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, field_validator, HttpUrl, Field
|
|
12
|
+
|
|
13
|
+
from .exceptions import ApiException
|
|
14
|
+
from .utils import get_file_type
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class File(BaseModel):
|
|
18
|
+
url: HttpUrl
|
|
19
|
+
type: str = None
|
|
20
|
+
|
|
21
|
+
def __init__(self, /, **data: typing.Any) -> None:
|
|
22
|
+
super().__init__(**data)
|
|
23
|
+
|
|
24
|
+
self.type = get_file_type(str(self.url))
|
|
25
|
+
|
|
26
|
+
async def download(self, path: Path | str = "./rule34_downloads") -> Path:
|
|
27
|
+
if isinstance(path, str):
|
|
28
|
+
path = Path(path)
|
|
29
|
+
# Create storage path
|
|
30
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
|
|
32
|
+
async with aiohttp.ClientSession() as session:
|
|
33
|
+
async with session.get(str(self.url)) as response:
|
|
34
|
+
if response.status != 200:
|
|
35
|
+
raise ApiException(f"Api returned status code {response.status} with message"
|
|
36
|
+
f" {await response.text()}")
|
|
37
|
+
|
|
38
|
+
file_name = os.path.basename(str(self.url))
|
|
39
|
+
save_path = path / file_name
|
|
40
|
+
|
|
41
|
+
async with aiofiles.open(save_path, 'wb') as file:
|
|
42
|
+
await file.write(await response.read())
|
|
43
|
+
|
|
44
|
+
return save_path
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Rule34Post(BaseModel):
|
|
48
|
+
id: int
|
|
49
|
+
owner: str | None
|
|
50
|
+
status: str | None
|
|
51
|
+
rating: str | None
|
|
52
|
+
score: int | None
|
|
53
|
+
|
|
54
|
+
preview_file: File = Field(validation_alias="preview_url")
|
|
55
|
+
sample_file: File = Field(validation_alias="sample_url")
|
|
56
|
+
file: File = Field(validation_alias="file_url")
|
|
57
|
+
source: str | None
|
|
58
|
+
|
|
59
|
+
width: int | None
|
|
60
|
+
height: int | None
|
|
61
|
+
hash: str | None
|
|
62
|
+
image: str | None
|
|
63
|
+
directory: int | None
|
|
64
|
+
|
|
65
|
+
change: int | None
|
|
66
|
+
parent_id: int | None
|
|
67
|
+
has_notes: bool | None
|
|
68
|
+
comment_count: int | None
|
|
69
|
+
|
|
70
|
+
sample: bool | None
|
|
71
|
+
sample_height: int | None
|
|
72
|
+
sample_width: int | None
|
|
73
|
+
|
|
74
|
+
tags: typing.List[str] | None
|
|
75
|
+
|
|
76
|
+
@field_validator('tags', mode='before')
|
|
77
|
+
@classmethod
|
|
78
|
+
def split_tags(cls, v):
|
|
79
|
+
if isinstance(v, str):
|
|
80
|
+
return v.strip().split()
|
|
81
|
+
return v
|
|
82
|
+
|
|
83
|
+
@field_validator('preview_file', 'sample_file', 'file', mode='before', check_fields=False)
|
|
84
|
+
@classmethod
|
|
85
|
+
def wrap_in_file(cls, v):
|
|
86
|
+
if isinstance(v, (str, HttpUrl)):
|
|
87
|
+
return File(url=v)
|
|
88
|
+
return v
|
|
89
|
+
|
|
90
|
+
class Config:
|
|
91
|
+
populate_by_name = True
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Rule34Comment(BaseModel):
|
|
95
|
+
id: int
|
|
96
|
+
post_id: int
|
|
97
|
+
message: str = Field(alias="body")
|
|
98
|
+
creator: str
|
|
99
|
+
creator_id: int
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class Rule34TagType(Enum):
|
|
103
|
+
GENERAL = "0"
|
|
104
|
+
ARTIST = "1"
|
|
105
|
+
COPYRIGHT = "3"
|
|
106
|
+
UNKNOWN = "2"
|
|
107
|
+
CHARACTER = "4"
|
|
108
|
+
META = "5"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class Rule34Tag(BaseModel):
|
|
112
|
+
id: int
|
|
113
|
+
type: Rule34TagType
|
|
114
|
+
name: str
|
|
115
|
+
count: int = Field(default_factory=int)
|
|
116
|
+
ambiguous: bool
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class Rule34Autocomplete(BaseModel):
|
|
120
|
+
label: str
|
|
121
|
+
value: str
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def count(self) -> int:
|
|
125
|
+
return int(re.search(r'\((\d+)\)', self.label).group(1))
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
FILE_TYPES = {
|
|
2
|
+
'jpg': "photo",
|
|
3
|
+
'jpeg': "photo",
|
|
4
|
+
'png': "photo",
|
|
5
|
+
|
|
6
|
+
'mp4': "video",
|
|
7
|
+
'avi': "video",
|
|
8
|
+
'mov': "video",
|
|
9
|
+
'webm': "video",
|
|
10
|
+
|
|
11
|
+
'gif': "animation",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def get_file_size(url, session):
|
|
16
|
+
async with session.head(url=url, allow_redirects=True) as response:
|
|
17
|
+
if 'Content-Length' in response.headers:
|
|
18
|
+
size = int(response.headers['Content-Length'])
|
|
19
|
+
return size
|
|
20
|
+
else:
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_file_type(url) -> str | None:
|
|
25
|
+
file_extension = url.split('.')[-1].lower()
|
|
26
|
+
|
|
27
|
+
if file_extension not in FILE_TYPES.keys(): return None
|
|
28
|
+
|
|
29
|
+
return FILE_TYPES[file_extension]
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simple_rule34
|
|
3
|
+
Version: 1.0.0.0
|
|
4
|
+
Summary: Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
5
|
+
Author-email: StarMan12 <author@example.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/SyperAlexKomp/simple-rule34-api
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/SyperAlexKomp/simple-rule34-api/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: aiofiles~=25.1.0
|
|
15
|
+
Requires-Dist: aiohttp~=3.12.15
|
|
16
|
+
Requires-Dist: pydantic~=2.12.5
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# rule34-simple-api
|
|
20
|
+
Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
@@ -2,9 +2,9 @@ LICENSE
|
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
4
|
src/__init__.py
|
|
5
|
-
src/SimpleRule34/Rule34.py
|
|
6
5
|
src/SimpleRule34/__init__.py
|
|
7
6
|
src/SimpleRule34/exceptions.py
|
|
7
|
+
src/SimpleRule34/main.py
|
|
8
8
|
src/SimpleRule34/types.py
|
|
9
9
|
src/SimpleRule34/utils.py
|
|
10
10
|
src/simple_rule34.egg-info/PKG-INFO
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from src.SimpleRule34 import Rule34Api
|
|
4
|
+
|
|
5
|
+
api = Rule34Api(api_key="3cb81d49b14a1f834f442c020d429bef836c3c2c29b8cc345f961d4c85d72daa07d970cd422059c2333d229da0efc38179057373f1da8d267126d542acdf74d6", user_id=5260076)
|
|
6
|
+
|
|
7
|
+
async def foo(_id):
|
|
8
|
+
p = await api.get_post_list(tags=["genshin_impact", f"id:<={_id}"], page=27, limit=1000)
|
|
9
|
+
return p[-1].id
|
|
10
|
+
|
|
11
|
+
async def main():
|
|
12
|
+
while True:
|
|
13
|
+
i = input("Enter tag: ")
|
|
14
|
+
for x in await api.autocomplete.search(text=i):
|
|
15
|
+
print(x)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if __name__ == '__main__':
|
|
20
|
+
asyncio.run(main())
|
simple_rule34-0.1.6.1/PKG-INFO
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: simple_rule34
|
|
3
|
-
Version: 0.1.6.1
|
|
4
|
-
Summary: Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
5
|
-
Author-email: StarMan12 <author@example.com>
|
|
6
|
-
Project-URL: Homepage, https://github.com/SyperAlexKomp/simple-rule34-api
|
|
7
|
-
Project-URL: Bug Tracker, https://github.com/SyperAlexKomp/simple-rule34-api/issues
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.9
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: aiohttp==3.8.4
|
|
15
|
-
Requires-Dist: aiosignal==1.3.1
|
|
16
|
-
Requires-Dist: alabaster==0.7.13
|
|
17
|
-
Requires-Dist: async-timeout==4.0.2
|
|
18
|
-
Requires-Dist: attrs==23.1.0
|
|
19
|
-
Requires-Dist: Babel==2.9.1
|
|
20
|
-
Requires-Dist: build==0.10.0
|
|
21
|
-
Requires-Dist: certifi==2023.5.7
|
|
22
|
-
Requires-Dist: charset-normalizer==3.2.0
|
|
23
|
-
Requires-Dist: colorama==0.4.6
|
|
24
|
-
Requires-Dist: docopt==0.6.2
|
|
25
|
-
Requires-Dist: docutils==0.18.1
|
|
26
|
-
Requires-Dist: frozenlist==1.4.0
|
|
27
|
-
Requires-Dist: idna==3.4
|
|
28
|
-
Requires-Dist: imagesize==1.4.1
|
|
29
|
-
Requires-Dist: importlib-metadata==6.8.0
|
|
30
|
-
Requires-Dist: Jinja2==3.1.2
|
|
31
|
-
Requires-Dist: MarkupSafe==2.1.3
|
|
32
|
-
Requires-Dist: multidict==6.0.4
|
|
33
|
-
Requires-Dist: packaging==23.1
|
|
34
|
-
Requires-Dist: pipreqs==0.4.13
|
|
35
|
-
Requires-Dist: Pygments==2.15.1
|
|
36
|
-
Requires-Dist: pyproject_hooks==1.0.0
|
|
37
|
-
Requires-Dist: requests==2.31.0
|
|
38
|
-
Requires-Dist: snowballstemmer==2.2.0
|
|
39
|
-
Requires-Dist: Sphinx==6.2.1
|
|
40
|
-
Requires-Dist: sphinx-rtd-theme==1.2.2
|
|
41
|
-
Requires-Dist: sphinxcontrib-applehelp==1.0.4
|
|
42
|
-
Requires-Dist: sphinxcontrib-devhelp==1.0.2
|
|
43
|
-
Requires-Dist: sphinxcontrib-htmlhelp==2.0.1
|
|
44
|
-
Requires-Dist: sphinxcontrib-jquery==4.1
|
|
45
|
-
Requires-Dist: sphinxcontrib-jsmath==1.0.1
|
|
46
|
-
Requires-Dist: sphinxcontrib-qthelp==1.0.3
|
|
47
|
-
Requires-Dist: sphinxcontrib-serializinghtml==1.1.5
|
|
48
|
-
Requires-Dist: tomli==2.0.1
|
|
49
|
-
Requires-Dist: urllib3==2.0.3
|
|
50
|
-
Requires-Dist: yarg==0.1.9
|
|
51
|
-
Requires-Dist: yarl==1.9.2
|
|
52
|
-
Requires-Dist: zipp==3.16.2
|
|
53
|
-
Requires-Dist: aiofiles~=23.2.1
|
|
54
|
-
Requires-Dist: pydantic~=2.7.1
|
|
55
|
-
Dynamic: license-file
|
|
56
|
-
|
|
57
|
-
# rule34-simple-api
|
|
58
|
-
Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=61.0"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "simple_rule34"
|
|
7
|
-
version = "0.1.6.1"
|
|
8
|
-
authors = [
|
|
9
|
-
{ name="StarMan12", email="author@example.com" },
|
|
10
|
-
]
|
|
11
|
-
description = "Simple api wrapper of rule34.xxx for python with asynchronous support"
|
|
12
|
-
readme = "README.md"
|
|
13
|
-
requires-python = ">=3.9"
|
|
14
|
-
classifiers = [
|
|
15
|
-
"Programming Language :: Python :: 3",
|
|
16
|
-
"License :: OSI Approved :: MIT License",
|
|
17
|
-
"Operating System :: OS Independent",
|
|
18
|
-
]
|
|
19
|
-
dependencies = [
|
|
20
|
-
'aiohttp==3.8.4',
|
|
21
|
-
'aiosignal==1.3.1',
|
|
22
|
-
'alabaster==0.7.13',
|
|
23
|
-
'async-timeout==4.0.2',
|
|
24
|
-
'attrs==23.1.0',
|
|
25
|
-
'Babel==2.9.1',
|
|
26
|
-
'build==0.10.0',
|
|
27
|
-
'certifi==2023.5.7',
|
|
28
|
-
'charset-normalizer==3.2.0',
|
|
29
|
-
'colorama==0.4.6',
|
|
30
|
-
'docopt==0.6.2',
|
|
31
|
-
'docutils==0.18.1',
|
|
32
|
-
'frozenlist==1.4.0',
|
|
33
|
-
'idna==3.4',
|
|
34
|
-
'imagesize==1.4.1',
|
|
35
|
-
'importlib-metadata==6.8.0',
|
|
36
|
-
'Jinja2==3.1.2',
|
|
37
|
-
'MarkupSafe==2.1.3',
|
|
38
|
-
'multidict==6.0.4',
|
|
39
|
-
'packaging==23.1',
|
|
40
|
-
'pipreqs==0.4.13',
|
|
41
|
-
'Pygments==2.15.1',
|
|
42
|
-
'pyproject_hooks==1.0.0',
|
|
43
|
-
'requests==2.31.0',
|
|
44
|
-
'snowballstemmer==2.2.0',
|
|
45
|
-
'Sphinx==6.2.1',
|
|
46
|
-
'sphinx-rtd-theme==1.2.2',
|
|
47
|
-
'sphinxcontrib-applehelp==1.0.4',
|
|
48
|
-
'sphinxcontrib-devhelp==1.0.2',
|
|
49
|
-
'sphinxcontrib-htmlhelp==2.0.1',
|
|
50
|
-
'sphinxcontrib-jquery==4.1',
|
|
51
|
-
'sphinxcontrib-jsmath==1.0.1',
|
|
52
|
-
'sphinxcontrib-qthelp==1.0.3',
|
|
53
|
-
'sphinxcontrib-serializinghtml==1.1.5',
|
|
54
|
-
'tomli==2.0.1',
|
|
55
|
-
'urllib3==2.0.3',
|
|
56
|
-
'yarg==0.1.9',
|
|
57
|
-
'yarl==1.9.2',
|
|
58
|
-
'zipp==3.16.2',
|
|
59
|
-
'aiofiles~=23.2.1',
|
|
60
|
-
'pydantic~=2.7.1'
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
[project.urls]
|
|
64
|
-
"Homepage" = "https://github.com/SyperAlexKomp/simple-rule34-api"
|
|
65
|
-
"Bug Tracker" = "https://github.com/SyperAlexKomp/simple-rule34-api/issues"
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import random
|
|
2
|
-
import time
|
|
3
|
-
|
|
4
|
-
import aiohttp
|
|
5
|
-
import datetime
|
|
6
|
-
import logging
|
|
7
|
-
import xml.etree.ElementTree as ET
|
|
8
|
-
|
|
9
|
-
from .exceptions import *
|
|
10
|
-
from .types import *
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Rule34Api:
|
|
14
|
-
def __init__(self, api_str: str):
|
|
15
|
-
self.header = {'User-Agent': 'rule34-simple-api 0.1.5.6 (Request)'}
|
|
16
|
-
self.api_str = api_str
|
|
17
|
-
|
|
18
|
-
async def get_post_count(self, tags: str = '') -> int:
|
|
19
|
-
async with aiohttp.ClientSession(headers=self.header) as session:
|
|
20
|
-
async with session.get(f'https://api.rule34.xxx/index.php?'
|
|
21
|
-
f'page=dapi&s=post&q=index&tags={tags}&{self.api_str}') as response:
|
|
22
|
-
xml_data = await response.text()
|
|
23
|
-
|
|
24
|
-
xml_root = ET.fromstring(xml_data)
|
|
25
|
-
|
|
26
|
-
return int(xml_root.get('count'))
|
|
27
|
-
|
|
28
|
-
async def get_post(self, id: int) -> Post:
|
|
29
|
-
st = time.time()
|
|
30
|
-
|
|
31
|
-
async with aiohttp.ClientSession(headers=self.header) as session:
|
|
32
|
-
async with session.get(f'https://api.rule34.xxx/index.php?'
|
|
33
|
-
f'json=1&page=dapi&s=post&q=index&id={id}&{self.api_str}') as response:
|
|
34
|
-
if response.status != 200:
|
|
35
|
-
raise ApiException(f"Api returned status code {response.status} with message"
|
|
36
|
-
f" {await response.text()}")
|
|
37
|
-
|
|
38
|
-
j = await response.json()
|
|
39
|
-
data = j[0]
|
|
40
|
-
|
|
41
|
-
data["main"] = {
|
|
42
|
-
"url": data['file_url']
|
|
43
|
-
}
|
|
44
|
-
data["preview"] = {
|
|
45
|
-
"url": data['preview_url']
|
|
46
|
-
}
|
|
47
|
-
data["tags"] = data["tags"].split(" ")
|
|
48
|
-
|
|
49
|
-
logging.debug(f"Post[{id}] where found in {time.time() - st}s")
|
|
50
|
-
|
|
51
|
-
return Post(**data)
|
|
52
|
-
|
|
53
|
-
async def get_random_post(self, tags: str = '', forbidden_tags: list[str] = []) -> Post:
|
|
54
|
-
start_time = time.time()
|
|
55
|
-
|
|
56
|
-
post_count = await self.get_post_count(tags)
|
|
57
|
-
|
|
58
|
-
page_count = post_count // 1000
|
|
59
|
-
|
|
60
|
-
if page_count > 0:
|
|
61
|
-
post_list = await self.get_post_list(page_id=random.randint(0, page_count if page_count <= 200 else 200),
|
|
62
|
-
tags=tags, limit=1000)
|
|
63
|
-
|
|
64
|
-
else:
|
|
65
|
-
post_list = await self.get_post_list(tags=tags, limit=1000)
|
|
66
|
-
|
|
67
|
-
post_list_ = []
|
|
68
|
-
|
|
69
|
-
for post in post_list:
|
|
70
|
-
if any(tag in forbidden_tags for tag in post.main.tags):
|
|
71
|
-
pass
|
|
72
|
-
else:
|
|
73
|
-
post_list_.append(post)
|
|
74
|
-
|
|
75
|
-
logging.debug(f"Random posts where found in {time.time() - start_time}s")
|
|
76
|
-
|
|
77
|
-
return post_list_[random.randint(0, len(post_list_) - 1)] if len(post_list_) > 0 else None
|
|
78
|
-
|
|
79
|
-
async def get_random_posts(self, tags: str = '', count: int = 8, forbidden_tags: list[str] = []) -> list[Post]:
|
|
80
|
-
st = time.time()
|
|
81
|
-
|
|
82
|
-
request_count = 1
|
|
83
|
-
true_count = count*20
|
|
84
|
-
|
|
85
|
-
post_list = []
|
|
86
|
-
|
|
87
|
-
if true_count > 1000:
|
|
88
|
-
request_count = true_count // 1000
|
|
89
|
-
|
|
90
|
-
post_count = await self.get_post_count(tags)
|
|
91
|
-
page_id = int(random.randint(0, int(post_count / true_count)) / 8) if post_count >= true_count else 0
|
|
92
|
-
|
|
93
|
-
for pid in range(request_count + 1):
|
|
94
|
-
post_list += await self.get_post_list(tags=tags, forbidden_tags=forbidden_tags,
|
|
95
|
-
page_id=page_id, limit=true_count if true_count <= 1000 else 1000)
|
|
96
|
-
|
|
97
|
-
getted = []
|
|
98
|
-
|
|
99
|
-
for x in range(count):
|
|
100
|
-
if len(post_list) > 0:
|
|
101
|
-
getted.append(post_list[random.randint(0, len(post_list) - 1)])
|
|
102
|
-
else:
|
|
103
|
-
pass
|
|
104
|
-
|
|
105
|
-
logging.debug(f"{count} random posts where found in {time.time() - st}s")
|
|
106
|
-
|
|
107
|
-
return getted
|
|
108
|
-
|
|
109
|
-
async def get_post_list(self, limit: int = 1000, page_id: int = 0, tags: str = '', forbidden_tags: list[str] = [])\
|
|
110
|
-
-> list[Post]:
|
|
111
|
-
if limit > 1000:
|
|
112
|
-
raise ToBigRequestException(f"The max size of request is 1000 when you tried to request {limit}")
|
|
113
|
-
|
|
114
|
-
async with aiohttp.ClientSession(headers=self.header) as session:
|
|
115
|
-
start_time = time.time()
|
|
116
|
-
|
|
117
|
-
async with session.get(f'https://api.rule34.xxx/index.php?'
|
|
118
|
-
f'json=1&page=dapi&s=post&q=index&limit={limit}&pid={page_id}&tags={tags}&{self.api_str}') as response:
|
|
119
|
-
if response.status != 200:
|
|
120
|
-
raise ApiException(f"Api returned status code {response.status} with message"
|
|
121
|
-
f" {await response.text()}")
|
|
122
|
-
|
|
123
|
-
data = await response.json()
|
|
124
|
-
|
|
125
|
-
logging.debug(f"Request with {limit} limit posts were done in {time.time() - start_time}s")
|
|
126
|
-
|
|
127
|
-
post_list = []
|
|
128
|
-
for post_data in data:
|
|
129
|
-
post_data["main"] = {
|
|
130
|
-
"url": post_data['file_url']
|
|
131
|
-
}
|
|
132
|
-
post_data["preview"] = {
|
|
133
|
-
"url": post_data['preview_url']
|
|
134
|
-
}
|
|
135
|
-
post_data["tags"] = post_data["tags"].split(" ")
|
|
136
|
-
|
|
137
|
-
post_list.append(Post(**post_data))
|
|
138
|
-
|
|
139
|
-
start_time = time.time()
|
|
140
|
-
|
|
141
|
-
post_list_ = []
|
|
142
|
-
|
|
143
|
-
for post in post_list:
|
|
144
|
-
if any(tag in forbidden_tags for tag in post.tags):
|
|
145
|
-
pass
|
|
146
|
-
else:
|
|
147
|
-
post_list_.append(post)
|
|
148
|
-
|
|
149
|
-
logging.debug(f"{len(post_list_)} posts where found in {time.time() - start_time}s")
|
|
150
|
-
|
|
151
|
-
return post_list_
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .Rule34 import Rule34Api
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import typing
|
|
3
|
-
import aiofiles
|
|
4
|
-
import aiohttp
|
|
5
|
-
|
|
6
|
-
from aiofiles import os as aos
|
|
7
|
-
from pydantic import BaseModel
|
|
8
|
-
|
|
9
|
-
from .exceptions import ApiException
|
|
10
|
-
from .utils import get_file_type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class File(BaseModel):
|
|
14
|
-
url: str
|
|
15
|
-
type: str = None
|
|
16
|
-
|
|
17
|
-
def __init__(self, /, **data: typing.Any) -> None:
|
|
18
|
-
super().__init__(**data)
|
|
19
|
-
|
|
20
|
-
self.type = get_file_type(self.url)
|
|
21
|
-
|
|
22
|
-
async def download(self, path: str = r'./rule34_download') -> str:
|
|
23
|
-
try:
|
|
24
|
-
await aos.mkdir(path)
|
|
25
|
-
except:
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
async with aiohttp.ClientSession() as session:
|
|
29
|
-
async with session.get(self.url) as response:
|
|
30
|
-
if response.status != 200:
|
|
31
|
-
raise ApiException(f"Api returned status code {response.status} with message"
|
|
32
|
-
f" {await response.text()}")
|
|
33
|
-
|
|
34
|
-
file_name = os.path.basename(self.url)
|
|
35
|
-
save_path = os.path.join(path, file_name)
|
|
36
|
-
|
|
37
|
-
async with aiofiles.open(save_path, 'wb') as file:
|
|
38
|
-
await file.write(await response.read())
|
|
39
|
-
|
|
40
|
-
return save_path
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class Post(BaseModel):
|
|
44
|
-
directory: int
|
|
45
|
-
hash: str
|
|
46
|
-
width: int
|
|
47
|
-
height: int
|
|
48
|
-
id: int
|
|
49
|
-
change: int
|
|
50
|
-
owner: str
|
|
51
|
-
parent_id: int
|
|
52
|
-
rating: str
|
|
53
|
-
sample: bool
|
|
54
|
-
score: int
|
|
55
|
-
tags: list
|
|
56
|
-
source: str
|
|
57
|
-
status: str
|
|
58
|
-
has_notes: bool
|
|
59
|
-
comment_count: int
|
|
60
|
-
|
|
61
|
-
main: File
|
|
62
|
-
preview: File
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
async def get_file_size(url, session):
|
|
3
|
-
async with session.head(url=url, allow_redirects=True) as response:
|
|
4
|
-
if 'Content-Length' in response.headers:
|
|
5
|
-
size = int(response.headers['Content-Length'])
|
|
6
|
-
return size
|
|
7
|
-
else:
|
|
8
|
-
return None
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def get_file_type(url):
|
|
12
|
-
file_extension = url.split('.')[-1].lower()
|
|
13
|
-
if file_extension in ['jpg', 'jpeg', 'png']:
|
|
14
|
-
return 'photo'
|
|
15
|
-
elif file_extension in ['mp4', 'avi', 'mov']:
|
|
16
|
-
return 'video'
|
|
17
|
-
elif file_extension == 'gif':
|
|
18
|
-
return 'animation'
|
|
19
|
-
else:
|
|
20
|
-
return None
|
|
21
|
-
|
|
22
|
-
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: simple_rule34
|
|
3
|
-
Version: 0.1.6.1
|
|
4
|
-
Summary: Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
5
|
-
Author-email: StarMan12 <author@example.com>
|
|
6
|
-
Project-URL: Homepage, https://github.com/SyperAlexKomp/simple-rule34-api
|
|
7
|
-
Project-URL: Bug Tracker, https://github.com/SyperAlexKomp/simple-rule34-api/issues
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.9
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: aiohttp==3.8.4
|
|
15
|
-
Requires-Dist: aiosignal==1.3.1
|
|
16
|
-
Requires-Dist: alabaster==0.7.13
|
|
17
|
-
Requires-Dist: async-timeout==4.0.2
|
|
18
|
-
Requires-Dist: attrs==23.1.0
|
|
19
|
-
Requires-Dist: Babel==2.9.1
|
|
20
|
-
Requires-Dist: build==0.10.0
|
|
21
|
-
Requires-Dist: certifi==2023.5.7
|
|
22
|
-
Requires-Dist: charset-normalizer==3.2.0
|
|
23
|
-
Requires-Dist: colorama==0.4.6
|
|
24
|
-
Requires-Dist: docopt==0.6.2
|
|
25
|
-
Requires-Dist: docutils==0.18.1
|
|
26
|
-
Requires-Dist: frozenlist==1.4.0
|
|
27
|
-
Requires-Dist: idna==3.4
|
|
28
|
-
Requires-Dist: imagesize==1.4.1
|
|
29
|
-
Requires-Dist: importlib-metadata==6.8.0
|
|
30
|
-
Requires-Dist: Jinja2==3.1.2
|
|
31
|
-
Requires-Dist: MarkupSafe==2.1.3
|
|
32
|
-
Requires-Dist: multidict==6.0.4
|
|
33
|
-
Requires-Dist: packaging==23.1
|
|
34
|
-
Requires-Dist: pipreqs==0.4.13
|
|
35
|
-
Requires-Dist: Pygments==2.15.1
|
|
36
|
-
Requires-Dist: pyproject_hooks==1.0.0
|
|
37
|
-
Requires-Dist: requests==2.31.0
|
|
38
|
-
Requires-Dist: snowballstemmer==2.2.0
|
|
39
|
-
Requires-Dist: Sphinx==6.2.1
|
|
40
|
-
Requires-Dist: sphinx-rtd-theme==1.2.2
|
|
41
|
-
Requires-Dist: sphinxcontrib-applehelp==1.0.4
|
|
42
|
-
Requires-Dist: sphinxcontrib-devhelp==1.0.2
|
|
43
|
-
Requires-Dist: sphinxcontrib-htmlhelp==2.0.1
|
|
44
|
-
Requires-Dist: sphinxcontrib-jquery==4.1
|
|
45
|
-
Requires-Dist: sphinxcontrib-jsmath==1.0.1
|
|
46
|
-
Requires-Dist: sphinxcontrib-qthelp==1.0.3
|
|
47
|
-
Requires-Dist: sphinxcontrib-serializinghtml==1.1.5
|
|
48
|
-
Requires-Dist: tomli==2.0.1
|
|
49
|
-
Requires-Dist: urllib3==2.0.3
|
|
50
|
-
Requires-Dist: yarg==0.1.9
|
|
51
|
-
Requires-Dist: yarl==1.9.2
|
|
52
|
-
Requires-Dist: zipp==3.16.2
|
|
53
|
-
Requires-Dist: aiofiles~=23.2.1
|
|
54
|
-
Requires-Dist: pydantic~=2.7.1
|
|
55
|
-
Dynamic: license-file
|
|
56
|
-
|
|
57
|
-
# rule34-simple-api
|
|
58
|
-
Simple api wrapper of rule34.xxx for python with asynchronous support
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
aiohttp==3.8.4
|
|
2
|
-
aiosignal==1.3.1
|
|
3
|
-
alabaster==0.7.13
|
|
4
|
-
async-timeout==4.0.2
|
|
5
|
-
attrs==23.1.0
|
|
6
|
-
Babel==2.9.1
|
|
7
|
-
build==0.10.0
|
|
8
|
-
certifi==2023.5.7
|
|
9
|
-
charset-normalizer==3.2.0
|
|
10
|
-
colorama==0.4.6
|
|
11
|
-
docopt==0.6.2
|
|
12
|
-
docutils==0.18.1
|
|
13
|
-
frozenlist==1.4.0
|
|
14
|
-
idna==3.4
|
|
15
|
-
imagesize==1.4.1
|
|
16
|
-
importlib-metadata==6.8.0
|
|
17
|
-
Jinja2==3.1.2
|
|
18
|
-
MarkupSafe==2.1.3
|
|
19
|
-
multidict==6.0.4
|
|
20
|
-
packaging==23.1
|
|
21
|
-
pipreqs==0.4.13
|
|
22
|
-
Pygments==2.15.1
|
|
23
|
-
pyproject_hooks==1.0.0
|
|
24
|
-
requests==2.31.0
|
|
25
|
-
snowballstemmer==2.2.0
|
|
26
|
-
Sphinx==6.2.1
|
|
27
|
-
sphinx-rtd-theme==1.2.2
|
|
28
|
-
sphinxcontrib-applehelp==1.0.4
|
|
29
|
-
sphinxcontrib-devhelp==1.0.2
|
|
30
|
-
sphinxcontrib-htmlhelp==2.0.1
|
|
31
|
-
sphinxcontrib-jquery==4.1
|
|
32
|
-
sphinxcontrib-jsmath==1.0.1
|
|
33
|
-
sphinxcontrib-qthelp==1.0.3
|
|
34
|
-
sphinxcontrib-serializinghtml==1.1.5
|
|
35
|
-
tomli==2.0.1
|
|
36
|
-
urllib3==2.0.3
|
|
37
|
-
yarg==0.1.9
|
|
38
|
-
yarl==1.9.2
|
|
39
|
-
zipp==3.16.2
|
|
40
|
-
aiofiles~=23.2.1
|
|
41
|
-
pydantic~=2.7.1
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from SimpleRule34.src.SimpleRule34.Rule34 import Rule34Api
|
|
2
|
-
from SimpleRule34.src.SimpleRule34 import Rule34Api
|
|
3
|
-
import asyncio
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
async def main1():
|
|
7
|
-
|
|
8
|
-
r = Rule34Api()
|
|
9
|
-
print("=====ALL 10=====")
|
|
10
|
-
lis = await r.get_post_list(tags='', limit=10)
|
|
11
|
-
|
|
12
|
-
for x in lis:
|
|
13
|
-
print(x)
|
|
14
|
-
|
|
15
|
-
print("=====FIRST 5=====")
|
|
16
|
-
lis = await r.get_post_list(tags='brawl_stars', limit=5)
|
|
17
|
-
|
|
18
|
-
for x in lis:
|
|
19
|
-
print(x)
|
|
20
|
-
|
|
21
|
-
print("=====SECOND 5=====")
|
|
22
|
-
lis = await r.get_post_list(tags='brawl_stars', limit=5, page_id=1)
|
|
23
|
-
|
|
24
|
-
for x in lis:
|
|
25
|
-
print(x)
|
|
26
|
-
|
|
27
|
-
print("=====EDITED=====")
|
|
28
|
-
post_list_ = await r.get_post_list(tags='brawl_stars', limit=100, page_id=0,
|
|
29
|
-
forbidden_tags=['male'])
|
|
30
|
-
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
async def main():
|
|
35
|
-
r = Rule34Api()
|
|
36
|
-
p = await r.get_post_list(limit=10)
|
|
37
|
-
print(p)
|
|
38
|
-
|
|
39
|
-
if __name__ == '__main__':
|
|
40
|
-
asyncio.run(main())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_rule34-0.1.6.1 → simple_rule34-1.0.0.0}/src/simple_rule34.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|