1919
2020logger = logging .getLogger ("bunkr-uploader" )
2121
22+ DEFAULT_HEADERS = {
23+ "Accept" : "application/json, text/plain, */*" ,
24+ "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0" ,
25+ "Referer" : "https://dash.bunkr.cr/" ,
26+ "striptags" : "null" ,
27+ "Origin" : "https://dash.bunkr.cr" ,
28+ "Sec-Fetch-Dest" : "empty" ,
29+ "Sec-Fetch-Mode" : "cors" ,
30+ "Sec-Fetch-Site" : "cross-site" ,
31+ "Pragma" : "no-cache" ,
32+ }
33+
2234
2335class BunkrrAPI :
2436 RATE_LIMIT = 50
2537
2638 def __init__ (self , token : str , chunk_size : int | None = None ):
2739 self ._token = token
2840 self ._api_entrypoint = URL ("https://dash.bunkr.cr/api/" )
29- self ._session_headers = {
30- "Accept" : "application/json" ,
31- "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0" ,
32- "token" : self ._token ,
33- }
41+ self ._session_headers = DEFAULT_HEADERS | {"token" : self ._token }
3442 self ._session = ClientSession (self ._api_entrypoint , headers = self ._session_headers )
35- self ._chunk_size : int = chunk_size # type: ignore
43+ self ._chunk_size : int = chunk_size or 0
3644 self ._info = None
3745 self ._semaphore = asyncio .Semaphore (self .RATE_LIMIT )
3846 self ._server_sessions : dict [URL , ClientSession ] = {}
@@ -50,15 +58,22 @@ async def _get_json(self, path: str) -> dict:
5058 resp .raise_for_status ()
5159 response : dict = await resp .json ()
5260 record = {"url" : str (resp .url ), "headers" : dict (resp .headers ), "response" : response }
53- logger .debug (f"response: \n { json .dumps (record , indent = 4 )} " )
61+ logger .debug (f"response: \n { json .dumps (record , indent = 4 , ensure_ascii = False )} " )
5462 return response
5563
5664 async def _post (self , path : str , * , data : FormData | dict | None = None , server : URL | None = None ) -> dict :
5765 data = data or {}
5866 if isinstance (data , dict ) and "finishchunks" not in path :
5967 data ["token" ] = data .get ("token" ) or self ._token
60- session = self .server_sessions .get (server ) or self ._session # type: ignore
61- async with self ._semaphore , session .post (path , data = data ) as resp :
68+
69+ session = self .server_sessions .get (server ) if server else None
70+ session = session or self ._session
71+ headers = session .headers
72+ if "finishchunks" in path :
73+ headers = dict (session .headers ) | {"Content-Type" : "application/json;charset=utf-8" }
74+ data = json .dumps (data ) # type: ignore
75+
76+ async with self ._semaphore , session .post (path , data = data , headers = headers ) as resp :
6277 resp .raise_for_status ()
6378 response = await resp .json ()
6479 record = {"url" : str (resp .url ), "headers" : dict (resp .headers ), "response" : response }
@@ -116,10 +131,12 @@ async def create_album(
116131 async def upload (self , file : FileInfo | Path , server : URL , album_id : str | None = None ) -> UploadResponse :
117132 if isinstance (file , Path ):
118133 file = FileInfo (file , album_id = album_id )
134+
119135 file_info = file
120136 assert file_info .size <= self .info .maxSize
121137 async with aiofiles .open (file_info .path , "rb" ) as file_data :
122138 chunk_data = await file_data .read (self ._chunk_size )
139+
123140 data = FormData ()
124141 data .add_field ("files[]" , chunk_data , filename = file_info .path .name , content_type = file_info .mimetype )
125142 if album_id :
@@ -130,5 +147,6 @@ async def upload(self, file: FileInfo | Path, server: URL, album_id: str | None
130147
131148 async def finish_chunks (self , file_info : FileInfo , server : URL ):
132149 data = {"files" : [file_info .dump_json ()]}
150+ logger .info (data )
133151 response = await self ._post ("upload/finishchunks" , data = data , server = server )
134152 return UploadResponse (** response )
0 commit comments