simple-rule34 0.1.5.5__py3-none-any.whl → 0.1.6.1__py3-none-any.whl

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.
SimpleRule34/Rule34.py CHANGED
@@ -1,213 +1,151 @@
1
1
  import random
2
2
  import time
3
- import typing
4
3
 
5
- import requests
4
+ import aiohttp
6
5
  import datetime
7
6
  import logging
8
7
  import xml.etree.ElementTree as ET
9
8
 
10
9
  from .exceptions import *
11
- from .types import Rule34MainPost, Rule34PostData, Rule34SamplePost, Rule34PreviewPost
12
-
13
-
14
- def parse_result(post_element):
15
-
16
-
17
- id = int(post_element.get('id'))
18
- height = int(post_element.get('height'))
19
- width = int(post_element.get('width'))
20
- url = post_element.get('file_url')
21
-
22
- sample_height = int(post_element.get('sample_height'))
23
- sample_width = int(post_element.get('sample_width'))
24
- sample_url = post_element.get('sample_url')
25
-
26
- sample_post = Rule34SamplePost(sample_height, sample_width, sample_url, id)
27
-
28
- preview_height = int(post_element.get('preview_height'))
29
- preview_width = int(post_element.get('preview_width'))
30
- preview_url = post_element.get('preview_url')
31
-
32
- preview_post = Rule34PreviewPost(preview_height, preview_width, preview_url, id)
33
-
34
- score = int(post_element.get('score'))
35
- rating = post_element.get('rating')
36
- creator_id = int(post_element.get('creator_id'))
37
- tags = post_element.get('tags')
38
- has_children = post_element.get('has_children') == 'true'
39
- created_date = datetime.datetime.strptime(post_element.get('created_at'), "%a %b %d %H:%M:%S %z %Y")
40
- status = post_element.get('status')
41
- source = post_element.get('source')
42
- has_notes = post_element.get('has_notes') == 'true'
43
- has_comments = post_element.get('has_comments') == 'true'
44
-
45
- main_post = Rule34MainPost(score, rating, creator_id, tags, has_children, created_date, status,
46
- source, has_notes, has_comments, height, width, url, id)
47
-
48
- return main_post, sample_post, preview_post
10
+ from .types import *
49
11
 
50
12
 
51
13
  class Rule34Api:
52
- """
53
- Sync main api class
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
54
17
 
55
- """
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()
56
23
 
57
- def __init__(self):
58
- self.s = requests.Session()
59
-
60
- def get_post_count(self, tags: str = '') -> int:
61
- """
62
- This function will search amount of posts with your tags from rule34.xxx
63
-
64
- :param tags: Tags in format 'tag1 tag2 ...'. Base ''
65
- :type tags: str
66
-
67
- :return: Amount of posts with current tags
68
- :rtype: int
69
- """
70
-
71
-
72
- r = self.s.get(f'https://api.rule34.xxx/index.php?'
73
- f'page=dapi&s=post&q=index&tags={tags}')
74
-
75
- xml_root = ET.fromstring(r.text)
24
+ xml_root = ET.fromstring(xml_data)
76
25
 
77
26
  return int(xml_root.get('count'))
78
27
 
79
- def get_post(self, id: int) -> typing.Optional[Rule34PostData]:
80
- """
81
- This function will search post with your id from rule34.xxx
82
-
83
- :param id: id of post
84
- :type id: int
85
-
86
- :return: On success, returns Rule34PostData object
87
- :rtype: :obj: 'typing.Optional[Rule34PostData]'
88
- """
89
-
90
- r = self.s.get(f'https://api.rule34.xxx/index.php?'
91
- f'page=dapi&s=post&q=index&id={id}')
92
-
93
- try:
94
- xml_root = ET.fromstring(r.text)
95
- except:
96
- return None
97
- post_element = xml_root.find('post')
28
+ async def get_post(self, id: int) -> Post:
29
+ st = time.time()
98
30
 
