reykit 1.1.3__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.
- reykit-1.1.3/.gitignore +2 -0
- reykit-1.1.3/LICENSE +7 -0
- reykit-1.1.3/PKG-INFO +44 -0
- reykit-1.1.3/README.md +9 -0
- reykit-1.1.3/pyproject.toml +37 -0
- reykit-1.1.3/src/reykit/__init__.py +35 -0
- reykit-1.1.3/src/reykit/rall.py +33 -0
- reykit-1.1.3/src/reykit/rcomm.py +431 -0
- reykit-1.1.3/src/reykit/rdata.py +395 -0
- reykit-1.1.3/src/reykit/rdll/__init__.py +17 -0
- reykit-1.1.3/src/reykit/rdll/rdll_inject.py +41 -0
- reykit-1.1.3/src/reykit/rdll/rdll_inject_core.py +202 -0
- reykit-1.1.3/src/reykit/remail.py +274 -0
- reykit-1.1.3/src/reykit/rexception.py +339 -0
- reykit-1.1.3/src/reykit/rimage.py +261 -0
- reykit-1.1.3/src/reykit/rlog.py +1061 -0
- reykit-1.1.3/src/reykit/rmonkey.py +340 -0
- reykit-1.1.3/src/reykit/rmultitask.py +870 -0
- reykit-1.1.3/src/reykit/rnumber.py +161 -0
- reykit-1.1.3/src/reykit/ros.py +1917 -0
- reykit-1.1.3/src/reykit/rrandom.py +382 -0
- reykit-1.1.3/src/reykit/rregex.py +290 -0
- reykit-1.1.3/src/reykit/rschedule.py +272 -0
- reykit-1.1.3/src/reykit/rstdout.py +356 -0
- reykit-1.1.3/src/reykit/rsystem.py +1384 -0
- reykit-1.1.3/src/reykit/rtable.py +511 -0
- reykit-1.1.3/src/reykit/rtext.py +458 -0
- reykit-1.1.3/src/reykit/rtime.py +665 -0
- reykit-1.1.3/src/reykit/rtype.py +106 -0
- reykit-1.1.3/src/reykit/rwrap.py +613 -0
- reykit-1.1.3/src/reykit/rzip.py +136 -0
reykit-1.1.3/.gitignore
ADDED
reykit-1.1.3/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright 2025 ReyXBo
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
reykit-1.1.3/PKG-INFO
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: reykit
|
3
|
+
Version: 1.1.3
|
4
|
+
Summary: Rey's kit method set.
|
5
|
+
Project-URL: homepage, https://github.com/reyxbo/reykit/
|
6
|
+
Author-email: Rey <reyxbo@163.com>
|
7
|
+
License: Copyright 2025 ReyXBo
|
8
|
+
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
14
|
+
License-File: LICENSE
|
15
|
+
Keywords: kit,rey,reyxbo,tool,tools
|
16
|
+
Requires-Python: >=3.12
|
17
|
+
Requires-Dist: aiohttp
|
18
|
+
Requires-Dist: apscheduler
|
19
|
+
Requires-Dist: captcha
|
20
|
+
Requires-Dist: concurrent-log-handler
|
21
|
+
Requires-Dist: filetype
|
22
|
+
Requires-Dist: pandas
|
23
|
+
Requires-Dist: pdfplumber
|
24
|
+
Requires-Dist: pillow
|
25
|
+
Requires-Dist: psutil
|
26
|
+
Requires-Dist: pymem
|
27
|
+
Requires-Dist: python-docx
|
28
|
+
Requires-Dist: pyzbar
|
29
|
+
Requires-Dist: qrcode
|
30
|
+
Requires-Dist: requests
|
31
|
+
Requires-Dist: tqdm
|
32
|
+
Requires-Dist: urwid
|
33
|
+
Requires-Dist: varname
|
34
|
+
Description-Content-Type: text/markdown
|
35
|
+
|
36
|
+
# reykit
|
37
|
+
|
38
|
+
> Rey's kit method set.
|
39
|
+
|
40
|
+
## Install
|
41
|
+
|
42
|
+
```
|
43
|
+
pip install reykit
|
44
|
+
```
|
reykit-1.1.3/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
[project]
|
2
|
+
name = "reykit"
|
3
|
+
version = "1.1.3"
|
4
|
+
description = "Rey's kit method set."
|
5
|
+
readme = "README.md"
|
6
|
+
requires-python = ">=3.12"
|
7
|
+
license = {file = "LICENSE"}
|
8
|
+
keywords = ["rey", "reyxbo", "kit", "tool", "tools"]
|
9
|
+
authors = [
|
10
|
+
{name = "Rey", email = "reyxbo@163.com"}
|
11
|
+
]
|
12
|
+
dependencies = [
|
13
|
+
"aiohttp",
|
14
|
+
"apscheduler",
|
15
|
+
"captcha",
|
16
|
+
"concurrent-log-handler",
|
17
|
+
"filetype",
|
18
|
+
"pandas",
|
19
|
+
"pyzbar",
|
20
|
+
"pdfplumber",
|
21
|
+
"psutil",
|
22
|
+
"pymem",
|
23
|
+
"python-docx",
|
24
|
+
"qrcode",
|
25
|
+
"requests",
|
26
|
+
"tqdm",
|
27
|
+
"urwid",
|
28
|
+
"varname",
|
29
|
+
"Pillow"
|
30
|
+
]
|
31
|
+
|
32
|
+
[project.urls]
|
33
|
+
homepage = "https://github.com/reyxbo/reykit/"
|
34
|
+
|
35
|
+
[build-system]
|
36
|
+
requires = ["hatchling"]
|
37
|
+
build-backend = "hatchling.build"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2022-12-05 14:09:21
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : Rey's kit method set.
|
9
|
+
|
10
|
+
Modules
|
11
|
+
-------
|
12
|
+
rall : All methods.
|
13
|
+
rcomm : Network communication methods.
|
14
|
+
rdata : Data methods.
|
15
|
+
rdll : DLL file methods.
|
16
|
+
remail : E-mail methods.
|
17
|
+
rexception : Exception methods.
|
18
|
+
rimage : Image methods.
|
19
|
+
rlog : Log methods.
|
20
|
+
rmonkey : Monkey patch methods.
|
21
|
+
rmultitask : Multi task methods.
|
22
|
+
rnumber : Number methods.
|
23
|
+
ros: Operation system methods.
|
24
|
+
rrandom : Random methods.
|
25
|
+
rregex : Regular expression methods.
|
26
|
+
rschedule : Schedule methods.
|
27
|
+
rstdout : Standard output methods.
|
28
|
+
rsystem : Interpreter system methods.
|
29
|
+
rtable : Table methods.
|
30
|
+
rtext : Text methods.
|
31
|
+
rtime : Time methods.
|
32
|
+
rtype : Type methods.
|
33
|
+
rwrap : Decorators.
|
34
|
+
rzip : File compress methods.
|
35
|
+
"""
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2022-12-08 13:11:09
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : All methods.
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
from .rcomm import *
|
13
|
+
from .rdata import *
|
14
|
+
from .rdll import *
|
15
|
+
from .remail import *
|
16
|
+
from .rexception import *
|
17
|
+
from .rimage import *
|
18
|
+
from .rlog import *
|
19
|
+
from .rmonkey import *
|
20
|
+
from .rmultitask import *
|
21
|
+
from .rnumber import *
|
22
|
+
from .ros import *
|
23
|
+
from .rrandom import *
|
24
|
+
from .rregex import *
|
25
|
+
from .rschedule import *
|
26
|
+
from .rstdout import *
|
27
|
+
from .rsystem import *
|
28
|
+
from .rtable import *
|
29
|
+
from .rtext import *
|
30
|
+
from .rtime import *
|
31
|
+
from .rtype import *
|
32
|
+
from .rwrap import *
|
33
|
+
from .rzip import *
|
@@ -0,0 +1,431 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2022-12-08 11:07:25
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : Network communication methods.
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
from typing import Any, Literal
|
13
|
+
from collections.abc import Callable, Iterable
|
14
|
+
from warnings import filterwarnings
|
15
|
+
from os.path import abspath as os_abspath, isfile as os_isfile
|
16
|
+
from socket import socket as Socket
|
17
|
+
from urllib.parse import urlsplit as urllib_urlsplit, quote as urllib_quote, unquote as urllib_unquote
|
18
|
+
from requests.api import request as requests_request
|
19
|
+
from requests.models import Response
|
20
|
+
from mimetypes import guess_type
|
21
|
+
from filetype import guess as filetype_guess
|
22
|
+
|
23
|
+
from .rexception import throw, check_response_code
|
24
|
+
from .ros import RFile
|
25
|
+
from .rregex import search
|
26
|
+
|
27
|
+
|
28
|
+
__all__ = (
|
29
|
+
'join_url',
|
30
|
+
'split_url',
|
31
|
+
'join_cookie',
|
32
|
+
'split_cookie',
|
33
|
+
'get_content_type',
|
34
|
+
'request',
|
35
|
+
'download',
|
36
|
+
'get_file_stream_time',
|
37
|
+
'listen_socket'
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
def join_url(url: str, params: dict) -> str:
|
42
|
+
"""
|
43
|
+
Join URL and parameters.
|
44
|
+
|
45
|
+
Parameters
|
46
|
+
----------
|
47
|
+
url : URL.
|
48
|
+
params : Parameters of URL.
|
49
|
+
|
50
|
+
Returns
|
51
|
+
-------
|
52
|
+
Joined URL.
|
53
|
+
"""
|
54
|
+
|
55
|
+
# Join parameter.
|
56
|
+
params_str = '&'.join(
|
57
|
+
[
|
58
|
+
f'{key}={urllib_quote(value)}'
|
59
|
+
for key, value in params.items()
|
60
|
+
]
|
61
|
+
)
|
62
|
+
|
63
|
+
# Join URL.
|
64
|
+
if '?' not in url:
|
65
|
+
url += '?'
|
66
|
+
elif url[-1] != '?':
|
67
|
+
url += '&'
|
68
|
+
url += params_str
|
69
|
+
|
70
|
+
return url
|
71
|
+
|
72
|
+
|
73
|
+
def split_url(url: str) -> tuple[str, dict[str, str]]:
|
74
|
+
"""
|
75
|
+
Split URL and parameters.
|
76
|
+
|
77
|
+
Parameters
|
78
|
+
----------
|
79
|
+
url : URL.
|
80
|
+
|
81
|
+
Returns
|
82
|
+
-------
|
83
|
+
Split URL and parameters.
|
84
|
+
"""
|
85
|
+
|
86
|
+
# Split URL.
|
87
|
+
split_result = urllib_urlsplit(url)
|
88
|
+
params_str = split_result.query
|
89
|
+
url = split_result.scheme + '://' + split_result.netloc + split_result.path
|
90
|
+
|
91
|
+
# Split parameter.
|
92
|
+
params = {
|
93
|
+
key: urllib_unquote(value)
|
94
|
+
for key, value in map(
|
95
|
+
lambda item: item.split('=', 1),
|
96
|
+
params_str.split('&')
|
97
|
+
)
|
98
|
+
}
|
99
|
+
|
100
|
+
return url, params
|
101
|
+
|
102
|
+
|
103
|
+
def join_cookie(params: dict[str, str]) -> str:
|
104
|
+
"""
|
105
|
+
Join parameters of Cookie.
|
106
|
+
|
107
|
+
Parameters
|
108
|
+
----------
|
109
|
+
params : Parameters.
|
110
|
+
|
111
|
+
Returns
|
112
|
+
-------
|
113
|
+
Joined cookie.
|
114
|
+
"""
|
115
|
+
|
116
|
+
# Join.
|
117
|
+
cookie = '; '.join(
|
118
|
+
[
|
119
|
+
f'{key}={value}'
|
120
|
+
for key, value in params.items()
|
121
|
+
]
|
122
|
+
)
|
123
|
+
|
124
|
+
return cookie
|
125
|
+
|
126
|
+
|
127
|
+
def split_cookie(cookie: str) -> dict[str, str]:
|
128
|
+
"""
|
129
|
+
Split parameters of Cookie.
|
130
|
+
|
131
|
+
Parameters
|
132
|
+
----------
|
133
|
+
cookie : Cookie.
|
134
|
+
|
135
|
+
Returns
|
136
|
+
-------
|
137
|
+
Split parameters
|
138
|
+
"""
|
139
|
+
|
140
|
+
# Split parameter.
|
141
|
+
params = {
|
142
|
+
key: value
|
143
|
+
for key, value in map(
|
144
|
+
lambda item: item.split('=', 1),
|
145
|
+
cookie.split('; ')
|
146
|
+
)
|
147
|
+
}
|
148
|
+
|
149
|
+
return params
|
150
|
+
|
151
|
+
|
152
|
+
def get_content_type(file: str | bytes) -> str | None:
|
153
|
+
"""
|
154
|
+
Get HTTP content type of file.
|
155
|
+
|
156
|
+
Parameters
|
157
|
+
----------
|
158
|
+
file : File path or bytes data.
|
159
|
+
|
160
|
+
Returns
|
161
|
+
-------
|
162
|
+
HTTP content type.
|
163
|
+
"""
|
164
|
+
|
165
|
+
# Guess.
|
166
|
+
if (
|
167
|
+
(
|
168
|
+
file.__class__ == str
|
169
|
+
and os_isfile(file)
|
170
|
+
) or file.__class__ == bytes
|
171
|
+
):
|
172
|
+
file_type_obj = filetype_guess(file)
|
173
|
+
else:
|
174
|
+
file_type_obj = None
|
175
|
+
if file_type_obj is not None:
|
176
|
+
file_type = file_type_obj.MIME
|
177
|
+
elif file.__class__ == str:
|
178
|
+
file_type, _ = guess_type(file)
|
179
|
+
else:
|
180
|
+
file_type = None
|
181
|
+
|
182
|
+
return file_type
|
183
|
+
|
184
|
+
|
185
|
+
def request(
|
186
|
+
url: str,
|
187
|
+
params: dict | None = None,
|
188
|
+
data: dict | str | bytes | None = None,
|
189
|
+
json: dict | None = None,
|
190
|
+
files: dict[str, str | bytes | tuple[str | bytes, dict]] | None = None,
|
191
|
+
headers: dict[str, str] = {},
|
192
|
+
timeout: float | None = None,
|
193
|
+
proxies: dict[str, str] = {},
|
194
|
+
stream: bool = False,
|
195
|
+
verify: bool = False,
|
196
|
+
method: Literal['get', 'post', 'put', 'patch', 'delete', 'options', 'head'] | None = None,
|
197
|
+
check: bool | int | Iterable[int] = False
|
198
|
+
) -> Response:
|
199
|
+
"""
|
200
|
+
Send request.
|
201
|
+
|
202
|
+
Parameters
|
203
|
+
----------
|
204
|
+
url : Request URL.
|
205
|
+
params : Request URL add parameters.
|
206
|
+
data : Request body data.
|
207
|
+
- `dict`, Convert to `key=value&...`: format bytes.
|
208
|
+
Automatic set `Content-Type` to `application/x-www-form-urlencoded`.
|
209
|
+
- `str`: File path to read file bytes data.
|
210
|
+
Automatic set `Content-Type` to file media type, and `filename` to file name.
|
211
|
+
- `bytes`: File bytes data.
|
212
|
+
Automatic set `Content-Type` to file media type.
|
213
|
+
json : Request body data, convert to `JSON` format.
|
214
|
+
Automatic set `Content-Type` to `application/json`.
|
215
|
+
files : Request body data, convert to `multi form` format.
|
216
|
+
Automatic set `Content-Type` to `multipart/form-data`.
|
217
|
+
- `dict[str, str]`: Parameter name and File path to read file bytes data.
|
218
|
+
Automatic set `Content-Type` to file media type, and `filename` to file name.
|
219
|
+
- `dict[str, bytes]`: Parameter name and file bytes data.
|
220
|
+
- `dict[str, tuple[str, dict]`: Parameter name and File path to read file bytes data and other parameters.
|
221
|
+
Automatic set `Content-Type` to file media type, and `filename` to file name.
|
222
|
+
- `dict[str, tuple[bytes, dict]`: Parameter name and file bytes data and other parameters.
|
223
|
+
headers : Request header data.
|
224
|
+
timeout : Request maximun waiting time.
|
225
|
+
proxies : Proxy IP setup.
|
226
|
+
- `None`: No setup.
|
227
|
+
- `dict[str, str]`: Name and use IP of each protocol.
|
228
|
+
stream : Whether use stream request.
|
229
|
+
verify : Whether verify certificate.
|
230
|
+
method : Request method.
|
231
|
+
- `None`: Automatic judge.
|
232
|
+
When parameter `data` or `json` or `files` not has value, then request method is `get`.
|
233
|
+
When parameter `data` or `json` or `files` has value, then request method is `post`.
|
234
|
+
- `Literal['get', 'post', 'put', 'patch', 'delete', 'options', 'head']`: Use this request method.
|
235
|
+
check : Check response code, and throw exception.
|
236
|
+
- `Literal[False]`: Not check.
|
237
|
+
- `Literal[True]`: Check if is between 200 and 299.
|
238
|
+
- `int`: Check if is this value.
|
239
|
+
- `Iterable`: Check if is in sequence.
|
240
|
+
|
241
|
+
Returns
|
242
|
+
-------
|
243
|
+
Response object of requests package.
|
244
|
+
"""
|
245
|
+
|
246
|
+
# Handle parameter.
|
247
|
+
if method is None:
|
248
|
+
if data is None and json is None and files is None:
|
249
|
+
method = 'get'
|
250
|
+
else:
|
251
|
+
method = 'post'
|
252
|
+
if files is None:
|
253
|
+
if data.__class__ == str:
|
254
|
+
rfile = RFile(data)
|
255
|
+
data = rfile.bytes
|
256
|
+
if 'Content-Disposition' not in headers:
|
257
|
+
file_name = rfile.name_suffix
|
258
|
+
headers['Content-Disposition'] = f'attachment; filename={file_name}'
|
259
|
+
if data.__class__ == bytes:
|
260
|
+
if 'Content-Type' not in headers:
|
261
|
+
headers['Content-Type'] = get_content_type(data)
|
262
|
+
else:
|
263
|
+
for key, value in files.items():
|
264
|
+
if value.__class__ == tuple:
|
265
|
+
item_data, item_headers = value
|
266
|
+
else:
|
267
|
+
item_data, item_headers = value, {}
|
268
|
+
if item_data.__class__ == str:
|
269
|
+
rfile = RFile(item_data)
|
270
|
+
data = rfile.bytes
|
271
|
+
item_headers.setdefault('filename', rfile.name_suffix)
|
272
|
+
if item_data.__class__ == bytes:
|
273
|
+
if 'Content-Type' not in item_headers:
|
274
|
+
item_headers['Content-Type'] = get_content_type(item_data)
|
275
|
+
files[key] = (
|
276
|
+
item_headers.get('filename', key),
|
277
|
+
item_data,
|
278
|
+
item_headers.get('Content-Type'),
|
279
|
+
item_headers
|
280
|
+
)
|
281
|
+
if not verify:
|
282
|
+
filterwarnings(
|
283
|
+
'ignore',
|
284
|
+
'Unverified HTTPS request is being made to host'
|
285
|
+
)
|
286
|
+
|
287
|
+
# Request.
|
288
|
+
response = requests_request(
|
289
|
+
method,
|
290
|
+
url,
|
291
|
+
params=params,
|
292
|
+
data=data,
|
293
|
+
json=json,
|
294
|
+
files=files,
|
295
|
+
headers=headers,
|
296
|
+
timeout=timeout,
|
297
|
+
proxies=proxies,
|
298
|
+
verify=verify,
|
299
|
+
stream=stream
|
300
|
+
)
|
301
|
+
|
302
|
+
# Set encod type.
|
303
|
+
if response.encoding == 'ISO-8859-1':
|
304
|
+
pattern = r'<meta [^>]*charset=([\w-]+)[^>]*>'
|
305
|
+
charset = search(pattern, response.text)
|
306
|
+
if charset is None:
|
307
|
+
charset = 'utf-8'
|
308
|
+
response.encoding = charset
|
309
|
+
|
310
|
+
# Check code.
|
311
|
+
if check is not False:
|
312
|
+
if check is True:
|
313
|
+
range_ = None
|
314
|
+
else:
|
315
|
+
range_ = check
|
316
|
+
check_response_code(response.status_code, range_)
|
317
|
+
|
318
|
+
return response
|
319
|
+
|
320
|
+
|
321
|
+
def download(url: str, path: str | None = None) -> str:
|
322
|
+
"""
|
323
|
+
Download file from URL.
|
324
|
+
|
325
|
+
Parameters
|
326
|
+
----------
|
327
|
+
url : Download URL.
|
328
|
+
path : Save path.
|
329
|
+
- `None`, File name is `download`: and automatic judge file type.
|
330
|
+
|
331
|
+
Returns
|
332
|
+
-------
|
333
|
+
File absolute path.
|
334
|
+
"""
|
335
|
+
|
336
|
+
# Download.
|
337
|
+
response = request(url)
|
338
|
+
content = response.content
|
339
|
+
|
340
|
+
# Judge file type and path.
|
341
|
+
if path is None:
|
342
|
+
Content_disposition = response.headers.get('Content-Disposition', '')
|
343
|
+
if 'filename' in Content_disposition:
|
344
|
+
file_name = search(
|
345
|
+
'filename=[\'"]?([^\\s\'"]+)',
|
346
|
+
Content_disposition
|
347
|
+
)
|
348
|
+
else:
|
349
|
+
file_name = None
|
350
|
+
if file_name is None:
|
351
|
+
file_type_obj = get_content_type(content)
|
352
|
+
if file_type_obj is not None:
|
353
|
+
file_name = 'download.' + file_type_obj.EXTENSION
|
354
|
+
if file_name is None:
|
355
|
+
file_name = 'download'
|
356
|
+
path = os_abspath(file_name)
|
357
|
+
|
358
|
+
# Save.
|
359
|
+
rfile = RFile(path)
|
360
|
+
rfile(content)
|
361
|
+
|
362
|
+
return path
|
363
|
+
|
364
|
+
|
365
|
+
def get_file_stream_time(
|
366
|
+
file: str | bytes | int,
|
367
|
+
bandwidth: float
|
368
|
+
) -> float:
|
369
|
+
"""
|
370
|
+
Get file stream transfer time, unit second.
|
371
|
+
|
372
|
+
Parameters
|
373
|
+
----------
|
374
|
+
file : File data.
|
375
|
+
- `str`: File path.
|
376
|
+
- `bytes`: File bytes data.
|
377
|
+
- `int`: File bytes size.
|
378
|
+
bandwidth : Bandwidth, unit Mpbs.
|
379
|
+
|
380
|
+
Returns
|
381
|
+
-------
|
382
|
+
File send seconds.
|
383
|
+
"""
|
384
|
+
|
385
|
+
# Get parameter.
|
386
|
+
match file:
|
387
|
+
case str():
|
388
|
+
rfile = RFile(file)
|
389
|
+
file_size = rfile.size
|
390
|
+
case bytes() | bytearray():
|
391
|
+
file_size = len(file)
|
392
|
+
case int():
|
393
|
+
file_size = file
|
394
|
+
case _:
|
395
|
+
throw(TypeError, file)
|
396
|
+
|
397
|
+
# Calculate.
|
398
|
+
seconds = file_size / 125_000 / bandwidth
|
399
|
+
|
400
|
+
return seconds
|
401
|
+
|
402
|
+
|
403
|
+
def listen_socket(
|
404
|
+
host: str,
|
405
|
+
port: str | int,
|
406
|
+
handler: Callable[[bytes], Any]
|
407
|
+
) -> None:
|
408
|
+
"""
|
409
|
+
Listen socket and handle data.
|
410
|
+
|
411
|
+
Parameters
|
412
|
+
----------
|
413
|
+
host : Socket host.
|
414
|
+
port : Socket port.
|
415
|
+
handler : Handler function.
|
416
|
+
"""
|
417
|
+
|
418
|
+
# Handle parameter.
|
419
|
+
port = int(port)
|
420
|
+
rece_size = 1024 * 1024 * 1024
|
421
|
+
|
422
|
+
# Instance.
|
423
|
+
socket = Socket()
|
424
|
+
socket.bind((host, port))
|
425
|
+
socket.listen()
|
426
|
+
|
427
|
+
# Loop.
|
428
|
+
while True:
|
429
|
+
socket_conn, _ = socket.accept()
|
430
|
+
data = socket_conn.recv(rece_size)
|
431
|
+
handler(data)
|