udemy-userAPI 0.3.11__py3-none-any.whl → 0.3.12__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.
@@ -1,4 +1,4 @@
1
- __version__ = '0.3.11'
1
+ __version__ = '0.3.12'
2
2
  __lib_name__ = 'udemy_userAPI' # local name
3
3
  __repo_name__ = 'udemy-userAPI'
4
4
  __autor__ = 'PauloCesar-dev404'
udemy_userAPI/api.py CHANGED
@@ -14,7 +14,7 @@ import base64
14
14
 
15
15
 
16
16
  AUTH = UdemyAuth()
17
- COOKIES = AUTH._load_cookies()
17
+ COOKIES = AUTH.load_cookies()
18
18
 
19
19
  HEADERS_USER = {
20
20
  "accept": "*/*",
@@ -1,14 +1,47 @@
1
+ import http
1
2
  import json
2
3
  import os
3
4
  import pickle
4
5
  import traceback
6
+ from http.cookies import SimpleCookie
7
+
8
+ import cloudscraper
5
9
  import requests
10
+
6
11
  from .exeptions import UnhandledExceptions, UdemyUserApiExceptions, LoginException, Upstreamconnecterror
7
- import cloudscraper
8
12
 
9
13
  DEBUG = False
10
14
 
11
15
 
16
+ def convert_cook(cookie_string):
17
+ """
18
+ Converte uma string de cookies para um dicionário usando http.cookies.
19
+
20
+ Args:
21
+ cookie_string (str): A string de cookies no formato "nome1=valor1; nome2=valor2".
22
+
23
+ Returns:
24
+ dict: Um dicionário onde as chaves são os nomes dos cookies e os valores são os seus respectivos valores.
25
+ Retorna um dicionário vazio se a string for inválida ou vazia.
26
+ """
27
+ if not isinstance(cookie_string, str) or not cookie_string.strip():
28
+ print("A string de cookies fornecida é inválida ou vazia.")
29
+ return {}
30
+
31
+ cookie = SimpleCookie()
32
+ try:
33
+ # Carrega a string de cookies
34
+ cookie.load(cookie_string)
35
+
36
+ # Converte o objeto SimpleCookie para um dicionário regular
37
+ dicionario_cookies = {k: v.value for k, v in cookie.items()}
38
+
39
+ return dicionario_cookies
40
+ except http.cookies.CookieError as e:
41
+ print(f"Erro ao analisar a string de cookies: {e}")
42
+ return {}
43
+
44
+
12
45
  class UdemyAuth:
13
46
  def __init__(self):
14
47
  """
@@ -162,7 +195,7 @@ class UdemyAuth:
162
195
 
163
196
  # Verifica a resposta para determinar se o login foi bem-sucedido
164
197
  if "returnUrl" in r.text:
165
- self._save_cookies(s.cookies)
198
+ self.__save_cookies(s.cookies)
166
199
  else:
167
200
  login_error = r.json().get("error", {}).get("data", {}).get("formErrors", [])[0]
168
201
  if login_error[0] == "Y":
@@ -176,14 +209,101 @@ class UdemyAuth:
176
209
  e = traceback.format_exc()
177
210
  raise LoginException(e)
178
211
 
179
- def _save_cookies(self, cookies):
212
+ def login_direct_cookies(self, cookies: str):
213
+ """
214
+ Realiza login via cookies diretamente. (Não é seguro para uso em produção).
215
+
216
+ Argumentos:
217
+ cookies: Pode ser o caminho do arquivo cookies (apenas .json ou .txt)
218
+ ou a string com os cookies.
219
+
220
+ Raises:
221
+ FileNotFoundError: Se o arquivo especificado não for encontrado.
222
+ ValueError: Se o arquivo não for .json ou .txt, ou se o JSON for inválido.
223
+ UnhandledExceptions: Para outros erros inesperados durante a leitura do arquivo.
224
+ LoginException: Se os cookies estiverem expirados, inválidos ou houver falha no login.
225
+ """
226
+ cookies_content = ""
227
+ # Verifica se a string fornecida é um caminho de arquivo existente
228
+ if os.path.isfile(cookies):
229
+ file_extension = os.path.splitext(cookies)[1].lower() # Pega a extensão do arquivo
230
+
231
+ # Verifica se a extensão é permitida
232
+ if file_extension not in ['.json', '.txt']:
233
+ raise ValueError(
234
+ f"Erro: Apenas arquivos .json ou .txt são permitidos. "
235
+ f"Extensão recebida: '{file_extension}' para o arquivo '{cookies}'."
236
+ )
237
+
238
+ try:
239
+ with open(cookies, 'r', encoding='utf-8') as f:
240
+ cookies_content = f.read()
241
+
242
+ # Se for um arquivo JSON, tenta carregá-lo para validar
243
+ if file_extension == '.json':
244
+ try:
245
+ # Tenta carregar o JSON. Se for um JSON de cookies, ele pode estar
246
+ # em um formato específico. Aqui estamos apenas validando a sintaxe JSON.
247
+ json.loads(cookies_content)
248
+ except json.JSONDecodeError as e:
249
+ raise ValueError(f"Erro: O arquivo '{cookies}' contém JSON inválido: {e}")
250
+
251
+ except FileNotFoundError:
252
+ raise FileNotFoundError(f"Erro: O arquivo '{cookies}' não foi encontrado.")
253
+ except Exception as e:
254
+ raise UnhandledExceptions(f"Erro ao ler o arquivo '{cookies}': {e}")
255
+ else:
256
+ # Se não for um arquivo, assume-se que é a string de cookies diretamente
257
+ cookies_content = cookies
258
+
259
+ headers = {
260
+ "accept": "*/*",
261
+ "accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
262
+ "cache-control": "no-cache",
263
+ "pragma": "no-cache",
264
+ "sec-ch-ua": '"Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"',
265
+ "sec-ch-ua-mobile": "?0",
266
+ "sec-ch-ua-platform": '"Windows"',
267
+ "sec-fetch-dest": "empty",
268
+ "sec-fetch-mode": "cors",
269
+ "sec-fetch-site": "cross-site",
270
+ "Cookie": cookies_content,
271
+ "Referer": "https://www.udemy.com/"
272
+ }
273
+ url = 'https://www.udemy.com/api-2.0/contexts/me/?header=true'
274
+
275
+ try:
276
+ resp = requests.get(url=url, headers=headers)
277
+ resp.raise_for_status() # Lança um HTTPError para respostas de status de erro (4xx ou 5xx)
278
+
279
+ convert = resp.json() # Usa resp.json() para parsear diretamente o JSON
280
+ is_logged_in = convert.get('header', {}).get('isLoggedIn', None)
281
+
282
+ if not is_logged_in:
283
+ raise LoginException(
284
+ "Cookies expirados ou inválidos!")
285
+ self.__save_cookies(resp.cookies)
286
+
287
+ except requests.exceptions.HTTPError as e:
288
+ # Captura erros HTTP (ex: 401 Unauthorized, 403 Forbidden)
289
+ raise LoginException(f"Erro de HTTP durante o login: {e}. Resposta: {e.response.text}")
290
+ except requests.exceptions.ConnectionError as e:
291
+ raise UnhandledExceptions(f"Erro de conexão: {e}")
292
+ except requests.exceptions.Timeout as e:
293
+ raise UnhandledExceptions(f"Tempo limite da requisição excedido: {e}")
294
+ except json.JSONDecodeError as e:
295
+ raise UnhandledExceptions(f"Erro ao decodificar JSON da resposta da API: {e}. Resposta: {resp.text}")
296
+ except Exception as e:
297
+ raise UnhandledExceptions(f"Um erro inesperado ocorreu durante o login: {e}")
298
+
299
+ def __save_cookies(self, cookies):
180
300
  try:
181
301
  with open(fr'{self.__file_path}', 'wb') as f:
182
302
  pickle.dump(cookies, f)
183
303
  except Exception as e:
184
304
  raise LoginException(e)
185
305
 
186
- def _load_cookies(self) -> str:
306
+ def load_cookies(self) -> str:
187
307
  """Carrega cookies e retorna-os em uma string formatada"""
188
308
  try:
189
309
  file = os.path.join(self.__file_path)
@@ -286,7 +406,7 @@ class UdemyAuth:
286
406
  response = session.post(otp_login_url, otp_data, allow_redirects=False)
287
407
 
288
408
  if response.status_code == 200:
289
- self._save_cookies(session.cookies)
409
+ self.__save_cookies(session.cookies)
290
410
  break # Sai do loop se o login for bem-sucedido
291
411
  else:
292
412
  if 'error_message' in response.text:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: udemy_userAPI
3
- Version: 0.3.11
3
+ Version: 0.3.12
4
4
  Summary: Obtenha detalhes de cursos que o usuário esteja inscrito da plataforma Udemy,usando o EndPoint de usuário o mesmo que o navegador utiliza para acessar e redenrizar os cursos.
5
5
  Author: PauloCesar-dev404
6
6
  Author-email: paulocesar0073dev404@gmail.com
@@ -21,6 +21,7 @@ Dynamic: description
21
21
  Dynamic: description-content-type
22
22
  Dynamic: keywords
23
23
  Dynamic: license
24
+ Dynamic: license-file
24
25
  Dynamic: platform
25
26
  Dynamic: project-url
26
27
  Dynamic: requires-dist
@@ -29,10 +30,10 @@ Dynamic: summary
29
30
  # udemy-userAPI
30
31
 
31
32
 
32
- ![Versão](https://img.shields.io/badge/version-0.3.11-orange)
33
+ ![Versão](https://img.shields.io/badge/version-0.3.12-orange)
33
34
  ![Licença](https://img.shields.io/badge/license-MIT-orange)
34
35
  [![Sponsor](https://img.shields.io/badge/💲Donate-yellow)](https://paulocesar-dev404.github.io/me-apoiando-online/)
35
- [![Sponsor](https://img.shields.io/badge/Documentation-green)](https://github.com/PauloCesar-dev404/udemy-userAPI/blob/main/docs/iniciando.md)
36
+ [![Sponsor](https://img.shields.io/badge/Documentation-green)]()
36
37
 
37
38
 
38
39
  Obtenha detalhes de cursos da plataforma udemy com a api de usuário,usando esta lib
@@ -1,7 +1,7 @@
1
1
  udemy_userAPI/__init__.py,sha256=BPle89xE_CMTKKe_Lw6jioYLgpH-q_Lpho2S-n1PIUA,206
2
- udemy_userAPI/__version__.py,sha256=H_ODVq4mKyiFkG5i7lWTBSW7IGZEXM6ygiPLRFT_VtA,406
3
- udemy_userAPI/api.py,sha256=GVvbbs3vFN-rF-qLBwiuHz77sjehwk8HjAI-Dey_A6c,29167
4
- udemy_userAPI/authenticate.py,sha256=lKh4_UMT4zapnUzUSgM0HZoyZYX84w0MMZAaGvCMZQ4,14086
2
+ udemy_userAPI/__version__.py,sha256=hsuWNfD58RhtiW3QQ8DEVA806KW5TK_7r4v9j6OIL2o,406
3
+ udemy_userAPI/api.py,sha256=Pxwy-UrqVCLX1tTLQQojb7nCjkHE9mLlnpO1OJuqlAI,29166
4
+ udemy_userAPI/authenticate.py,sha256=ObUh8cs-o7mC9Ovid1UoFvPS4m0nSe4fBk-E3XQqL1o,19511
5
5
  udemy_userAPI/bultins.py,sha256=LZlyOjSGte6B6gNn7cjl6L2Q2T_CyXIqqfkOUzt4CV4,21996
6
6
  udemy_userAPI/exeptions.py,sha256=kfnPdZpqYY8nd0gnl6_Vh-MIz-XupmmbRPIuFnyXupk,692
7
7
  udemy_userAPI/sections.py,sha256=Q1PlVt2Bu5MSEP8g11-F_gilJDdhZq50TV1Bo400jcA,6389
@@ -10,8 +10,8 @@ udemy_userAPI/.cache/.udemy_userAPI,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
10
10
  udemy_userAPI/mpd_analyzer/__init__.py,sha256=i3JVWyvcFLaj5kPmx8c1PgjsLht7OUIQQClD4yqYbo8,102
11
11
  udemy_userAPI/mpd_analyzer/bin.wvd,sha256=1rAJdCc120hQlX9qe5KUS628eY2ZHYxQSmyhGNefSzo,2956
12
12
  udemy_userAPI/mpd_analyzer/mpd_parser.py,sha256=PgUkHc5x8FTuXFCuYkWPZr9TaO_nsKalb02EFYl_zeA,8926
13
- udemy_userAPI-0.3.11.dist-info/LICENSE,sha256=l4jdKYt8gSdDFOGr09vCKnMn_Im55XIcQKqTDEtFfNs,1095
14
- udemy_userAPI-0.3.11.dist-info/METADATA,sha256=HEgb5dgPW0dIQPdd2BHd4moLOuA1_y_8PWm1CapcxMY,1657
15
- udemy_userAPI-0.3.11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
16
- udemy_userAPI-0.3.11.dist-info/top_level.txt,sha256=ijTINaSDRKhdahY_X7dmSRFTxBIwQErWv9ATCG55mog,14
17
- udemy_userAPI-0.3.11.dist-info/RECORD,,
13
+ udemy_userapi-0.3.12.dist-info/licenses/LICENSE,sha256=l4jdKYt8gSdDFOGr09vCKnMn_Im55XIcQKqTDEtFfNs,1095
14
+ udemy_userapi-0.3.12.dist-info/METADATA,sha256=dkTiWdFOxfJejB4wL_ZYwuq2iy6DKRQheCcydIlzC2o,1602
15
+ udemy_userapi-0.3.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ udemy_userapi-0.3.12.dist-info/top_level.txt,sha256=ijTINaSDRKhdahY_X7dmSRFTxBIwQErWv9ATCG55mog,14
17
+ udemy_userapi-0.3.12.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5