99
- parsed = parse_result(post_element)
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()}")
100
37
 
101
- if parsed is None:
102
- return None
103
- else:
104
- main_post, sample_post, preview_post = parsed
38
+ j = await response.json()
39
+ data = j[0]
105
40
 
106
- return Rule34PostData(id, main_post, sample_post, preview_post)
41
+ data["main"] = {
42
+ "url": data['file_url']
43
+ }
44
+ data["preview"] = {
45
+ "url": data['preview_url']
46
+ }
47
+ data["tags"] = data["tags"].split(" ")
107
48
 
108
- def get_random_post(self, tags: str = '') -> typing.Optional[Rule34PostData]:
109
- """
110
- This function will search 1 random post with your tags from rule34.xxx
49
+ logging.debug(f"Post[{id}] where found in {time.time() - st}s")
111
50
 
112
- :param tags: Tags in format 'tag1 tag2 ...' with which post will be searching. Base ''
113
- :type tags: str
51
+ return Post(**data)
114
52
 
115
- :return: On success, returns Rule34PostData object
116
- :rtype: :obj: 'typing.Optional[Rule34PostData]'
117
- """
53
+ async def get_random_post(self, tags: str = '', forbidden_tags: list[str] = []) -> Post:
54
+ start_time = time.time()
118
55
 
119
- post_count = self.get_post_count(tags)
56
+ post_count = await self.get_post_count(tags)
120
57
 
121
58
  page_count = post_count // 1000
122
59
 
123
60
  if page_count > 0:
124
- post_list = self.get_post_list(page_id=random.randint(0, page_count if page_count <= 200 else 200),
125
- tags=tags, limit=1000)
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)
126
63
 
127
64
  else:
128
- post_list = self.get_post_list(tags=tags, limit=1000)
129
-
130
- return post_list[random.randint(0, len(post_list) - 1)] if len(post_list) > 0 else None
131
-
132
- def get_random_posts(self, tags: str = '', count: int = 8) -> list[Rule34PostData]:
133
- """
134
- This function will search your amount of random posts with your tags from rule34.xxx
65
+ post_list = await self.get_post_list(tags=tags, limit=1000)
135
66
 
136
- :param tags: Tags in format 'tag1 tag2 ...' with which post will be searching. Base ''
137
- :type tags: str
67
+ post_list_ = []
138
68
 
139
- :param count: Amount of posts that will need to be founded. Base 8
140
- :type count: int
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)
141
74
 
142
- :return: List with founded posts
143
- :rtype: :obj: 'list[Rule34PostData]'
75
+ logging.debug(f"Random posts where found in {time.time() - start_time}s")
144
76
 
145
- """
77
+ return post_list_[random.randint(0, len(post_list_) - 1)] if len(post_list_) > 0 else None
146
78
 
79
+ async def get_random_posts(self, tags: str = '', count: int = 8, forbidden_tags: list[str] = []) -> list[Post]:
147
80
  st = time.time()
148
81
 
149
82
  request_count = 1
83
+ true_count = count*20
150
84
 
151
85
  post_list = []
152
86
 
153
- if count > 1000:
154
- request_count = count // 1000
155
-
156
- for pid in range(request_count + 1):
157
- post_list += self.get_post_list(tags=tags)
87
+ if true_count > 1000:
88
+ request_count = true_count // 1000
158
89
 
159
- getted = [post_list[random.randint(0, len(post_list) - 1)] if len(post_list) > 0 else None for x in
160
- range(count)]
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
161
92
 
162
- logging.debug(f"{count} random posts where founded in {time.time() - st}")
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)
163
96
 
164
- return getted
97
+ getted = []
165
98
 
