udemy-userAPI 0.1.4__tar.gz → 0.1.6__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {udemy_userapi-0.1.4/udemy_userAPI.egg-info → udemy_userapi-0.1.6}/PKG-INFO +3 -3
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/README.md +1 -1
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/README_PYPI.md +1 -1
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/__version__.py +2 -4
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/api.py +37 -3
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/authenticate.py +16 -9
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/bultins.py +23 -10
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/udemy.py +18 -3
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6/udemy_userAPI.egg-info}/PKG-INFO +3 -3
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/LICENSE +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/MANIFEST.in +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/setup.cfg +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/setup.py +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/__init__.py +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/exeptions.py +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI/sections.py +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI.egg-info/SOURCES.txt +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI.egg-info/dependency_links.txt +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI.egg-info/not-zip-safe +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI.egg-info/requires.txt +0 -0
- {udemy_userapi-0.1.4 → udemy_userapi-0.1.6}/udemy_userAPI.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: udemy_userAPI
|
3
|
-
Version: 0.1.
|
4
|
-
Summary: Obtenha detalhes de cursos que o usuário esteja inscrito da plataforma Udemy,usando o EndPoint de
|
3
|
+
Version: 0.1.6
|
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
|
7
7
|
License: MIT
|
@@ -18,7 +18,7 @@ Requires-Dist: cloudscraper
|
|
18
18
|
# udemy-userAPI
|
19
19
|
|
20
20
|
|
21
|
-

|
21
|
+

|
22
22
|

