34
34
import sys
35
35
from dataclasses import dataclass
36
36
from pathlib import Path
37
- from typing import List , Tuple
37
+ from typing import List , Tuple , Union
38
38
from urllib .parse import ParseResult , urljoin , urlparse
39
39
from urllib .request import getproxies
40
40
@@ -89,9 +89,13 @@ def get_logfile_path() -> Path:
89
89
90
90
@dataclass (frozen = True )
91
91
class ParseResponse :
92
+ """
93
+ Data class that is primarily used as a structured return type for the upload,
94
+ preview and download methods.
95
+ """
92
96
response : Response
93
97
file_path : Path
94
- ddl : str
98
+ ddl : ParseResult
95
99
96
100
@property
97
101
def json (self ) -> dict :
@@ -103,7 +107,7 @@ def json(self) -> dict:
103
107
@property
104
108
def status (self ) -> bool :
105
109
"""
106
- Return the upload status. If `false `, an error message indicating the
110
+ Return the upload status. If `False `, an error message indicating the
107
111
cause for the malfunction will be redirected to `sys.stderr`.
108
112
"""
109
113
status = bool (self .json ['status' ])
@@ -146,32 +150,61 @@ def size(self) -> int:
146
150
"""
147
151
return int (self .json ['data' ]['file' ]['metadata' ]['size' ]['bytes' ])
148
152
153
+ def __str__ (self ) -> str :
154
+ return str (self .name )
155
+
156
+ def __repr__ (self ) -> str :
157
+ return f"{ self .__class__ .__name__ } (ID={ self .id } )"
158
+
149
159
#endregion
150
160
151
161
class AnonFile :
162
+ """
163
+ The unofficial Python API for https://anonfiles.com.
164
+
165
+ Basic Usage
166
+ -----------
167
+
168
+ ```
169
+ from anonfile import AnonFile
170
+
171
+ anon = AnonFile()
172
+ preview = anon.preview('https://anonfiles.com/b7NaVd0cu3/topsecret_mkv')
173
+
174
+ # topsecret.mkv
175
+ print(preview)
176
+ ```
177
+
178
+ Docs
179
+ ----
180
+ See full documentation at <https://www.hentai-chan.dev/projects/anonfile>.
181
+ """
152
182
_timeout = (5 , 5 )
153
183
_total = 5
154
184
_status_forcelist = [413 , 429 , 500 , 502 , 503 , 504 ]
155
185
_backoff_factor = 1
156
186
_user_agent = None
187
+ _proxies = None
157
188
158
189
API = "https://api.anonfiles.com/"
159
190
160
- __slots__ = ['endpoint' , 'token' , 'timeout' , 'total' , 'status_forcelist' , 'backoff_factor' , 'user_agent' ]
191
+ __slots__ = ['endpoint' , 'token' , 'timeout' , 'total' , 'status_forcelist' , 'backoff_factor' , 'user_agent' , 'proxies' ]
161
192
162
193
def __init__ (self ,
163
194
token : str = "undefined" ,
164
195
timeout : Tuple [float ,float ]= _timeout ,
165
196
total : int = _total ,
166
197
status_forcelist : List [int ]= _status_forcelist ,
167
198
backoff_factor : int = _backoff_factor ,
168
- user_agent : str = _user_agent ) -> AnonFile :
199
+ user_agent : str = _user_agent ,
200
+ proxies : dict = _proxies ) -> AnonFile :
169
201
self .token = token
170
202
self .timeout = timeout
171
203
self .total = total ,
172
204
self .status_forcelist = status_forcelist ,
173
205
self .backoff_factor = backoff_factor
174
206
self .user_agent = user_agent
207
+ self .proxies = proxies
175
208
176
209
@staticmethod
177
210
def __progressbar_options (iterable , desc , unit , color : str = "\033 [32m" , char = '\u25CB ' , total = None , disable = False ) -> dict :
@@ -219,7 +252,7 @@ def __get(self, url: str, **kwargs) -> Response:
219
252
Returns the GET request encoded in `utf-8`. Adds proxies to this session
220
253
on the fly if urllib is able to pick up the system's proxy settings.
221
254
"""
222
- response = self .session .get (url , timeout = self .timeout , proxies = getproxies (), ** kwargs )
255
+ response = self .session .get (url , timeout = self .timeout , proxies = self . proxies or getproxies (), ** kwargs )
223
256
response .encoding = 'utf-8'
224
257
return response
225
258
@@ -231,7 +264,7 @@ def __callback(monitor: MultipartEncoderMonitor, tqdm_handler: tqdm):
231
264
tqdm_handler .total = monitor .len
232
265
tqdm_handler .update (monitor .bytes_read - tqdm_handler .n )
233
266
234
- def upload (self , path : str , progressbar : bool = False , enable_logging : bool = False ) -> ParseResponse :
267
+ def upload (self , path : Union [ str , Path ] , progressbar : bool = False , enable_logging : bool = False ) -> ParseResponse :
235
268
"""
236
269
Upload a file located in `path` to http://anonfiles.com. Set
237
270
`enable_logging` to `True` to store the URL in a global config file.
@@ -252,13 +285,14 @@ def upload(self, path: str, progressbar: bool=False, enable_logging: bool=False)
252
285
Note
253
286
----
254
287
Although `anonfile` offers unlimited bandwidth, uploads cannot exceed a
255
- file size of 20GB in theory. Due to technical difficulties in the implementation
288
+ file size of 20GB in theory. Due to technical difficulties in the implementation,
256
289
the upper cap occurs much earlier at around 500MB.
257
290
"""
291
+ path = Path (path )
258
292
size = os .stat (path ).st_size
259
- options = AnonFile .__progressbar_options (None , f"Upload: { Path ( path ) .name } " , unit = 'B' , total = size , disable = progressbar )
293
+ options = AnonFile .__progressbar_options (None , f"Upload: { path .name } " , unit = 'B' , total = size , disable = progressbar )
260
294
with open (path , mode = 'rb' ) as file_handler :
261
- fields = {'file' : (Path ( path ) .name , file_handler , 'application/octet-stream' )}
295
+ fields = {'file' : (path .name , file_handler , 'application/octet-stream' )}
262
296
with tqdm (** options ) as tqdm_handler :
263
297
encoder_monitor = MultipartEncoderMonitor .from_fields (fields , callback = lambda monitor : AnonFile .__callback (monitor , tqdm_handler ))
264
298
response = self .session .post (
@@ -271,9 +305,9 @@ def upload(self, path: str, progressbar: bool=False, enable_logging: bool=False)
271
305
verify = True
272
306
)
273
307
logger .log (logging .INFO if enable_logging else logging .NOTSET , "upload::%s" , response .json ()['data' ]['file' ]['url' ]['full' ])
274
- return ParseResponse (response , Path ( path ) , None )
308
+ return ParseResponse (response , path , None )
275
309
276
- def preview (self , url : str , path : Path = Path .cwd ()) -> ParseResponse :
310
+ def preview (self , url : str , path : Union [ str , Path ] = Path .cwd ()) -> ParseResponse :
277
311
"""
278
312
Obtain meta data associated with this `url` without commiting to a time-
279
313
consuming download.
@@ -293,11 +327,11 @@ def preview(self, url: str, path: Path=Path.cwd()) -> ParseResponse:
293
327
"""
294
328
with self .__get (urljoin (AnonFile .API , f"v2/file/{ urlparse (url ).path .split ('/' )[1 ]} /info" )) as response :
295
329
links = re .findall (r'''.*?href=['"](.*?)['"].*?''' , html .unescape (self .__get (url ).text ), re .I )
296
- ddl = next (filter (lambda link : 'cdn-' in link , links ))
297
- file_path = path .joinpath (Path (urlparse ( ddl ) .path ).name )
330
+ ddl = urlparse ( next (filter (lambda link : 'cdn-' in link , links ) ))
331
+ file_path = Path ( path ) .joinpath (Path (ddl .path ).name )
298
332
return ParseResponse (response , file_path , ddl )
299
333
300
- def download (self , url : str , path : Path = Path .cwd (), progressbar : bool = False , enable_logging : bool = False ) -> ParseResponse :
334
+ def download (self , url : str , path : Union [ str , Path ] = Path .cwd (), progressbar : bool = False , enable_logging : bool = False ) -> ParseResponse :
301
335
"""
302
336
Download a file from https://anonfiles.com given a `url`. Set the download
303
337
directory in `path` (uses the current working directory by default). Set
@@ -328,7 +362,7 @@ def download(self, url: str, path: Path=Path.cwd(), progressbar: bool=False, ena
328
362
options = AnonFile .__progressbar_options (None , f"Download { download .id } " , unit = 'B' , total = download .size , disable = progressbar )
329
363
with open (download .file_path , mode = 'wb' ) as file_handler :
330
364
with tqdm (** options ) as tqdm_handler :
331
- with self .__get (download .ddl , stream = True ) as response :
365
+ with self .__get (download .ddl . geturl () , stream = True ) as response :
332
366
for chunk in response .iter_content (1024 * 1024 ):
333
367
tqdm_handler .update (len (chunk ))
334
368
file_handler .write (chunk )
0 commit comments