udemy-userAPI 0.2.6__py3-none-any.whl → 0.2.8__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.
- udemy_userAPI/__version__.py +1 -1
- udemy_userAPI/authenticate.py +70 -26
- {udemy_userAPI-0.2.6.dist-info → udemy_userAPI-0.2.8.dist-info}/METADATA +3 -3
- {udemy_userAPI-0.2.6.dist-info → udemy_userAPI-0.2.8.dist-info}/RECORD +7 -7
- {udemy_userAPI-0.2.6.dist-info → udemy_userAPI-0.2.8.dist-info}/LICENSE +0 -0
- {udemy_userAPI-0.2.6.dist-info → udemy_userAPI-0.2.8.dist-info}/WHEEL +0 -0
- {udemy_userAPI-0.2.6.dist-info → udemy_userAPI-0.2.8.dist-info}/top_level.txt +0 -0
udemy_userAPI/__version__.py
CHANGED
udemy_userAPI/authenticate.py
CHANGED
@@ -2,6 +2,9 @@ import json
|
|
2
2
|
import os
|
3
3
|
import pickle
|
4
4
|
import traceback
|
5
|
+
import hashlib
|
6
|
+
import hmac
|
7
|
+
import math
|
5
8
|
from datetime import datetime
|
6
9
|
import requests
|
7
10
|
from .exeptions import UnhandledExceptions, UdemyUserApiExceptions, LoginException
|
@@ -13,7 +16,7 @@ DEBUG = False
|
|
13
16
|
class UdemyAuth:
|
14
17
|
def __init__(self):
|
15
18
|
"""Autenticação na plataforma udemy de maneira segura, atencao ao limite de logins,recomendo que apos logar
|
16
|
-
nao use
|
19
|
+
nao use novamnete o metodo login use apenas o verifcador de login para evitar bloqueios temporários..."""
|
17
20
|
self.__cookie_dict = {}
|
18
21
|
# Diretório do arquivo atual
|
19
22
|
current_directory = os.path.dirname(__file__)
|
@@ -185,7 +188,6 @@ class UdemyAuth:
|
|
185
188
|
raise LoginException(f"Erro ao carregar cookies: {e}")
|
186
189
|
|
187
190
|
def remove_cookies(self):
|
188
|
-
"""remove os cookies salvos"""
|
189
191
|
if os.path.exists(self.__file_path):
|
190
192
|
with open(self.__file_path, 'wb') as f:
|
191
193
|
f.write(b'')
|
@@ -241,30 +243,45 @@ class UdemyAuth:
|
|
241
243
|
login_url = "https://www.udemy.com/api-2.0/auth/code-generation/login/4.0/"
|
242
244
|
response = session.post(login_url, data=data, allow_redirects=False)
|
243
245
|
if 'error_message' in response.text:
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
246
|
+
erro_data: dict = response.json()
|
247
|
+
error_message = erro_data.get('error_message', {})
|
248
|
+
raise LoginException(error_message)
|
249
|
+
for attempt in range(3):
|
250
|
+
# Solicita o código OTP ao usuário
|
251
|
+
otp = input("Digite o código de 6 dígitos enviado ao seu e-mail: ")
|
252
|
+
# Realiza o login com o código OTP
|
253
|
+
otp_login_url = "https://www.udemy.com/api-2.0/auth/udemy-passwordless/login/4.0/"
|
254
|
+
otp_data = {
|
255
|
+
"email": email,
|
256
|
+
"fullname": "",
|
257
|
+
"otp": otp,
|
258
|
+
"subscribeToEmails": "false",
|
259
|
+
"upow": J(email, 'login')
|
260
|
+
}
|
261
|
+
session.headers.update({
|
262
|
+
"Referer": f"https://www.udemy.com/join/passwordless-auth/?locale={locale}&next="
|
263
|
+
f"https%3A%2F%2Fwww.udemy.com%2Fmobile%2Fipad%2F&response_type=html"
|
264
|
+
})
|
265
|
+
response = session.post(otp_login_url, otp_data, allow_redirects=False)
|
266
|
+
# Verifica se o login foi bem-sucedido
|
267
|
+
if response.status_code == 200:
|
268
|
+
self._save_cookies(session.cookies)
|
269
|
+
else:
|
270
|
+
if 'error_message' in response.text:
|
271
|
+
erro_data: dict = response.json()
|
272
|
+
error_message = erro_data.get('error_message', {})
|
273
|
+
error_code = erro_data.get('error_code', {})
|
274
|
+
if error_code == '1538':
|
275
|
+
raise LoginException(error_message)
|
276
|
+
elif error_code == '2550':
|
277
|
+
print(error_message)
|
278
|
+
continue
|
279
|
+
elif error_code == '1330':
|
280
|
+
raise LoginException(error_message)
|
281
|
+
elif error_code == '1149':
|
282
|
+
LoginException(f"Erro interno ao enviar os dados veja os detalhes: '{error_message}'")
|
283
|
+
raise LoginException(response.text)
|
284
|
+
break
|
268
285
|
except Exception as e:
|
269
286
|
if DEBUG:
|
270
287
|
error_details = traceback.format_exc()
|
@@ -273,3 +290,30 @@ class UdemyAuth:
|
|
273
290
|
raise LoginException(error_details)
|
274
291
|
|
275
292
|
|
293
|
+
def J(e, t):
|
294
|
+
r = datetime.now()
|
295
|
+
s = r.isoformat()[:10]
|
296
|
+
return s + X(e, s, t)
|
297
|
+
|
298
|
+
|
299
|
+
def X(e, t, r):
|
300
|
+
s = 0
|
301
|
+
while True:
|
302
|
+
o = ee(s)
|
303
|
+
a = hmac.new(r.encode(), (e + t + o).encode(), hashlib.sha256).digest()
|
304
|
+
if te(16, a):
|
305
|
+
return o
|
306
|
+
s += 1
|
307
|
+
|
308
|
+
|
309
|
+
def ee(e):
|
310
|
+
if e < 0:
|
311
|
+
return ""
|
312
|
+
return ee(e // 26 - 1) + chr(65 + e % 26)
|
313
|
+
|
314
|
+
|
315
|
+
def te(e, t):
|
316
|
+
r = math.ceil(e / 8)
|
317
|
+
s = t[:r]
|
318
|
+
o = ''.join(format(byte, '08b') for byte in s)
|
319
|
+
return o.startswith('0' * e)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: udemy_userAPI
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.8
|
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
|
@@ -19,10 +19,10 @@ Requires-Dist: pywidevine
|
|
19
19
|
# udemy-userAPI
|
20
20
|
|
21
21
|
|
22
|
-

|
23
23
|

|
24
24
|
[](https://apoia.se/paulocesar-dev404)
|
25
|
-
[](https://github.com/PauloCesar-dev404/udemy-userAPI/
|
25
|
+
[](https://github.com/PauloCesar-dev404/udemy-userAPI/blob/main/docs/iniciando.md)
|
26
26
|
|
27
27
|
|
28
28
|
Obtenha detalhes de cursos da plataforma udemy com a api de usuário,usando esta lib
|
@@ -11,9 +11,9 @@ m3u8_analyzer/__init__.py,sha256=v7CiVqsCq2YH347C-QR1kHPJtXFFdru8qole3E9adCY,217
|
|
11
11
|
m3u8_analyzer/__version__.py,sha256=YP3yT87ZKrU3eARUUdQ_pg4xAXLGfBXjH4ZgEoZSq1I,25
|
12
12
|
m3u8_analyzer/exeptions.py,sha256=fK6bU3YxNSbfsPmCp4yudUvmwy_g6dj2KwIkH0dW4LI,3672
|
13
13
|
udemy_userAPI/__init__.py,sha256=BPle89xE_CMTKKe_Lw6jioYLgpH-q_Lpho2S-n1PIUA,206
|
14
|
-
udemy_userAPI/__version__.py,sha256=
|
14
|
+
udemy_userAPI/__version__.py,sha256=vx5RTMBCZ8TPFvdbHibhAEl83lKiEzlCu5oYTGRiPQg,405
|
15
15
|
udemy_userAPI/api.py,sha256=dpwFtXewQmKwgG1IvzDFYZoEHNTwZbLIuv4WKgbqjOg,18817
|
16
|
-
udemy_userAPI/authenticate.py,sha256=
|
16
|
+
udemy_userAPI/authenticate.py,sha256=84frcOMfOzfCBfXDtoTa3POqkwWwuqgJ6h4ROF0TVAM,13850
|
17
17
|
udemy_userAPI/bultins.py,sha256=_-CM8Y-EuOEyg3kbNI2LKUONdCn2d1El1AmoNqFo0EU,12426
|
18
18
|
udemy_userAPI/exeptions.py,sha256=nuZoAt4i-ctrW8zx9LZtejrngpFXDHOVE5cEXM4RtrY,508
|
19
19
|
udemy_userAPI/sections.py,sha256=zPyDhvTIQCL0nbf7OJZG28Kax_iooILQ_hywUwvHoL8,4043
|
@@ -22,8 +22,8 @@ udemy_userAPI/.cache/.udemy_userAPI,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
22
22
|
udemy_userAPI/mpd_analyzer/__init__.py,sha256=i3JVWyvcFLaj5kPmx8c1PgjsLht7OUIQQClD4yqYbo8,102
|
23
23
|
udemy_userAPI/mpd_analyzer/bin.wvd,sha256=1rAJdCc120hQlX9qe5KUS628eY2ZHYxQSmyhGNefSzo,2956
|
24
24
|
udemy_userAPI/mpd_analyzer/mpd_parser.py,sha256=_vw1feJXDjw5fQLOmA5-H3UklX_30Pbl__HtDUqvp3c,17283
|
25
|
-
udemy_userAPI-0.2.
|
26
|
-
udemy_userAPI-0.2.
|
27
|
-
udemy_userAPI-0.2.
|
28
|
-
udemy_userAPI-0.2.
|
29
|
-
udemy_userAPI-0.2.
|
25
|
+
udemy_userAPI-0.2.8.dist-info/LICENSE,sha256=l4jdKYt8gSdDFOGr09vCKnMn_Im55XIcQKqTDEtFfNs,1095
|
26
|
+
udemy_userAPI-0.2.8.dist-info/METADATA,sha256=rOApAgyamEEbPBHpoE7JDYl1RjPryfsCr3e3aPl_LCY,1417
|
27
|
+
udemy_userAPI-0.2.8.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
28
|
+
udemy_userAPI-0.2.8.dist-info/top_level.txt,sha256=ijTINaSDRKhdahY_X7dmSRFTxBIwQErWv9ATCG55mog,14
|
29
|
+
udemy_userAPI-0.2.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|