166
- def get_post_list(self, limit: int = 1000, page_id: int = 0, tags: str = '',
167
- blocked_tags: typing.Optional[str] = None) -> list[Rule34PostData]:
168
- """
169
- This function will get list of posts with your tags on page
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
170
104
 
171
- :param limit: limit of posts in list. Base value is 1000
172
- :type limit: int
105
+ logging.debug(f"{count} random posts where found in {time.time() - st}s")
173
106
 
174
- :param page_id: number of page with posts. Base value is 0
175
- :type page_id: int
107
+ return getted
176
108
 
177
- :param tags: Tags in format 'tag1 tag2 ...' with which post will be searching. Base values is ''
178
- :type tags: str
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}")
179
113
 
180
- :parameter blocked_tags: Tags that will be banned from search in format 'tag1 tag2 ...'. Base values is None.
181
- Can slow search
182
- :type blocked_tags: str or None
114
+ async with aiohttp.ClientSession(headers=self.header) as session:
115
+ start_time = time.time()
183
116
 
184
- :return: :obj: 'list[Rule34PostData]'
185
- """
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()}")
186
122
 
187
- if limit > 1000:
188
- raise ToBigRequestException(f"The max size of request is 1000 when you tried to request {limit}")
123
+ data = await response.json()
189
124
 
190
- start_time = time.time()
125
+ logging.debug(f"Request with {limit} limit posts were done in {time.time() - start_time}s")
191
126
 
192
- r = self.s.get(f'https://api.rule34.xxx/index.php?'
193
- f'page=dapi&s=post&q=index&limit={limit}&pid={page_id}&tags={tags}')
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(" ")
194
136
 
195
- logging.debug(f"Request with {limit}limit posts where done in {time.time() - start_time}s")
137
+ post_list.append(Post(**post_data))
196
138
 
197
- xml_root = ET.fromstring(r.text)
198
- posts = xml_root.findall('post')
199
- post_list = []
139
+ start_time = time.time()
200
140
 
201
- start_time = time.time()
202
- for post_element in posts:
203
- parsed = parse_result(post_element)
141
+ post_list_ = []
204
142
 
205
- if parsed is None:
206
- continue
207
- else:
208
- main_post, sample_post, preview_post = parsed
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)
209
148
 
210
- post_list.append(Rule34PostData(main_post.id, main_post, sample_post, preview_post))
211
- logging.debug(f"Creating {len(posts)} objects where done in {time.time() - start_time}s")
149
+ logging.debug(f"{len(post_list_)} posts where found in {time.time() - start_time}s")
212
150
 
213
- return post_list
151
+ return post_list_
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  class ToBigRequestException(Exception):
4
2
  def __init__(self, msg):
5
3
  self.msg = msg
@@ -15,3 +13,11 @@ class RequestMoreThanAvailableException(Exception):
15
13
 
16
14
  def __str__(self):
17
15
  return self.msg
16
+
17
+
18
+ class ApiException(Exception):
19
+ def __init__(self, msg):
20
+ self.msg = msg
21
+
22
+ def __str__(self):
23
+ return self.msg
SimpleRule34/types.py CHANGED
@@ -1,95 +1,62 @@
1
- import datetime
2
- import requests
3
1
  import os
2
+ import typing
3
+ import aiofiles
4
+ import aiohttp
4
5
 
5
- from .utils import get_file_type, get_file_size
6
+ from aiofiles import os as aos
7
+ from pydantic import BaseModel
6
8
 
9
+ from .exceptions import ApiException
10
+ from .utils import get_file_type
7
11
 
8
- class Rule34Post:
9
- def __init__(self, height: int, width: int, url: str, id: int):
10
- self.path = r'./rule34_download'
11
- self.s = requests.Session()
12
12
 
13
- self.height = height
14
- self.width = width
15
- self.url = url
16
- self.id = id
13
+ class File(BaseModel):
14
+ url: str
15
+ type: str = None
17
16
 
18
- self.file_type = get_file_type(self.url)
17
+ def __init__(self, /, **data: typing.Any) -> None:
18
+ super().__init__(**data)
19
19
 
20
- def __str__(self):
21
- return f"<Rule34Post(id={self.id}, height={self.height}, width={self.width}, url={self.url})>"
20
+ self.type = get_file_type(self.url)
22
21
 
