bcpkgfox 0.15.30__py3-none-any.whl → 0.17.7__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.
bcpkgfox/invoke_api.py CHANGED
@@ -1,7 +1,14 @@
1
+ import json
2
+
3
+ from selenium.webdriver.support import expected_conditions as EC
4
+ from selenium.webdriver.support.ui import WebDriverWait
5
+ from selenium.webdriver.common.by import By
1
6
  from typing import Optional
7
+ from threading import Thread
2
8
  import time
9
+ import os
3
10
 
4
- def invoke_api_list(link: str, token: str, method: Optional[str] = "GET", print_response: Optional[bool] = False) -> dict:
11
+ def invoke_api_list(link: str, token: str, method: Optional[str] = "GET", headers: Optional[str] = None, print_response: Optional[bool] = False) -> dict:
5
12
  import requests
6
13
 
7
14
  """
@@ -32,7 +39,8 @@ def invoke_api_list(link: str, token: str, method: Optional[str] = "GET", print_
32
39
  raise ValueError(f"Método HTTP inválido. Use um dos seguintes: {', '.join(http_methods.keys())}.")
33
40
 
34
41
  payload = {}
35
- headers = {"x-access-token": token}
42
+ if headers is None: headers = {"x-access-token": token}
43
+ else: {headers: token}
36
44
 
37
45
  max_attempts = 5
38
46
  for attempt in range(1, max_attempts + 1):
@@ -59,9 +67,7 @@ def invoke_api_list(link: str, token: str, method: Optional[str] = "GET", print_
59
67
 
60
68
  else: raise ValueError("Api list falhou")
61
69
 
62
- return response_api_list
63
-
64
- def invoke_api_proc(link: str, payload_vars: dict, token: str, method: str, print_response: Optional[bool] = False) -> str:
70
+ def invoke_api_proc(link: str, payload_vars: dict, token: str, method: str, print_response: Optional[bool | str] = False) -> str:
65
71
  import requests
66
72
 
67
73
  """