|
23
23
|
[](https://apoia.se/paulocesar-dev404)
|
24
24
|
[](https://github.com/PauloCesar-dev404/udemy-userAPI/wiki)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<img src="assets/udemy_userAPI-logo.png" alt="udemy_userAPI-logo" width="200"/>
|
3
3
|
|
4
4
|
|
5
|
-

|
5
|
+

|
6
6
|

|
7
7
|
[](https://apoia.se/paulocesar-dev404)
|
8
8
|
[](https://github.com/PauloCesar-dev404/udemy-userAPI/wiki)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# udemy-userAPI
|
2
2
|
|
3
3
|
|
4
|
-

|
4
|
+

|
5
5
|

|
6
6
|
[](https://apoia.se/paulocesar-dev404)
|
7
7
|
[](https://github.com/PauloCesar-dev404/udemy-userAPI/wiki)
|
@@ -1,8 +1,6 @@
|
|
1
|
-
__version__ = '0.1.
|
1
|
+
__version__ = '0.1.6'
|
2
2
|
__lib_name__ = 'udemy_userAPI' # local name
|
3
3
|
__repo_name__ = 'udemy-userAPI'
|
4
4
|
__autor__ = 'PauloCesar-dev404'
|
5
5
|
__repo__ = f'https://github.com/PauloCesar-dev404/{__repo_name__}'
|
6
|
-
__description__ = """Obtenha detalhes de cursos que o usuário esteja inscrito da plataforma Udemy,usando o EndPoint de
|
7
|
-
usuário o mesmo que o navegador utiliza para
|
8
|
-
acessar e redenrizar os cursos."""
|
6
|
+
__description__ = """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."""
|
@@ -67,14 +67,14 @@ def parser_chapers(results):
|
|
67
67
|
elif _class == 'lecture' and current_chapter is not None:
|
68
68
|
asset = dictionary.get('asset')
|
69
69
|
if asset:
|
70
|
-
video_title =
|
70
|
+
video_title = dictionary.get('title', None)
|
71
71
|
if not video_title:
|
72
72
|
video_title = 'Files'
|
73
73
|
current_chapter['videos_in_chapter'].append({
|
74
74
|
'video_title': video_title,
|
75
75
|
'title_lecture': dictionary.get('title'),
|
76
|
-
'
|
77
|
-
'
|
76
|
+
'lecture_id': dictionary.get('id'),
|
77
|
+
'asset_id': asset.get('id')
|
78
78
|
})
|
79
79
|
|
80
80
|
return chapters_dict
|
@@ -257,3 +257,37 @@ def format_size(byte_size):
|
|
257
257
|
return f"{byte_size / TB:.2f} TB"
|
258
258
|
except Exception as e:
|
259
259
|
return byte_size
|
260
|
+
|
261
|
+
|
262
|
+
def lecture_infor(course_id: int, id_lecture: int):
|
263
|
+
edpoint = (f"https://www.udemy.com/api-2.0/users/me/subscribed-courses/{course_id}/lectures/{id_lecture}/?"
|
264
|
+
f"fields[asset]=media_license_token&q=0.06925737374647678")
|
265
|
+
r = requests.get(edpoint, headers=HEADERS_USER)
|
266
|
+
if r.status_code == 200:
|
267
|
+
return json.loads(r.text)
|
268
|
+
|
269
|
+
|
270
|
+
def assets_infor(course_id: int, id_lecture: int, assets_id: int):
|
271
|
+
endpoint = (f'https://www.udemy.com/api-2.0/assets/{assets_id}/?fields[asset]=@min,status,delayed_asset_message,'
|
272
|
+
f'processing_errors,body&course_id={course_id}&lecture_id={id_lecture}')
|
273
|
+
r = requests.get(endpoint, headers=HEADERS_USER)
|
274
|
+
if r.status_code == 200:
|
275
|
+
dt = json.loads(r.text)
|
276
|
+
body = dt.get("body")
|
277
|
+
title = lecture_infor(course_id=course_id, id_lecture=id_lecture).get("title")
|
278
|
+
return save_html(body, title_lecture=title)
|
279
|
+
|
280
|
+
|
281
|
+
def save_html(body, title_lecture):
|
282
|
+
html_content = f"""<!DOCTYPE html>
|
283
|
+
<html lang="en">
|
284
|
+
<head>
|
285
|
+
<meta charset="UTF-8">
|
286
|
+
<title>{title_lecture}</title>
|
287
|
+
</head>
|
288
|
+
<body>
|
289
|
+
{body}
|
290
|
+
</body>
|
291
|
+
</html>"""
|
292
|
+
|
293
|
+
return html_content
|
@@ -11,9 +11,17 @@ class UdemyAuth:
|
|
11
11
|
"""Autenticação na plataforma udemy de maneira segura, atencao ao limite de logins,recomendo que apos logar
|
12
12
|
nao use novamnete o metodo login use apenas o verifcador de login para evitar bloqueios temporários..."""
|
13
13
|
self.__cookie_dict = {}
|
14
|
-
|
15
|
-
os.
|
16
|
-
|
14
|
+
# Diretório do arquivo atual
|
15
|
+
current_directory = os.path.dirname(__file__)
|
16
|
+
# dir cache
|
17
|
+
cache = '.cache'
|
18
|
+
cache_dir = os.path.join(current_directory, cache)
|
19
|
+
os.makedirs(cache_dir, exist_ok=True)
|
20
|
+
# Cria o diretório completo para a API do usuário
|
21
|
+
self.__user_dir = os.path.join(cache_dir)
|
22
|
+
# Cria o caminho completo para um arquivo específico
|
23
|
+
file_name = '.udemy_userAPI' # Nome do arquivo
|
24
|
+
self.__file_path = os.path.join(self.__user_dir, file_name)
|
17
25
|
|
18
26
|
def __make_cookies(self, client_id: str, access_token: str, csrf_token: str):
|
19
27
|
self.__cookie_dict = {
|
@@ -29,7 +37,7 @@ class UdemyAuth:
|
|
29
37
|
def verif_config():
|
30
38
|
# Verificar se o arquivo .userLogin existe e carregar cookies se existir
|
31
39
|
try:
|
32
|
-
with open(fr'{self.
|
40
|
+
with open(fr'{self.__file_path}', 'rb') as f:
|
33
41
|
cookies = pickle.load(f)
|
34
42
|
cookies_dict = {cookie.name: cookie.value for cookie in cookies}
|
35
43
|
cookies_str = "; ".join([f"{key}={value}" for key, value in cookies_dict.items()])
|
@@ -144,19 +152,18 @@ class UdemyAuth:
|
|
144
152
|
return s
|
145
153
|
|
146
154
|
def __save_cookies(self, cookies):
|
147
|
-
with open(fr'{self.
|
155
|
+
with open(fr'{self.__file_path}', 'wb') as f:
|
148
156
|
pickle.dump(cookies, f)
|
149
157
|
|
150
158
|
@property
|
151
159
|
def load_cookies(self) -> str:
|
152
160
|
"""carrega cookies e retorna-os em uma string formatada"""
|
153
|
-
file = os.path.join(fr'{self.
|
161
|
+
file = os.path.join(fr'{self.__file_path}')
|
154
162
|
if os.path.exists(file):
|
155
|
-
with open(fr'{self.
|
163
|
+
with open(fr'{self.__file_path}', 'rb') as f:
|
156
164
|
cookies = pickle.load(f)
|
157
165
|
cookies_dict = {cookie.name: cookie.value for cookie in cookies}
|
158
166
|
cookies_str = "; ".join([f"{key}={value}" for key, value in cookies_dict.items()])
|
159
167
|
return cookies_str
|
160
168
|
else:
|
161
|
-
|
162
|
-
|
169
|
+
return 'None'
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import requests
|
2
2
|
import json
|
3
3
|
from .sections import get_course_infor
|
4
|
-
from .api import get_links, remove_tag, parser_chapers, extract_files, HEADERS_USER
|
5
|
-
|
4
|
+
from .api import get_links, remove_tag, parser_chapers, extract_files, HEADERS_USER, assets_infor
|
6
5
|
|
7
6
|
|
8
7
|
class Files:
|
@@ -32,7 +31,8 @@ class Files:
|
|
32
31
|
class Lecture:
|
33
32
|
"""CRIAR objetos aula(lecture) do curso e extrair os dados.."""
|
34
33
|
|
35
|
-
def __init__(self, data: dict):
|
34
|
+
def __init__(self, data: dict, course_id: int):
|
35
|
+
self.__course_id = course_id
|
36
36
|
self.__data = data
|
37
37
|
self.__asset = self.__data.get("asset")
|
38
38
|
|
@@ -105,6 +105,11 @@ class Lecture:
|
|
105
105
|
"""obtem slides se tiver.."""
|
106
106
|
return self.__asset.get('slides')
|
107
107
|
|
108
|
+
@property
|
109
|
+
def get_articles(self):
|
110
|
+
d = assets_infor(course_id=self.__course_id, id_lecture=self.get_lecture_id, assets_id=self.__asset.get("id"))
|
111
|
+
return d
|
112
|
+
|
108
113
|
|
109
114
|
class Course:
|
110
115
|
"""receb um dict com os dados do curso"""
|
@@ -172,21 +177,29 @@ class Course:
|
|
172
177
|
|
173
178
|
@property
|
174
179
|
def get_lectures(self) -> list:
|
175
|
-
"""Obtém uma lista com
|
180
|
+
"""Obtém uma lista com todas as aulas."""
|
176
181
|
videos = []
|
177
182
|
for chapter in self.__data.values():
|
178
|
-
for video in chapter.get('videos_in_chapter', []):
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
+
for index, video in enumerate(chapter.get('videos_in_chapter', [])): # Corrigido o loop
|
184
|
+
section = chapter.get('title_chapter')
|
185
|
+
title = video.get('video_title')
|
186
|
+
id_lecture = video.get('lecture_id')
|
187
|
+
id_asset = video.get('asset_id')
|
188
|
+
section_order = index + 1 # Adiciona 1 para começar a numeração em 1
|
189
|
+
dt = {
|
190
|
+
'section': section,
|
191
|
+
'title': title,
|
192
|
+
'lecture_id': id_lecture,
|
193
|
+
'asset_id': id_asset,
|
194
|
+
'section_order': section_order
|
195
|
+
}
|
183
196
|
videos.append(dt)
|
184
197
|
return videos
|
185
198
|
|
186
199
|
def get_details_lecture(self, lecture_id: int) -> Lecture:
|
187
200
|
"""obter detalhes de uma aula específica, irá retornar o objeto Lecture"""
|
188
201
|
links = get_links(course_id=self.__course_id, id_lecture=lecture_id)
|
189
|
-
lecture = Lecture(data=links)
|
202
|
+
lecture = Lecture(data=links, course_id=self.__course_id)
|
190
203
|
return lecture
|
191
204
|
|
192
205
|
@property
|
@@ -30,10 +30,25 @@ class Udemy:
|
|
30
30
|
|
31
31
|
@property
|
32
32
|
def my_subscribed_courses(self) -> list[dict]:
|
33
|
-
"""
|
33
|
+
"""Obtém os cursos que o usuário está inscrito, excluindo listas vazias ou nulas"""
|
34
34
|
try:
|
35
|
-
|
36
|
-
|
35
|
+
# Obtém os cursos
|
36
|
+
courses1 = get_courses_plan(tipe='default') # lista de cursos padrão
|
37
|
+
courses2 = get_courses_plan(tipe='plan') # lista de cursos de um plano
|
38
|
+
|
39
|
+
# Cria uma lista vazia para armazenar os cursos válidos
|
40
|
+
all_courses = []
|
41
|
+
|
42
|
+
# Adiciona a lista somente se não estiver vazia ou nula
|
43
|
+
if courses1:
|
44
|
+
for i in courses1:
|
45
|
+
all_courses.extend(i)
|
46
|
+
if courses2:
|
47
|
+
for i in courses2:
|
48
|
+
all_courses.extend(i)
|
49
|
+
|
50
|
+
return all_courses
|
51
|
+
|
37
52
|
except UdemyUserApiExceptions as e:
|
38
53
|
UnhandledExceptions(e)
|
39
54
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: udemy_userAPI
|
3
|
-
Version: 0.1.
|
4
|
-
Summary: Obtenha detalhes de cursos que o usuário esteja inscrito da plataforma Udemy,usando o EndPoint de
|
3
|
+
Version: 0.1.6
|
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
|
7
7
|
License: MIT
|
@@ -18,7 +18,7 @@ Requires-Dist: cloudscraper
|
|
18
18
|
# udemy-userAPI
|
19
19
|
|
20
20
|
|
21
|
-

|
21
|
+

|
22
22
|

|
23
23
|
[](https://apoia.se/paulocesar-dev404)
|
24
24
|
[](https://github.com/PauloCesar-dev404/udemy-userAPI/wiki)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|