23
- def get_file_size(self):
24
- return get_file_size(self.url, self.s)
25
-
26
- def download(self, path = r'./rule34_download'):
27
- r = self.s.get(self.url)
28
- if r.status_code == 200:
29
- try:
30
- os.mkdir(self.path)
31
- except:
32
- pass
33
-
34
- file_name = os.path.basename(self.url)
35
- save_path = os.path.join(path, file_name)
36
- with open(save_path, 'wb') as file:
37
- file.write(r.content)
38
-
39
- return save_path
40
- else:
22
+ async def download(self, path: str = r'./rule34_download') -> str:
23
+ try:
24
+ await aos.mkdir(path)
25
+ except:
41
26
  pass
42
27
 
43
- def get_bytes(self):
44
- r = self.s.get(self.url)
45
-
46
- return r.content
47
-
48
-
49
- class Rule34MainPost(Rule34Post):
50
- def __init__(self, score: int, rating: str, creator_id: int, tags: str, has_children: bool,
51
- created_date: datetime.datetime, status: str, source: str, has_notes: bool, has_comments: bool,
52
- height: int, width: int, url: str, id: int):
53
- super().__init__(height, width, url, id)
54
- self.score = score
55
- self.rating = rating
56
- self.creator_id = creator_id
57
- self.tags = tags.split(" ")
58
- self.has_children = has_children
59
- self.created_date = created_date
60
- self.status = status
61
- self.source = source
62
- self.has_notes = has_notes
63
- self.has_comments = has_comments
64
-
65
- def __str__(self):
66
- return f"<Rule34MainPost(id={self.id}, height={self.height}, width={self.width}, url={self.url}," \
67
- f" score={self.score}, rating={self.rating}, creator_id={self.creator_id}," \
68
- f" has_children={self.has_children}, has_notes={self.has_notes}, has_comments={self.has_comments}" \
69
- f" created_date={self.created_date}, status={self.status}, tags={self.tags})>"
70
-
71
- def format_tags(self, format: str = "#"):
72
- str_tags = (format + ' ').join(self.tags)
73
- return str_tags.split(" ")
74
-
75
-
76
- class Rule34SamplePost(Rule34Post):
77
- def __str__(self):
78
- return f"<Rule34SamplePost(id={self.id}, height={self.height}, width={self.width}, url={self.url})>"
79
-
80
-
81
- class Rule34PreviewPost(Rule34Post):
82
- def __str__(self):
83
- return f"<Rule34PreviewPost(id={self.id}, height={self.height}, width={self.width}, url={self.url})>"
84
-
85
-
86
- class Rule34PostData:
87
- def __init__(self, id: int, main: Rule34MainPost, sample: Rule34SamplePost, preview: Rule34PreviewPost):
88
- self.id = id
89
- self.main = main
90
- self.sample = sample
91
- self.preview = preview
92
-
93
- def __str__(self):
94
- return f"<Rule34PostData(id={self.id}, main={str(self.main)}, sample={str(self.sample)}," \
95
- f" preview={str(self.preview)})>"
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
SimpleRule34/utils.py CHANGED
@@ -1,13 +1,11 @@
1
- import requests
2
1
 
3
-
4
- def get_file_size(url, session: requests.Session):
5
- response = session.head(url, allow_redirects=True)
6
- if 'Content-Length' in response.headers:
7
- size = int(response.headers['Content-Length'])
8
- return size
9
- else:
10
- return None
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
11
9
 
12
10
 
13
11
  def get_file_type(url):
@@ -16,20 +14,9 @@ def get_file_type(url):
16
14
  return 'photo'
17
15
  elif file_extension in ['mp4', 'avi', 'mov']:
18
16
  return 'video'
19
- elif file_extension == '.gif':
17
+ elif file_extension == 'gif':
20
18
  return 'animation'
21
19
  else:
22
20
  return None
23
21
 
24
22
 