@@ -83,9 +89,17 @@ def invoke_api_proc(link: str, payload_vars: dict, token: str, method: str, prin
83
89
  bc.invoke_api_proc_final(link, payload, token, print_response=True)
84
90
 
85
91
  OBS: o print_response vem por padrão desligado, caso você queria ver o returno do response coloque 'ON'
92
+ OBS2: Caso queria printar o json response intero coloque: 'print_response = "full"'
86
93
 
87
94
  """
88
95
 
96
+ if isinstance(print_response, str):
97
+ if print_response.lower().strip() == "full":
98
+ print_response = "full"
99
+
100
+ else:
101
+ raise ValueError("print_response com variável inválida\n Use tipo 'bool' ou escreva 'full' (str) para response completo")
102
+
89
103
  http_methods = {
90
104
  "POST": requests.post,
91
105
  "GET": requests.get,
@@ -104,7 +118,7 @@ def invoke_api_proc(link: str, payload_vars: dict, token: str, method: str, prin
104
118
 
105
119
  payload = payload_vars
106
120
 
107
- if print_response == True:
121
+ if print_response == True or print_response == "full":
108
122
  print(f'payload: {payload}')
109
123
 
110
124
  headers = {"x-access-token": token}
@@ -118,19 +132,14 @@ def invoke_api_proc(link: str, payload_vars: dict, token: str, method: str, prin
118
132
 
119
133
  response_insert.raise_for_status()
120
134
 
121
- if print_response == True:
135
+ if print_response == True or print_response == "full":
122
136
  print(response_insert.json())
123
137
 
124
- try:
125
- status = response_insert.json()[0]['STATUS']
138
+ if print_response == "full":
139
+ return response_insert.json()
126
140
 
127
- if status != 200:
128
- from .get_driver import ORANGE, RESET, RD
129
- print(f' {ORANGE} > {RD}Erro ao atualizar caso!{RESET}')
130
- invoke_api_proc()
131
- else: return status
132
- except: pass
133
- return None
141
+ status = response_insert.json()[0]['STATUS']
142
+ return status
134
143
 
135
144
  except Exception as e:
136
145
  print(f"Tentativa {attempt} falhou: {e}")
@@ -160,81 +169,370 @@ def invoke_api_proc_log(link, id_robo, token):
160
169
  "POST", link, json=payload, headers=headers)
161
170
  print(f"\n{responseinsert.json()}")
162
171
 
163
- # FIX: Não funcional ainda, está aqui como base para o futuro
164
- def captcha_solver():
172
+ def login_2fac(driver, certificate, system, token, code_timeout=60):
165
173
  import requests
174
+ import pyautogui
175
+ from . import mostrar_mensagem
176
+
177
+ class login_2fac:
178
+ def __init__(self):
179
+ self.certificate = certificate
180
+ self.system = system
181
+ self.token = token
182
+ self.code_timeout = code_timeout
183
+ self.driver = driver
184
+
185
+ class Pop_up_protection(login_2fac):
186
+ def __init__(self):
187
+ super().__init__()
188
+ self.status = False
189
+
190
+ def __monitor(self):
191
+ while self.status:
166
192
 
193
+ handles = self.driver.window_handles
194
+ if len(handles) > 1:
195
+ self.driver.switch_to.window(self.driver.window_handles[-1])
196
+
197
+ try:
198
+ alert = self.driver.switch_to.alert
199
+ alert.accept()
200
+ except:
201
+ pass
202
+
203
+ time.sleep(0.1)
204
+
205
+ def start(self):
206
+ self.status = True
207
+ protection = Thread(target=self.__monitor, daemon=True)
208
+ protection.start()
209
+
210
+ def stop(self):
211
+ self.status = False
212
+
213
+ class tool(login_2fac):
214
+ def find_element_with_wait(self, by, value, timeout=10):
215
+ global driver
216
+ return WebDriverWait(
217
+ self.driver, timeout).until(
218
+ EC.presence_of_element_located(
219
+ (by, value)))
167
220
 
168
- # Configurações
169
- API_KEY = "40efad0ffa6a4398bb7829185b1729e9"
170
- SITE_KEY = "6LeARtIZAAAAAEyCjkSFdYCBZG6JahcIveDriif3" # A "sitekey" do reCAPTCHA
171
- PAGE_URL = "https://consorcio.cnpseguradora.com.br/" # URL onde o CAPTCHA aparece
172
-
173
- def enviar_captcha():
174
- url = "https://2captcha.com/in.php"
175
- payload = {
176
- "key": API_KEY,
177
- "method": "userrecaptcha",
178
- "googlekey": SITE_KEY,
179
- "pageurl": PAGE_URL,
180
- "json": 1,
181
- }
182
- response = requests.post(url, data=payload)
183
- result = response.json()
184
-
185
- if result.get("status") == 1:
186
- return result.get("request") # ID da tarefa
187
- else:
188
- raise Exception(f"Erro ao enviar CAPTCHA: {result.get('request')}")
189
-
190
- def verificar_captcha(task_id):
191
- url = "https://2captcha.com/res.php"
192
- payload = {
193
- "key": API_KEY,
194
- "action": "get",
195
- "id": task_id,
196
- "json": 1,
197
- }
198
-
199
- while True:
200
- response = requests.get(url, params=payload)
201
- result = response.json()
202
-
203
- if result.get("status") == 1: # Solução disponível
204
- return result.get("request") # TOKEN do CAPTCHA
205
- elif result.get("request") == "CAPCHA_NOT_READY": # Ainda processando
206
- time.sleep(5) # Aguardar antes de tentar novamente
207
- else:
208
- raise Exception(f"Erro ao verificar CAPTCHA: {result.get('request')}")
221
+ def find_elements_with_wait(self, by, value, timeout=10):
222
+ return WebDriverWait(
223
+ self.driver, timeout).until(
224
+ EC.presence_of_all_elements_located(
225
+ (by, value)))
209
226
 
210
- def resolver_recaptcha():
211
- try:
212
- print("Enviando CAPTCHA para o TwoCaptcha...")
213
- task_id = enviar_captcha()
214
- print(f"Tarefa enviada! ID: {task_id}")
227
+ class invokes_whoom(login_2fac):
228
+ def __init__(self):
229
+ super().__init__()
215
230
 
216
- print("Aguardando solução...")
217
- token = verificar_captcha(task_id)
218
- print(f"CAPTCHA resolvido! Token: {token}")
231
+ self.list_codes = []
219
232
 
220
- return token
221
- except Exception as e:
222
- print(f"Erro: {e}")
223
-
224
- id = enviar_captcha()
225
- verificar_captcha(id)
226
- token_resolution = resolver_recaptcha()
227
-
228
- self.driver.execute_script("""
229
- var element = document.querySelector('input[id="g-recaptcha-response]"');
230
- if (element) {
231
- element.setAttribute('type', 'text');
232
- }
233
- """)
234
-
235
- self.driver.execute_script(f"""
236
- const element = document.querySelector('textarea[id="g-recaptcha-response"]');
237
- if (element) {{
238
- element.value = "{token_resolution}";
239
- }}
240
- """)
233
+ def invoke_get_codes(self):
234
+
235
+ url = "https://api-4.bcfox.com.br/bcjur/views/codigo-validacao"
236
+ headers = {"x-access-token": self.token}
237
+
238
+ max_attempts = 5
239
+ for attempt in range(1, max_attempts + 1):
240
+ try:
241
+ response = requests.get(url, headers=headers)
242
+ response.raise_for_status() # Lança uma exceção se a resposta não for bem-sucedida
243
+
244
+ self.list_codes = response.json()
245
+ # print(self.list_codes)
246
+ return self.list_codes
247
+
248
+ except Exception as e:
249
+ print(f'Tentativa {attempt} falhou: {e}')
250
+
251
+ if attempt < max_attempts:
252
+ print('Tentando novamente em 5 segundos...')
253
+ time.sleep(5)
254
+ continue
255
+ else:
256
+ raise('Todas as tentativas falharam!')
257
+
258
+ def invoke_update_status(self, id):
259
+
260
+ url = f"https://api-4.bcfox.com.br/bcjur/views/codigo-validacao/{id}"
261
+ headers = {"x-access-token": self.token}
262
+
263
+ max_attempts = 5
264
+ for attempt in range(1, max_attempts + 1):
265
+ try:
266
+ responseinsert = requests.put(url, headers=headers)
267
+ responseinsert.raise_for_status() # Lança uma exceção se a resposta não for bem-sucedida
268
+
269
+ print(responseinsert)
270
+ return responseinsert
271
+
272
+ except Exception as e:
273
+ print(f'Tentativa {attempt} falhou: {e}')
274
+
275
+ if attempt < max_attempts:
276
+ print('Tentando novamente em 5 segundos...')
277
+ time.sleep(5)
278
+ continue
279
+ else:
280
+ raise('Todas as tentativas falharam!')
281
+
282
+ class whoom_codes(login_2fac):
283
+ def __init__(self):
284
+ super().__init__()
285
+
286
+ def extension_check(self):
287
+
288
+ self.driver.get('chrome-extension://lnidijeaekolpfeckelhkomndglcglhh/index.html')
289
+ time.sleep(3)
290
+
291
+ for _ in range(10):
292
+
293
+ # Caso a extensão já esteja instalada
294
+ try:
295
+ tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Digite ou selecione um sistema pra acessar"]', timeout=1)
296
+ return
297
+ except: pass
298
+
299
+ try:
300
+ tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Insira aqui o seu email"]', timeout=1)
301
+ return
302
+ except: pass
303
+
304
+ # Caso a extensão não esteja instala
305
+ if 'This page has been blocked by Chrome' in driver.page_source:
306
+ break
307
+
308
+ if 'eliezer@bcfox.com.br' in self.driver.page_source:
309
+ tools.find_element_with_wait(By.XPATH, "//span[text()='alterar']").click()
310
+ return
311
+
312
+ # Abrir uma nova aba
313
+ self.driver.execute_script("window.open('');")
314
+
315
+ # Fechar a aba original
316
+ self.driver.close()
317
+
318
+ # Mudar para a nova aba
319
+ self.driver.switch_to.window(self.driver.window_handles[-1])
320
+
321
+ time.sleep(1)
322
+
323
+ self.driver.get("https://chromewebstore.google.com/detail/whom-gerenciador-de-certi/lnidijeaekolpfeckelhkomndglcglhh")
324
+
325
+
326
+ tools.find_element_with_wait(By.XPATH, "//span[contains(text(), 'no Chrome') or contains(text(), 'Usar') or contains(text(), 'Add to Chrome')]").click()
327
+ time.sleep(5)
328
+ import pygetwindow as gw
329
+ windows = gw.getAllTitles()
330
+ for w in windows:
331
+ if w and "Whom?".lower() in w.lower():
332
+ print("Janela de extensão detectada:", w)
333
+ window = gw.getWindowsWithTitle(w)[0]
334
+ window.activate()
335
+ time.sleep(1)
336
+ coords = (gw.getActiveWindow().left + gw.getActiveWindow().size[0] // 2,
337
+ gw.getActiveWindow().top + int(gw.getActiveWindow().size[1] * 0.3))
338
+ pyautogui.moveTo(coords[0], coords[1])
339
+ pyautogui.click()
340
+
341
+ # Envia TAB e ENTER do teclado físico
342
+ pyautogui.press('tab')
343
+ time.sleep(0.5)
344
+ pyautogui.press('enter')
345
+ time.sleep(5)
346
+ break
347
+
348
+ self.driver.get('chrome-extension://lnidijeaekolpfeckelhkomndglcglhh/index.html')
349
+
350
+ def codes_2_fac(self):
351
+ try:
352
+ tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Digite ou selecione um sistema pra acessar"]', timeout=2).send_keys(self.system)
353
+ code_insertion = True
354
+
355
+ except:
356
+ self.driver.get('chrome-extension://lnidijeaekolpfeckelhkomndglcglhh/index.html')
357
+
358
+ # Request the code
359
+ for _ in range(50): # Wait the extension to load
360
+
361
+ try:
362
+ tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Insira aqui o seu email"]', timeout=1).send_keys('eliezer@bcfox.com.br')
363
+ time.sleep(1)
364
+ break
365
+ except:
366
+ self.driver.get('chrome-extension://lnidijeaekolpfeckelhkomndglcglhh/index.html')
367
+
368
+ # Envia o código pro email, o for é só para tratativa de bugs
369
+ for _ in range(10):
370
+ try:
371
+ tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Digite aqui o código que enviamos para o seu e-mail"]', timeout=1)
372
+ break
373
+
374
+ except:
375
+ try:
376
+ element = tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Insira aqui o seu email"]', timeout=1)
377
+ element.clear()
378
+ element.send_keys('eliezer@bcfox.com.br')
379
+ tools.find_element_with_wait(By.XPATH, '//button').click()
380
+ time.sleep(1)
381
+ except:
382
+ break
383
+
384
+ # Attempts the new codes until success or requests limit
385
+ for _ in range(code_timeout):
386
+ responses = api.invoke_get_codes()
387
+
388
+ # Try new codes
389
+ code_insertion = False
390
+ for response in responses:
391
+
392
+ CODE = response['CODIGO']
393
+ ID = response['ID']
394
+
395
+ element = tools.find_element_with_wait(By.XPATH, '//input[@type="password"]')
396
+ element.clear()
397
+ element.send_keys(CODE)
398
+
399
+ for _ in range(10):
400
+ try:
401
+ tools.find_element_with_wait(By.XPATH, '//div/div[2]/button', timeout=2).click()
402
+ time.sleep(1)
403
+ except:
404
+ break
405
+
406
+ # Check the code result
407
+ for _ in range(30):
408
+
409
+ # Correct
410
+ try:
411
+ # input('\n\n > Selecione o sistema e aperte alguma tecla.')
412
+ tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Digite ou selecione um sistema pra acessar"]', timeout=1).send_keys(self.system)
413
+ api.invoke_update_status(ID) #FIX: Update
414
+ code_insertion = True
415
+ break
416
+
417
+ except:
418
+ pass
419
+
420
+ # Wrong
421
+ try:
422
+ tools.find_element_with_wait(By.XPATH, "//span[contains(text(), 'Senha inválida')]", timeout=1)
423
+ tools.find_element_with_wait(By.XPATH, "//button[text()='Voltar']", timeout=1).click()
424
+ code_insertion = False
425
+ break
426
+
427
+ except:
428
+ pass
429
+
430
+ # If the 'new_response' loop succeeds immediately
431
+ if not responses:
432
+ time.sleep(1)
433
+
434
+ if code_insertion:
435
+ break
436
+
437
+ if not(code_insertion):
438
+ raise TimeoutError('Código WHOOM não chegou dentro do timeout estabelecido')
439
+
440
+ def select_system(self):
441
+ time.sleep(4)
442
+ try:
443
+ tools.find_element_with_wait(By.XPATH, '//input[@placeholder="Insira aqui o seu email"]',
444
+ timeout=1).click()
445
+ time.sleep(1)
446
+ self.codes_2_fac()
447
+ return
448
+ except:
449
+ pass
450
+
451
+ # Selects the system to access
452
+ lines = tools.find_elements_with_wait(By.XPATH, '//div[@role="menu"]//div[@role="menuitem"]')
453
+
454
+ finded = False
455
+ div_list = []
456
+
457
+ # This loop extract the lines with the system name
458
+ for line in lines:
459
+
460
+ titulo_element = line.find_elements(By.XPATH, './span[*[name()="svg"]]')
461
+
462
+ if not titulo_element and not finded:
463
+ continue
464
+
465
+ elif titulo_element and not finded:
466
+ titulo_text = line.find_element(By.XPATH, './span').text
467
+ if self.certificate.lower().strip() in titulo_text.lower().strip():
468
+ finded = True
469
+ continue
470
+
471
+ elif not titulo_element and finded:
472
+ div_list.append(line)
473
+
474
+ elif titulo_element and finded:
475
+ break
476
+
477
+ if not div_list:
478
+ mostrar_mensagem('Não conseguiu achar o sistema no certificado')
479
+ raise ValueError('Não conseguiu achar o sistema no certificado')
480
+
481
+ if len(div_list) == 1:
482
+ time.sleep(1)
483
+ div_list[0].click()
484
+
485
+ # Just do this loop if there are more than one system
486
+ else:
487
+ for div in div_list:
488
+ div_text = div.find_element(By.XPATH, './span').text
489
+ if self.system.lower().strip() not in div_text.lower().strip():
490
+ div_list.remove(div)
491
+
492
+ if len(div_list) == 1:
493
+ div_list[0].click()
494
+ else:
495
+ mostrar_mensagem('Mais de um sistema encontrado, verifique o nome do sistema no WHOOM e coloque um nome único na função')
496
+ raise ValueError('Mais de um sistema encontrado, verifique o nome')
497
+
498
+
499
+ # Verifies if the system was opened
500
+ for _ in range(30):
501
+ time.sleep(1)
502
+ if len(self.driver.window_handles) == 1:
503
+ try:
504
+ tools.find_element_with_wait(By.XPATH, "//button[text()='Acessar']", timeout=1).click()
505
+ except:
506
+ time.sleep(1)
507
+ else:
508
+ time.sleep(3)
509
+ break
510
+
511
+ self.driver.switch_to.window(self.driver.window_handles[-1])
512
+ attempt = 0
513
+ while 'whoom' in self.driver.title.strip().lower() and attempt <= 180:
514
+ time.sleep(1)
515
+ attempt += 1
516
+ time.sleep(5)
517
+
518
+ if attempt >= 180:
519
+ mostrar_mensagem('Whoom congelou no conectar com site.')
520
+ raise SystemError('Whoom congelou no conectar com site.')
521
+
522
+ protection.stop()
523
+ if len(self.driver.window_handles) > 1:
524
+ self.driver.switch_to.window(self.driver.window_handles[0])
525
+ self.driver.close()
526
+ self.driver.switch_to.window(self.driver.window_handles[-1])
527
+
528
+ # Instances
529
+ tools = tool()
530
+ api = invokes_whoom()
531
+ protection = Pop_up_protection()
532
+ bot = whoom_codes()
533
+
534
+ # Operacional
535
+ bot.extension_check()
536
+ protection.start()
537
+ bot.codes_2_fac()
538
+ bot.select_system()
bcpkgfox/system.py CHANGED
@@ -142,7 +142,6 @@ class System:
142
142
 
143
143
  @staticmethod
144
144
  def extract_pdf(pdf_path: str = None) -> str:
145
- import fitz
146
145
  """
147
146
  Extracts and returns the text content from a PDF file.
148
147
 
@@ -158,6 +157,7 @@ class System:
158
157
  Note:
159
158
  Use `resource_path` to localize the `pdf_path` to avoid issues with pyinstaller.
160
159
  """
160
+ import fitz
161
161
  if not pdf_path:
162
162
  raise ValueError("PDF path cannot be None.")
163
163
 
@@ -187,19 +187,19 @@ class System:
187
187
 
188
188
  def wait_for_window(self,
189
189
  object: Optional[str|list],
190
- type: str,
191
190
  timeout: Optional[int] = 10
192
191
  ) -> str | WebElement:
192
+ """
193
+ it function will disregrated difference between upper and lower case.
194
+ and you can pass multiples titles to analise.
195
+
196
+ Args:
197
+ object (str | list): pass the window titles(s)
198
+ """
193
199
 
194
200
  from .get_driver import RD, RESET
195
201
  import pygetwindow as gw
196
202
 
197
- window_type = ["window", "windows", "wd", "jn", "janela", "janelas", "janel", "windosw", "ui", "interface", "interface", "graphic", "display", "salvar como"]
198
- for escrita in window_type:
199
- if escrita in type.lower():
200
- type = "window"
201
- break
202
-
203
203
  timeout = float("inf") if timeout == 0 else timeout
204
204
  attempt = 0
205
205
  if isinstance(object, str) == True: object = [object]
@@ -219,4 +219,37 @@ class System:
219
219
  if unicodedata.category(letra) != 'Mn'
220
220
  )
221
221
 
222
-
222
+ def uf_estado(self, valor: str) -> str:
223
+ estados = {
224
+ "AC": "Acre",
225
+ "AL": "Alagoas",
226
+ "AP": "Amapá",
227
+ "AM": "Amazonas",
228
+ "BA": "Bahia",
229
+ "CE": "Ceará",
230
+ "DF": "Distrito Federal",
231
+ "ES": "Espírito Santo",
232
+ "GO": "Goiás",
233
+ "MA": "Maranhão",
234
+ "MT": "Mato Grosso",
235
+ "MS": "Mato Grosso do Sul",
236
+ "MG": "Minas Gerais",
237
+ "PA": "Pará",
238
+ "PB": "Paraíba",
239
+ "PR": "Paraná",
240
+ "PE": "Pernambuco",
241
+ "PI": "Piauí",
242
+ "RJ": "Rio de Janeiro",
243
+ "RN": "Rio Grande do Norte",
244
+ "RS": "Rio Grande do Sul",
245
+ "RO": "Rondônia",
246
+ "RR": "Roraima",
247
+ "SC": "Santa Catarina",
248
+ "SP": "São Paulo",
249
+ "SE": "Sergipe",
250
+ "TO": "Tocantins"
251
+ }
252
+ if valor.upper() in estados:
253
+ return estados[valor.upper()]
254
+ estado_uf = {v.lower(): k for k, v in estados.items()}
255
+ return estado_uf.get(valor.lower(), "Valor inválido")
@@ -1,10 +1,10 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: bcpkgfox
3
- Version: 0.15.30
3
+ Version: 0.17.7
4
4
  Summary: Biblioteca BCFOX
5
5
  Home-page: https://github.com/robotsbcfox/PacotePythonBCFOX
6
- Author: Guilherme Neri
7
- Author-email: guilherme.neri@bcfox.com.br
6
+ Author: BCFOX
7
+ Author-email: bcfox@bcfox.com.br
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
@@ -13,12 +13,27 @@ Description-Content-Type: text/markdown
13
13
  Requires-Dist: setuptools
14
14
  Requires-Dist: pyperclip
15
15
  Requires-Dist: pyinstaller
16
+ Requires-Dist: selenium
17
+ Provides-Extra: pynput
18
+ Requires-Dist: pynput; extra == "pynput"
19
+ Provides-Extra: screeninfo
20
+ Requires-Dist: screeninfo; extra == "screeninfo"
21
+ Provides-Extra: pywinauto
22
+ Requires-Dist: pywinauto; extra == "pywinauto"
23
+ Provides-Extra: capmonstercloudclient
24
+ Requires-Dist: capmonstercloudclient; extra == "capmonstercloudclient"
25
+ Provides-Extra: twocaptcha
26
+ Requires-Dist: twocaptcha; extra == "twocaptcha"
27
+ Requires-Dist: 2captcha-python; extra == "twocaptcha"
28
+ Provides-Extra: psutil
29
+ Requires-Dist: psutil; extra == "psutil"
16
30
  Provides-Extra: full
17
31
  Requires-Dist: undetected-chromedriver; extra == "full"
18
32
  Requires-Dist: webdriver-manager; extra == "full"
19
33
  Requires-Dist: opencv-python; extra == "full"
20
34
  Requires-Dist: pygetwindow; extra == "full"
21
35
  Requires-Dist: pyinstaller; extra == "full"
36
+ Requires-Dist: screeninfo; extra == "full"
22
37
  Requires-Dist: pyscreeze; extra == "full"
23
38
  Requires-Dist: pyautogui; extra == "full"
24
39
  Requires-Dist: selenium; extra == "full"
@@ -26,6 +41,7 @@ Requires-Dist: requests; extra == "full"
26
41
  Requires-Dist: pymupdf; extra == "full"
27
42
  Requires-Dist: Pillow; extra == "full"
28
43
  Requires-Dist: psutil; extra == "full"
44
+ Requires-Dist: pynput; extra == "full"
29
45
  Dynamic: author
30
46
  Dynamic: author-email
31
47
  Dynamic: classifier
@@ -0,0 +1,12 @@
1
+ bcpkgfox/__init__.py,sha256=49TPbTUNI6xKcYk4blwseUZQTgHtRcNI1AFEqxSQ3wY,16540
2
+ bcpkgfox/clean.py,sha256=80pJDTGmKmPiq73uL1IWopuxqVJF_bj_RVv-njkpl-A,8946
3
+ bcpkgfox/cli.py,sha256=E1Yahd8jIjUwxM6EMHveDDne5-fh8QeAvAhyATNatEo,33541
4
+ bcpkgfox/find_elements.py,sha256=oeB-73LqMLoKchozPXuxRkThBju9IgUKqbgU-2AAq0s,23027
5
+ bcpkgfox/get_driver.py,sha256=ohimk9E2hL6T35IXv0XX0uvWDGCUZvZDlPMnuRjV1R0,30490
6
+ bcpkgfox/invoke_api.py,sha256=TQ9f_eAhf37VvEyUL6UJR__r8HWTvpsgMsR7X56kGdM,20140
7
+ bcpkgfox/system.py,sha256=3lyOWx893T6KiAI-jDv7zAo3oKPf0Q5CLgZ8TeFd0Do,7901
8
+ bcpkgfox-0.17.7.dist-info/METADATA,sha256=VmejLvx9ZJbmeL9_Y2BWnKGfnUkfgSV-zQZgJmaW0qU,1893
9
+ bcpkgfox-0.17.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ bcpkgfox-0.17.7.dist-info/entry_points.txt,sha256=qmaEg6K7Y0HOeaFo-G6lf44InGkeVI4I6hqobcY_nns,653
11
+ bcpkgfox-0.17.7.dist-info/top_level.txt,sha256=h01SqyYBEfS72vkRFOlEDZBUSu9pzU0bdX4m9hWNNmw,9
12
+ bcpkgfox-0.17.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5