25
- def remove_blocked_tags_posts(post_list, blocked_tags):
26
- post_list_ = []
27
-
28
- for post in post_list:
29
- if blocked_tags in post.main.tags:
30
- pass
31
- else:
32
- post_list_.append(post)
33
-
34
- return post
35
-
__init__.py ADDED
File without changes
@@ -0,0 +1,58 @@
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
@@ -0,0 +1,11 @@
1
+ __init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ SimpleRule34/Rule34.py,sha256=Oe9zpotMgJWeqvo-TAn6OqQoyGqsSsHdAOtTNGI-KoA,5526
3
+ SimpleRule34/__init__.py,sha256=C4IbcJ_rjqBhpENXImVGuEQxf81GUwNaycqNNAY_ROc,31
4
+ SimpleRule34/exceptions.py,sha256=dUpJBROzXWT67ZOLAHWWse0srvMRunIa9rSl1Cs10B8,491
5
+ SimpleRule34/types.py,sha256=n9y60b96g9wyD8FAZ_ElETBFNnM1F1GAs5VoxzCFI68,1518
6
+ SimpleRule34/utils.py,sha256=fWx-ntJ672NoktH5Ws9-FcO0gtCNVmd8VfxFxjWqsD0,616
7
+ simple_rule34-0.1.6.1.dist-info/licenses/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
8
+ simple_rule34-0.1.6.1.dist-info/METADATA,sha256=FqjEHB4rhE-PiCgpMam0WY9U93vHspcu5lZb7OGQ8wg,2138
9
+ simple_rule34-0.1.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ simple_rule34-0.1.6.1.dist-info/top_level.txt,sha256=YI-Z1ijzIjlJw2WeM95PSmClCzIvm24KAlyZi80YVNs,22
11
+ simple_rule34-0.1.6.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,186 +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
- async def parse_result(post_element):
14
-
15
-
16
- id = int(post_element.get('id'))
17
- height = int(post_element.get('height'))
18
- width = int(post_element.get('width'))
19
- url = post_element.get('file_url')
20
-
21
- sample_height = int(post_element.get('sample_height'))
22
- sample_width = int(post_element.get('sample_width'))
23
- sample_url = post_element.get('sample_url')
24
-
25
- sample_post = Rule34SamplePost(sample_height, sample_width, sample_url, id)
26
-
27
- preview_height = int(post_element.get('preview_height'))
28
- preview_width = int(post_element.get('preview_width'))
29
- preview_url = post_element.get('preview_url')
30
-
31
- preview_post = Rule34PreviewPost(preview_height, preview_width, preview_url, id)
32
-
33
- score = int(post_element.get('score'))
34
- rating = post_element.get('rating')
35
- creator_id = int(post_element.get('creator_id'))
36
- tags = post_element.get('tags')
37
- has_children = post_element.get('has_children') == 'true'
38
- created_date = datetime.datetime.strptime(post_element.get('created_at'), "%a %b %d %H:%M:%S %z %Y")
39
- status = post_element.get('status')
40
- source = post_element.get('source')
41
- has_notes = post_element.get('has_notes') == 'true'
42
- has_comments = post_element.get('has_comments') == 'true'
43
-
44
- main_post = Rule34MainPost(score, rating, creator_id, tags, has_children, created_date, status,
45
- source, has_notes, has_comments, height, width, url, id)
46
-
47
- return main_post, sample_post, preview_post
48
-
49
- class Rule34Api:
50
- def __init__(self):
51
- self.header = {'User-Agent': 'rule34-simple-api 0.1.5.3 (Request)'}
52
- async def get_post_count(self, tags: str = '') -> int:
53
- async with aiohttp.ClientSession(headers=self.header) as session:
54
- async with session.get(f'https://api.rule34.xxx/index.php?'
55
- f'page=dapi&s=post&q=index&tags={tags}') as response:
56
- xml_data = await response.text()
57
-
58
- xml_root = ET.fromstring(xml_data)
59
-
60
- return int(xml_root.get('count'))
61
-
62
- async def get_post(self, id: int):
63
- st = time.time()
64
-
65
- async with aiohttp.ClientSession(headers=self.header) as session:
66
- async with session.get(f'https://api.rule34.xxx/index.php?'
67
- f'page=dapi&s=post&q=index&id={id}') as response:
68
- xml_data = await response.text()
69
-
70
- try:
71
- xml_root = ET.fromstring(xml_data)
72
- except:
73
- return None
74
-
75
- post_element = xml_root.find('post')
76
-
77
- parsed = await parse_result(post_element)
78
-
79
- if parsed is None:
80
- return None
81
- else:
82
- main_post, sample_post, preview_post = parsed
83
-
84
- logging.info(f"Post where found in {time.time() - st}s")
85
-
86
- return Rule34PostData(id, main_post, sample_post, preview_post)
87
-
88
- async def get_random_post(self, tags: str = '', forbidden_tags: list[str] = []):
89
- start_time = time.time()
90
-
91
- post_count = await self.get_post_count(tags)
92
-
93
- page_count = post_count // 1000
94
-
95
- if page_count > 0:
96
- post_list = await self.get_post_list(page_id=random.randint(0, page_count if page_count <= 200 else 200),
97
- tags=tags, limit=1000)
98
-
99
- else:
100
- post_list = await self.get_post_list(tags=tags, limit=1000)
101
-
102
- post_list_ = []
103
-
104
- for post in post_list:
105
- if any(tag in forbidden_tags for tag in post.main.tags):
106
- pass
107
- else:
108
- post_list_.append(post)
109
-
110
- logging.info(f"Random post where found in {time.time() - start_time}s")
111
-
112
- return post_list_[random.randint(0, len(post_list_) - 1)] if len(post_list_) > 0 else None
113
-
114
- async def get_random_posts(self, tags: str = '', count: int = 8, forbidden_tags: list[str] = []) -> list[Rule34PostData]:
115
- st = time.time()
116
-
117
- request_count = 1
118
- true_count = count*20
119
-
120
- post_list = []
121
-
122
- if true_count > 1000:
123
- request_count = true_count // 1000
124
-
125
- post_count = await self.get_post_count(tags)
126
- page_id = int(random.randint(0, int(post_count / true_count)) / 8) if post_count >= true_count else 0
127
-
128
- for pid in range(request_count + 1):
129
- post_list += await self.get_post_list(tags=tags, forbidden_tags=forbidden_tags,
130
- page_id=page_id, limit=true_count if true_count <= 1000 else 1000)
131
-
132
- getted = []
133
-
134
- for x in range(count):
135
- if len(post_list) > 0:
136
- getted.append(post_list[random.randint(0, len(post_list) - 1)])
137
- else:
138
- pass
139
-
140
- logging.info(f"{count} random posts where found in {time.time() - st}s")
141
-
142
- return getted
143
-
144
- async def get_post_list(self, limit: int = 1000, page_id: int = 0, tags: str = '', forbidden_tags: list[str] = [])\
145
- -> list[Rule34PostData]:
146
- async with aiohttp.ClientSession(headers=self.header) as session:
147
- if limit > 1000:
148
- raise ToBigRequestException(f"The max size of request is 1000 when you tried to request {limit}")
149
-
150
- start_time = time.time()
151
-
152
- async with session.get(f'https://api.rule34.xxx/index.php?'
153
- f'page=dapi&s=post&q=index&limit={limit}&pid={page_id}&tags={tags}') as response:
154
- xml_data = await response.text()
155
-
156
- logging.debug(f"Request with {limit} limit posts were done in {time.time() - start_time}s")
157
-
158
- xml_root = ET.fromstring(xml_data)
159
- posts = xml_root.findall('post')
160
- post_list = []
161
-
162
- start_time = time.time()
163
-
164
- for post_element in posts:
165
- parsed = await parse_result(post_element)
166
-
167
- if parsed is None:
168
- return []
169
- else:
170
- main_post, sample_post, preview_post = parsed
171
-
172
- post_list.append(Rule34PostData(main_post.id, main_post, sample_post, preview_post))
173
-
174
- logging.debug(f"Creating {len(posts)} objects was done in {time.time() - start_time}s")
175
-
176
- post_list_ = []
177
-
178
- for post in post_list:
179
- if any(tag in forbidden_tags for tag in post.main.tags):
180
- pass
181
- else:
182
- post_list_.append(post)
183
-
184
- logging.info(f"{len(post_list_)} posts where found in {time.time() - start_time}s")
185
-
186
- return post_list_
SimpleRule34/aio/types.py DELETED
@@ -1,98 +0,0 @@
1
- import typing
2
-
3
- import aiofiles
4
- import aiohttp
5
- import os
6
- import datetime
7
-
8
- from .utils import get_file_size, get_file_type
9
-
10
-
11
- class Rule34Post:
12
- def __init__(self, height: int, width: int, url: str, id: int):
13
- self.path = r'./rule34_download'
14
- self.height = height
15
- self.width = width
16
- self.url = url
17
- self.id = id
18
- self.file_type = get_file_type(self.url)
19
-
20
- def __str__(self):
21
- return f"<Rule34Post(id={self.id}, height={self.height}, width={self.width}, url={self.url})>"
22
-
23
- async def get_file_size(self) -> typing.Optional[int]:
24
- async with aiohttp.ClientSession() as session:
25
- file_size = await get_file_size(self.url, session)
26
- return file_size
27
-
28
- async def download(self, path=r'./rule34_download'):
29
- async with aiohttp.ClientSession() as session:
30
- async with session.get(self.url) as response:
31
- if response.status == 200:
32
- try:
33
- os.mkdir(self.path)
34
- except:
35
- pass
36
-
37
- file_name = os.path.basename(self.url)
38
- save_path = os.path.join(path, file_name)
39
- async with aiofiles.open(save_path, 'wb') as file:
40
- await file.write(await response.read())
41
-
42
- return save_path
43
- else:
44
- pass
45
-
46
- async def get_bytes(self):
47
- async with aiohttp.ClientSession() as session:
48
- async with session.get(self.url) as response:
49
- return await response.read()
50
-
51
-
52
- class Rule34MainPost(Rule34Post):
53
- def __init__(self, score: int, rating: str, creator_id: int, tags: str, has_children: bool,
54
- created_date: datetime.datetime, status: str, source: str, has_notes: bool, has_comments: bool,
55
- height: int, width: int, url: str, id: int):
56
- super().__init__(height, width, url, id)
57
- self.score = score
58
- self.rating = rating
59
- self.creator_id = creator_id
60
- self.tags = tags.split(" ")
61
- self.has_children = has_children
62
- self.created_date = created_date
63
- self.status = status
64
- self.source = source
65
- self.has_notes = has_notes
66
- self.has_comments = has_comments
67
-
68
- def __str__(self):
69
- return f"<Rule34MainPost(id={self.id}, height={self.height}, width={self.width}, url={self.url}," \
70
- f" score={self.score}, rating={self.rating}, creator_id={self.creator_id}," \
71
- f" has_children={self.has_children}, has_notes={self.has_notes}, has_comments={self.has_comments}" \
72
- f" created_date={self.created_date}, status={self.status}, tags={self.tags})>"
73
-
74
- def format_tags(self, format: str = "#"):
75
- str_tags = (format + ' ').join(self.tags)
76
- return str_tags.split(" ")
77
-
78
-
79
- class Rule34SamplePost(Rule34Post):
80
- def __str__(self):
81
- return f"<Rule34SamplePost(id={self.id}, height={self.height}, width={self.width}, url={self.url})>"
82
-
83
-
84
- class Rule34PreviewPost(Rule34Post):
85
- def __str__(self):
86
- return f"<Rule34PreviewPost(id={self.id}, height={self.height}, width={self.width}, url={self.url})>"
87
-
88
-
89
- class Rule34PostData:
90
- def __init__(self, id: int, main: Rule34MainPost, sample: Rule34SamplePost, preview: Rule34PreviewPost):
91
- self.id = id
92
- self.main = main
93
- self.sample = sample
94
- self.preview = preview
95
-
96
- def __str__(self):
97
- return f"<Rule34PostData(id={self.id}, main={str(self.main)}, sample={str(self.sample)}," \
98
- f" preview={str(self.preview)})>"
SimpleRule34/aio/utils.py DELETED
@@ -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
-
SimpleRule34/setup.py DELETED
@@ -1,26 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(
4
- name='SimpleRule34',
5
- version='0.1',
6
- description='Simple api wrapper of rule34.xxx for python with asynchronous support',
7
- packages=find_packages(),
8
- install_requires=[
9
- 'aiohttp==3.8.4',
10
- 'aiosignal==1.3.1',
11
- 'async-timeout==4.0.2',
12
- 'attrs==23.1.0',
13
- 'certifi==2023.5.7',
14
- 'charset-normalizer==3.2.0',
15
- 'docopt==0.6.2',
16
- 'frozenlist==1.4.0',
17
- 'idna==3.4',
18
- 'multidict==6.0.4',
19
- 'pipreqs==0.4.13',
20
- 'requests==2.31.0',
21
- 'urllib3==2.0.3',
22
- 'yarg==0.1.9',
23
- 'yarl==1.9.2',
24
- ],
25
- url='https://github.com/Loshok229/rule34-simple-api'
26
- )
@@ -1,56 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: simple_rule34
3
- Version: 0.1.5.5
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
-
55
- # rule34-simple-api
56
- Simple api wrapper of rule34.xxx for python with asynchronous support
@@ -1,14 +0,0 @@
1
- SimpleRule34/Rule34.py,sha256=3eMo_5a20g8eQVlSwm3EBJVZVlxdiB354EejMRWnqMs,7136
2
- SimpleRule34/__init__.py,sha256=C4IbcJ_rjqBhpENXImVGuEQxf81GUwNaycqNNAY_ROc,31
3
- SimpleRule34/exceptions.py,sha256=8MbvBbdb254UaYWfPg3xo_GbSDO6L9iI0d2AFaet9AM,354
4
- SimpleRule34/setup.py,sha256=7hNDTD52EAs7W00-Nd5LzvH8H4-Dvc59W8a999LqvW4,735
5
- SimpleRule34/types.py,sha256=PpIHfMlFfRvXAZ_0Seaj9HJH6f_9JpJHCELIoSbeyuo,3278
6
- SimpleRule34/utils.py,sha256=lVbM6w2z9QwdOhVpff4q73_DfPLxDEXPVlxI2M6aK6I,854
7
- SimpleRule34/aio/ARule34.py,sha256=nZwxmMNo_g_a16U9dJmxFGUIkDtgNB-W0uFH8LJ8tSI,6858
8
- SimpleRule34/aio/types.py,sha256=919XQt5ydRoLeVxy5HRujc0IeKYlD3crYuH_qvPqdKY,3719
9
- SimpleRule34/aio/utils.py,sha256=fWx-ntJ672NoktH5Ws9-FcO0gtCNVmd8VfxFxjWqsD0,616
10
- simple_rule34-0.1.5.5.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
11
- simple_rule34-0.1.5.5.dist-info/METADATA,sha256=vYXD5uJjBsLn5W8gGxZvZH3537_TEM2RsTmO5dERrrU,2123
12
- simple_rule34-0.1.5.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
13
- simple_rule34-0.1.5.5.dist-info/top_level.txt,sha256=IrrcPxvAx-V0ikmhRaLYkjYt-hZ9SRGTcUdtAcbMzGE,13
14
- simple_rule34-0.1.5.5.dist-info/RECORD,,