udemy-userAPI 0.3.5__py3-none-any.whl → 0.3.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.
- udemy_userAPI/__version__.py +1 -1
- udemy_userAPI/api.py +139 -39
- udemy_userAPI/authenticate.py +1 -1
- udemy_userAPI/bultins.py +243 -56
- udemy_userAPI/sections.py +2 -1
- udemy_userAPI/udemy.py +13 -4
- {udemy_userAPI-0.3.5.dist-info → udemy_userAPI-0.3.7.dist-info}/METADATA +13 -3
- udemy_userAPI-0.3.7.dist-info/RECORD +17 -0
- {udemy_userAPI-0.3.5.dist-info → udemy_userAPI-0.3.7.dist-info}/WHEEL +1 -1
- animation_consoles/__init__.py +0 -1
- animation_consoles/animation.py +0 -64
- ffmpeg_for_python/__config__.py +0 -118
- ffmpeg_for_python/__init__.py +0 -8
- ffmpeg_for_python/__utils.py +0 -78
- ffmpeg_for_python/__version__.py +0 -6
- ffmpeg_for_python/exeptions.py +0 -91
- ffmpeg_for_python/ffmpeg.py +0 -203
- m3u8_analyzer/M3u8Analyzer.py +0 -807
- m3u8_analyzer/__init__.py +0 -7
- m3u8_analyzer/__version__.py +0 -1
- m3u8_analyzer/exeptions.py +0 -82
- udemy_userAPI-0.3.5.dist-info/RECORD +0 -29
- {udemy_userAPI-0.3.5.dist-info → udemy_userAPI-0.3.7.dist-info}/LICENSE +0 -0
- {udemy_userAPI-0.3.5.dist-info → udemy_userAPI-0.3.7.dist-info}/top_level.txt +0 -0
udemy_userAPI/bultins.py
CHANGED
@@ -1,11 +1,8 @@
|
|
1
|
-
import json
|
2
1
|
from typing import Any
|
3
|
-
import
|
4
|
-
from .api import get_links, remove_tag, parser_chapers, extract_files, HEADERS_USER, assets_infor, get_add_files, \
|
5
|
-
get_files_aule, get_external_liks, extract, get_pssh, organize_streams, get_mpd_file, get_highest_resolution
|
6
|
-
from .sections import get_course_infor
|
7
|
-
from .mpd_analyzer import MPDParser
|
2
|
+
from .api import *
|
8
3
|
from .exeptions import LoginException
|
4
|
+
from .mpd_analyzer import MPDParser
|
5
|
+
from .sections import get_course_infor
|
9
6
|
|
10
7
|
|
11
8
|
class DRM:
|
@@ -108,6 +105,171 @@ class Files:
|
|
108
105
|
download_urls.append(dt_file)
|
109
106
|
return download_urls
|
110
107
|
|
108
|
+
class Quiz:
|
109
|
+
"""Representa um quiz.
|
110
|
+
"""
|
111
|
+
|
112
|
+
def __init__(self, quiz_data: dict):
|
113
|
+
"""
|
114
|
+
Inicializa uma instância de Quiz.
|
115
|
+
|
116
|
+
Args:
|
117
|
+
quiz_data (dict): Dados do quiz.
|
118
|
+
"""
|
119
|
+
self._data = quiz_data
|
120
|
+
|
121
|
+
@property
|
122
|
+
def id(self) -> int:
|
123
|
+
"""Retorna o ID do quiz."""
|
124
|
+
return self._data.get('id', 0)
|
125
|
+
|
126
|
+
@property
|
127
|
+
def title(self) -> str:
|
128
|
+
"""Retorna o título do quiz."""
|
129
|
+
return self._data.get('title', '')
|
130
|
+
|
131
|
+
@property
|
132
|
+
def type_quiz(self) -> str:
|
133
|
+
"""Retorna o tipo de quiz (exame ou prática)."""
|
134
|
+
return self._data.get('type', '')
|
135
|
+
|
136
|
+
@property
|
137
|
+
def description(self) -> str:
|
138
|
+
"""Retorna a descrição do quiz."""
|
139
|
+
return remove_tag(self._data.get('description', ''))
|
140
|
+
|
141
|
+
@property
|
142
|
+
def duration(self) -> int:
|
143
|
+
"""Retorna a duração do quiz em minutos, se aplicável."""
|
144
|
+
duration: int = self._data.get('duration', 1)
|
145
|
+
if duration > 1:
|
146
|
+
return int(duration / 60)
|
147
|
+
else:
|
148
|
+
return 0
|
149
|
+
|
150
|
+
@property
|
151
|
+
def pass_percent(self) -> int:
|
152
|
+
"""Retorna a porcentagem necessária para passar."""
|
153
|
+
return self._data.get('pass_percent', 0)
|
154
|
+
|
155
|
+
@property
|
156
|
+
def num_assessments(self) -> int:
|
157
|
+
"""Retorna o número de perguntas do quiz."""
|
158
|
+
return self._data.get('num_assessments', 0)
|
159
|
+
|
160
|
+
def content(self) -> dict:
|
161
|
+
"""Obtém o conteúdo do quiz."""
|
162
|
+
htmls = get_quizzes(lecture_id=self.id)
|
163
|
+
return htmls
|
164
|
+
|
165
|
+
|
166
|
+
class Caption:
|
167
|
+
"""Representa uma legenda."""
|
168
|
+
|
169
|
+
def __init__(self, caption: dict):
|
170
|
+
"""
|
171
|
+
Inicializa uma instância de Caption.
|
172
|
+
|
173
|
+
Args:
|
174
|
+
caption (dict): Dados da legenda.
|
175
|
+
"""
|
176
|
+
self._caption = caption
|
177
|
+
|
178
|
+
@property
|
179
|
+
def locale(self) -> str:
|
180
|
+
"""Retorna o idioma."""
|
181
|
+
return self._caption.get('video_label', '')
|
182
|
+
|
183
|
+
@property
|
184
|
+
def status(self) -> str:
|
185
|
+
"""Retorna o status da legenda 1 ou 0"""
|
186
|
+
return self._caption.get('status')
|
187
|
+
|
188
|
+
@property
|
189
|
+
def title(self) -> str:
|
190
|
+
"""Retorna o título da legenda."""
|
191
|
+
return self._caption.get('title', '')
|
192
|
+
|
193
|
+
@property
|
194
|
+
def created(self) -> str:
|
195
|
+
"""Retorna a data de criação da legenda."""
|
196
|
+
return self._caption.get('created', '')
|
197
|
+
|
198
|
+
@property
|
199
|
+
def id(self) -> int:
|
200
|
+
"""Retorna o ID da legenda."""
|
201
|
+
return self._caption.get('id', 0)
|
202
|
+
|
203
|
+
@property
|
204
|
+
def url(self) -> str:
|
205
|
+
"""Retorna a URL da legenda."""
|
206
|
+
return self._caption.get('url', '')
|
207
|
+
|
208
|
+
@property
|
209
|
+
def content(self) -> str:
|
210
|
+
"""Obtém o conteúdo da legenda."""
|
211
|
+
if self.url:
|
212
|
+
r = requests.get(headers=HEADERS_USER, url=self.url)
|
213
|
+
if r.status_code == 200:
|
214
|
+
return r.text
|
215
|
+
else:
|
216
|
+
raise ConnectionError(
|
217
|
+
f'status_code: {r.status_code}, Não foi possível obter o conteúdo da legenda!'
|
218
|
+
)
|
219
|
+
else:
|
220
|
+
raise FileNotFoundError(
|
221
|
+
'Não foi possível obter a URL da legenda!'
|
222
|
+
)
|
223
|
+
|
224
|
+
class Captions:
|
225
|
+
"""Gerencia as legendas de um vídeo."""
|
226
|
+
|
227
|
+
def __init__(self, caption_data: list):
|
228
|
+
"""
|
229
|
+
Inicializa uma instância de Captions.
|
230
|
+
|
231
|
+
Args:
|
232
|
+
caption_data (list): Dados das legendas.
|
233
|
+
"""
|
234
|
+
self._caption_data = caption_data
|
235
|
+
|
236
|
+
def languages(self) -> list[dict]:
|
237
|
+
"""Retorna a lista de idiomas disponíveis na aula."""
|
238
|
+
langs = []
|
239
|
+
for caption in self._caption_data:
|
240
|
+
locale_id = caption.get('locale_id', '')
|
241
|
+
video_label = caption.get('video_label','')
|
242
|
+
if locale_id:
|
243
|
+
langs.append({'locale_id': locale_id,'locale':video_label})
|
244
|
+
return langs
|
245
|
+
|
246
|
+
def get_lang(self, locale_id: str) -> Caption:
|
247
|
+
"""
|
248
|
+
Obtém a legenda para o idioma especificado.
|
249
|
+
|
250
|
+
|
251
|
+
Args:
|
252
|
+
locale_id (str): ID do idioma,pode ser obtido no método -> 'languages'
|
253
|
+
|
254
|
+
Returns:
|
255
|
+
Caption: Objeto Caption.
|
256
|
+
|
257
|
+
Raises:
|
258
|
+
FileNotFoundError: Se o idioma não estiver disponível na aula.
|
259
|
+
"""
|
260
|
+
is_t = False
|
261
|
+
cpt = {}
|
262
|
+
for caption in self._caption_data:
|
263
|
+
if locale_id == caption.get('locale_id'):
|
264
|
+
is_t = True
|
265
|
+
cpt = caption
|
266
|
+
if not is_t:
|
267
|
+
raise FileNotFoundError(
|
268
|
+
'Esse idioma não está disponível nessa aula!'
|
269
|
+
)
|
270
|
+
c = Caption(caption=cpt)
|
271
|
+
return c
|
272
|
+
|
111
273
|
|
112
274
|
class Lecture:
|
113
275
|
"""Cria objetos aula (lecture) do curso e extrai os dados."""
|
@@ -166,8 +328,8 @@ class Lecture:
|
|
166
328
|
"""
|
167
329
|
thumbnail_sprite = self.__asset.get('thumbnail_sprite', {})
|
168
330
|
return {
|
169
|
-
'thumbnail_vtt_url': thumbnail_sprite.get('vtt_url'),
|
170
|
-
'thumbnail_img_url': thumbnail_sprite.get('img_url')
|
331
|
+
'thumbnail_vtt_url': thumbnail_sprite.get('vtt_url',[]),
|
332
|
+
'thumbnail_img_url': thumbnail_sprite.get('img_url',[])
|
171
333
|
}
|
172
334
|
|
173
335
|
@property
|
@@ -178,7 +340,7 @@ class Lecture:
|
|
178
340
|
Returns:
|
179
341
|
str: O tipo de asset.
|
180
342
|
"""
|
181
|
-
return self.__asset.get('asset_type', '
|
343
|
+
return self.__asset.get('asset_type', '') or self.__data.get('_class','').replace('quiz','Quiz')
|
182
344
|
|
183
345
|
@property
|
184
346
|
def get_media_sources(self) -> list:
|
@@ -188,18 +350,23 @@ class Lecture:
|
|
188
350
|
Returns:
|
189
351
|
list: Uma lista contendo as fontes de mídia.
|
190
352
|
"""
|
191
|
-
return self.__asset.get('media_sources')
|
353
|
+
return self.__asset.get('media_sources',[])
|
192
354
|
|
193
355
|
@property
|
194
|
-
def get_captions(self) ->
|
356
|
+
def get_captions(self) -> Captions:
|
195
357
|
"""
|
196
358
|
Obtém as legendas.
|
197
359
|
|
198
360
|
Returns:
|
199
|
-
|
200
|
-
"""
|
201
|
-
|
202
|
-
|
361
|
+
Captions: Objeto para gerenciar as legendas.
|
362
|
+
"""
|
363
|
+
if self.__asset.get('captions',[]):
|
364
|
+
c = Captions(caption_data=self.__asset.get('captions',[]))
|
365
|
+
return c
|
366
|
+
else:
|
367
|
+
raise FileNotFoundError(
|
368
|
+
'Não foi encontrada legendas nessa aula!'
|
369
|
+
)
|
203
370
|
@property
|
204
371
|
def get_external_url(self) -> list:
|
205
372
|
"""
|
@@ -208,7 +375,7 @@ class Lecture:
|
|
208
375
|
Returns:
|
209
376
|
list: Uma lista contendo os links externos.
|
210
377
|
"""
|
211
|
-
return self.__asset.get('external_url')
|
378
|
+
return self.__asset.get('external_url',[])
|
212
379
|
|
213
380
|
@property
|
214
381
|
def get_media_license_token(self) -> str:
|
@@ -218,7 +385,7 @@ class Lecture:
|
|
218
385
|
Returns:
|
219
386
|
str: O token de acesso à aula.
|
220
387
|
"""
|
221
|
-
return self.__asset.get('media_license_token')
|
388
|
+
return self.__asset.get('media_license_token','')
|
222
389
|
|
223
390
|
def course_is_drmed(self) -> DRM:
|
224
391
|
"""
|
@@ -227,12 +394,19 @@ class Lecture:
|
|
227
394
|
Returns:
|
228
395
|
DRM: O objeto DRM contendo as keys da aula ou None.
|
229
396
|
"""
|
230
|
-
|
231
|
-
d = DRM(license_token=self.get_media_license_token,
|
397
|
+
d = DRM(license_token=self.get_media_license_token,
|
232
398
|
get_media_sources=self.get_media_sources)
|
233
|
-
|
234
|
-
|
235
|
-
|
399
|
+
return d
|
400
|
+
|
401
|
+
def quiz_object(self) ->Quiz:
|
402
|
+
"""se for um quiz ele retorna um objeto Quiz"""
|
403
|
+
if self.get_asset_type.lower() == 'quiz':
|
404
|
+
q =Quiz(get_assessments(lecture_id=self.get_lecture_id,course_id=self.__course_id))
|
405
|
+
return q
|
406
|
+
else:
|
407
|
+
raise UserWarning(
|
408
|
+
'Atenção essa aula não é um Quiz!'
|
409
|
+
)
|
236
410
|
|
237
411
|
@property
|
238
412
|
def get_download_urls(self) -> list:
|
@@ -242,7 +416,7 @@ class Lecture:
|
|
242
416
|
Returns:
|
243
417
|
list: Uma lista contendo as URLs de download.
|
244
418
|
"""
|
245
|
-
return self.__asset.get('download_urls')
|
419
|
+
return self.__asset.get('download_urls',[])
|
246
420
|
|
247
421
|
@property
|
248
422
|
def get_slide_urls(self) -> list:
|
@@ -252,7 +426,7 @@ class Lecture:
|
|
252
426
|
Returns:
|
253
427
|
list: Uma lista contendo as URLs de slides.
|
254
428
|
"""
|
255
|
-
return self.__asset.get('slide_urls')
|
429
|
+
return self.__asset.get('slide_urls',[])
|
256
430
|
|
257
431
|
@property
|
258
432
|
def get_slides(self) -> list:
|
@@ -262,7 +436,7 @@ class Lecture:
|
|
262
436
|
Returns:
|
263
437
|
list: Uma lista contendo os slides.
|
264
438
|
"""
|
265
|
-
return self.__asset.get('slides')
|
439
|
+
return self.__asset.get('slides',[])
|
266
440
|
|
267
441
|
@property
|
268
442
|
def get_articles(self):
|
@@ -272,8 +446,11 @@ class Lecture:
|
|
272
446
|
Returns:
|
273
447
|
Os artigos relacionados à aula.
|
274
448
|
"""
|
275
|
-
|
276
|
-
|
449
|
+
if self.__asset:
|
450
|
+
d = assets_infor(course_id=self.__course_id, id_lecture=self.get_lecture_id, assets_id=self.__asset.get("id"))
|
451
|
+
return d
|
452
|
+
else:
|
453
|
+
return []
|
277
454
|
|
278
455
|
@property
|
279
456
|
def get_resources(self):
|
@@ -283,10 +460,12 @@ class Lecture:
|
|
283
460
|
Returns:
|
284
461
|
Os recursos adicionais relacionados à aula.
|
285
462
|
"""
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
463
|
+
if self.__additional_files:
|
464
|
+
files_add = get_files_aule(lecture_id_filter=self.get_lecture_id, data=self.__additional_files)
|
465
|
+
f = Files(files=files_add, id_course=self.__course_id).get_download_url
|
466
|
+
return f
|
467
|
+
else:
|
468
|
+
return []
|
290
469
|
|
291
470
|
class Course:
|
292
471
|
"""Recebe um dicionário com os dados do curso."""
|
@@ -299,8 +478,8 @@ class Course:
|
|
299
478
|
results (dict): Um dicionário contendo os dados do curso.
|
300
479
|
course_id (int): O ID do curso.
|
301
480
|
"""
|
302
|
-
self.__parser_chapers =
|
303
|
-
self.__data = self.__parser_chapers
|
481
|
+
self.__parser_chapers = parser_chapters(results=results)
|
482
|
+
self.__data:list = self.__parser_chapers
|
304
483
|
self.__course_id = course_id
|
305
484
|
self.__results = results
|
306
485
|
self.__additional_files_data = get_add_files(course_id)
|
@@ -375,8 +554,8 @@ class Course:
|
|
375
554
|
int: O número total de lectures no curso.
|
376
555
|
"""
|
377
556
|
total_lectures = 0
|
378
|
-
for chapter in self.__data
|
379
|
-
total_lectures += len(chapter.get('
|
557
|
+
for chapter in self.__data:
|
558
|
+
total_lectures += len(chapter.get('lectures', []))
|
380
559
|
return total_lectures
|
381
560
|
|
382
561
|
@property
|
@@ -398,39 +577,35 @@ class Course:
|
|
398
577
|
list: Uma lista contendo os títulos de vídeos no curso.
|
399
578
|
"""
|
400
579
|
videos = []
|
401
|
-
for chapter in self.__data
|
580
|
+
for chapter in self.__data:
|
402
581
|
for video in chapter.get('videos_in_chapter', []):
|
403
|
-
|
404
|
-
if
|
405
|
-
|
582
|
+
asset_type = video.get('asset_type')
|
583
|
+
if asset_type == 'Video':
|
584
|
+
title = video['title']
|
585
|
+
if title != "Files":
|
586
|
+
videos.append(title)
|
406
587
|
return videos
|
407
588
|
|
408
589
|
@property
|
409
590
|
def get_lectures(self) -> list:
|
410
591
|
"""
|
411
|
-
Obtém uma lista com todas as aulas.
|
412
|
-
|
592
|
+
Obtém uma lista de dicionários com todas as aulas.
|
413
593
|
Returns:
|
414
594
|
list: Uma lista contendo todas as aulas.
|
415
595
|
"""
|
416
596
|
videos = []
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
for index, video in enumerate(chapter.get('videos_in_chapter', [])):
|
421
|
-
section = f"{chapter.get('title_chapter')}" # Adicionar numeração da Sessão
|
422
|
-
title = video.get('video_title')
|
423
|
-
id_lecture = video.get('lecture_id')
|
424
|
-
id_asset = video.get('asset_id')
|
597
|
+
|
598
|
+
for chapter in self.__data:
|
599
|
+
for video in chapter.get('lectures', []):
|
425
600
|
dt = {
|
426
|
-
'section':
|
427
|
-
'title': title,
|
428
|
-
'lecture_id':
|
429
|
-
'asset_id':
|
430
|
-
'
|
601
|
+
'section': chapter.get('title', ''),
|
602
|
+
'title': video.get('title', ''),
|
603
|
+
'lecture_id': video.get('lecture_id', ''),
|
604
|
+
'asset_id': video.get('asset_id', ''),
|
605
|
+
'asset_type': video.get('asset_type', '')
|
431
606
|
}
|
432
607
|
videos.append(dt)
|
433
|
-
|
608
|
+
|
434
609
|
return videos
|
435
610
|
|
436
611
|
def get_details_lecture(self, lecture_id: int) -> Lecture:
|
@@ -443,7 +618,19 @@ class Course:
|
|
443
618
|
Returns:
|
444
619
|
Lecture: Um objeto Lecture contendo os detalhes da aula.
|
445
620
|
"""
|
446
|
-
|
621
|
+
type_lecture = ''
|
622
|
+
links= {}
|
623
|
+
if not is_lecture_in_course(lecture_id=lecture_id,lectures=self.get_lectures):
|
624
|
+
raise FileNotFoundError(
|
625
|
+
'Essa aula não existe nesse curso!'
|
626
|
+
)
|
627
|
+
for l in self.get_lectures:
|
628
|
+
if lecture_id == l.get('lecture_id'):
|
629
|
+
type_lecture = l.get('asset_type')
|
630
|
+
if type_lecture.lower() == 'video' or type_lecture.lower() == 'article':
|
631
|
+
links = get_links(course_id=self.__course_id, id_lecture=lecture_id)
|
632
|
+
else:
|
633
|
+
links = get_assessments(course_id=self.__course_id,lecture_id=lecture_id)
|
447
634
|
additional_files = self.__load_assets()
|
448
635
|
lecture = Lecture(data=links, course_id=self.__course_id, additional_files=additional_files)
|
449
636
|
return lecture
|
udemy_userAPI/sections.py
CHANGED
@@ -84,7 +84,8 @@ def get_details_courses(course_id):
|
|
84
84
|
resposta = json.loads(response.text)
|
85
85
|
return resposta
|
86
86
|
else:
|
87
|
-
raise UdemyUserApiExceptions(
|
87
|
+
raise UdemyUserApiExceptions(
|
88
|
+
response.text)
|
88
89
|
|
89
90
|
|
90
91
|
def get_course_infor(course_id):
|
udemy_userAPI/udemy.py
CHANGED
@@ -19,9 +19,6 @@ class Udemy:
|
|
19
19
|
LoginException: Se a sessão estiver expirada.
|
20
20
|
"""
|
21
21
|
self.__headers = HEADERS_USER
|
22
|
-
if not verif_login:
|
23
|
-
raise LoginException("Sessão expirada!")
|
24
|
-
|
25
22
|
@staticmethod
|
26
23
|
def my_subscribed_courses_by_plan() -> list[dict]:
|
27
24
|
"""
|
@@ -33,6 +30,10 @@ class Udemy:
|
|
33
30
|
Raises:
|
34
31
|
UdemyUserApiExceptions: Se houver erro ao obter os cursos.
|
35
32
|
"""
|
33
|
+
if not verif_login:
|
34
|
+
raise LoginException(
|
35
|
+
"Nenhuma sessão ativa,primeiro efetue login!")
|
36
|
+
|
36
37
|
try:
|
37
38
|
courses = get_courses_plan(tipe='plan')
|
38
39
|
return courses
|
@@ -50,6 +51,10 @@ class Udemy:
|
|
50
51
|
Raises:
|
51
52
|
UdemyUserApiExceptions: Se houver erro ao obter os cursos.
|
52
53
|
"""
|
54
|
+
if not verif_login:
|
55
|
+
raise LoginException(
|
56
|
+
"Nenhuma sessão ativa,primeiro efetue login!")
|
57
|
+
|
53
58
|
try:
|
54
59
|
# Obtém os cursos
|
55
60
|
courses1 = get_courses_plan(tipe='default') # lista de cursos padrão
|
@@ -72,7 +77,7 @@ class Udemy:
|
|
72
77
|
raise UnhandledExceptions(e)
|
73
78
|
|
74
79
|
@staticmethod
|
75
|
-
def get_details_course(course_id):
|
80
|
+
def get_details_course(course_id) ->Course:
|
76
81
|
"""
|
77
82
|
Obtém detalhes de um curso através do ID.
|
78
83
|
|
@@ -85,6 +90,10 @@ class Udemy:
|
|
85
90
|
Raises:
|
86
91
|
UnhandledExceptions: Se houver erro ao obter os detalhes do curso.
|
87
92
|
"""
|
93
|
+
if not verif_login:
|
94
|
+
raise LoginException(
|
95
|
+
"Nenhuma sessão ativa,primeiro efetue login!")
|
96
|
+
|
88
97
|
try:
|
89
98
|
d = get_details_courses(course_id)
|
90
99
|
b = Course(course_id=course_id, results=d)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: udemy_userAPI
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.7
|
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
|
@@ -15,11 +15,21 @@ License-File: LICENSE
|
|
15
15
|
Requires-Dist: requests
|
16
16
|
Requires-Dist: cloudscraper
|
17
17
|
Requires-Dist: pywidevine
|
18
|
+
Dynamic: author
|
19
|
+
Dynamic: author-email
|
20
|
+
Dynamic: description
|
21
|
+
Dynamic: description-content-type
|
22
|
+
Dynamic: keywords
|
23
|
+
Dynamic: license
|
24
|
+
Dynamic: platform
|
25
|
+
Dynamic: project-url
|
26
|
+
Dynamic: requires-dist
|
27
|
+
Dynamic: summary
|
18
28
|
|
19
29
|
# udemy-userAPI
|
20
30
|
|
21
31
|
|
22
|
-

|
23
33
|

|
24
34
|
[](https://paulocesar-dev404.github.io/me-apoiando-online/)
|
25
35
|
[](https://github.com/PauloCesar-dev404/udemy-userAPI/blob/main/docs/iniciando.md)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
udemy_userAPI/__init__.py,sha256=BPle89xE_CMTKKe_Lw6jioYLgpH-q_Lpho2S-n1PIUA,206
|
2
|
+
udemy_userAPI/__version__.py,sha256=ZlJ4BqU7L0jruy2h0iTeuMxcPub8qGB7jbO8vbwvXbY,405
|
3
|
+
udemy_userAPI/api.py,sha256=jWWwJBYS9dJDjlozUj4Yi4uc8OCAy5PILqUiRWZMiq8,28153
|
4
|
+
udemy_userAPI/authenticate.py,sha256=IJRrCjmhe_x40CrQ2KrOMNP8VvotZf0QMWsrbcLl_rw,14225
|
5
|
+
udemy_userAPI/bultins.py,sha256=s12tXjbZgyKAnYrEtZxUzuTY-aIINXlm4mpbxR-r4Io,21932
|
6
|
+
udemy_userAPI/exeptions.py,sha256=kfnPdZpqYY8nd0gnl6_Vh-MIz-XupmmbRPIuFnyXupk,692
|
7
|
+
udemy_userAPI/sections.py,sha256=eRjUUlEApwrwlcCs9GWIk580qq1UVFqR5RmOgP6y65E,5424
|
8
|
+
udemy_userAPI/udemy.py,sha256=AAXc24iAtFTyDyVehhFeSx9CyhWMeFWsbYn1J80TgFw,3270
|
9
|
+
udemy_userAPI/.cache/.udemy_userAPI,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
udemy_userAPI/mpd_analyzer/__init__.py,sha256=i3JVWyvcFLaj5kPmx8c1PgjsLht7OUIQQClD4yqYbo8,102
|
11
|
+
udemy_userAPI/mpd_analyzer/bin.wvd,sha256=1rAJdCc120hQlX9qe5KUS628eY2ZHYxQSmyhGNefSzo,2956
|
12
|
+
udemy_userAPI/mpd_analyzer/mpd_parser.py,sha256=PgUkHc5x8FTuXFCuYkWPZr9TaO_nsKalb02EFYl_zeA,8926
|
13
|
+
udemy_userAPI-0.3.7.dist-info/LICENSE,sha256=l4jdKYt8gSdDFOGr09vCKnMn_Im55XIcQKqTDEtFfNs,1095
|
14
|
+
udemy_userAPI-0.3.7.dist-info/METADATA,sha256=B5tTj-p8_9DEWwgarUotK9gTteg6teb_R5oeLg7HznQ,1655
|
15
|
+
udemy_userAPI-0.3.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
16
|
+
udemy_userAPI-0.3.7.dist-info/top_level.txt,sha256=ijTINaSDRKhdahY_X7dmSRFTxBIwQErWv9ATCG55mog,14
|
17
|
+
udemy_userAPI-0.3.7.dist-info/RECORD,,
|
animation_consoles/__init__.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
from .animation import AnimationConsole
|
animation_consoles/animation.py
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
import sys
|
2
|
-
import time
|
3
|
-
import threading
|
4
|
-
from colorama import init, Fore, Style
|
5
|
-
|
6
|
-
# Inicializa o suporte a cores no Windows
|
7
|
-
init(autoreset=True)
|
8
|
-
|
9
|
-
|
10
|
-
class AnimationConsole:
|
11
|
-
def __init__(self, text="Loading", color=Fore.GREEN, color_frame=Fore.BLUE):
|
12
|
-
"""
|
13
|
-
Cria uma animação de loading com uma mensagem colorida no console.
|
14
|
-
:param text: Texto inicial da mensagem de loading.
|
15
|
-
:param color: Cor do texto, usando Fore do colorama.
|
16
|
-
"""
|
17
|
-
self._color_frame = color_frame
|
18
|
-
self._text = text
|
19
|
-
self._color = color
|
20
|
-
self._running = False
|
21
|
-
self._animation_thread = None
|
22
|
-
self._frames = ["-", "\\", "|", "/"]
|
23
|
-
self._index = 0
|
24
|
-
|
25
|
-
def start(self):
|
26
|
-
"""
|
27
|
-
Inicia a animação no console.
|
28
|
-
"""
|
29
|
-
if self._running:
|
30
|
-
return # Previne múltiplas execuções
|
31
|
-
self._running = True
|
32
|
-
self._animation_thread = threading.Thread(target=self._animate, daemon=True)
|
33
|
-
self._animation_thread.start()
|
34
|
-
|
35
|
-
def stop(self):
|
36
|
-
"""
|
37
|
-
Para a animação no console.
|
38
|
-
"""
|
39
|
-
self._running = False
|
40
|
-
if self._animation_thread:
|
41
|
-
self._animation_thread.join()
|
42
|
-
sys.stdout.write("\r" + " " * (len(self._text) + 20) + "\r") # Limpa a linha
|
43
|
-
|
44
|
-
def update_message(self, new_text, new_color=None):
|
45
|
-
"""
|
46
|
-
Atualiza a mensagem exibida junto à animação.
|
47
|
-
:param new_text: Novo texto a ser exibido.
|
48
|
-
:param new_color: Nova cor para o texto (opcional).
|
49
|
-
"""
|
50
|
-
self._text = new_text
|
51
|
-
if new_color:
|
52
|
-
self._color = new_color
|
53
|
-
|
54
|
-
def _animate(self):
|
55
|
-
"""
|
56
|
-
Animação interna do console.
|
57
|
-
"""
|
58
|
-
while self._running:
|
59
|
-
frame = self._frames[self._index]
|
60
|
-
self._index = (self._index + 1) % len(self._frames)
|
61
|
-
sys.stdout.write(
|
62
|
-
f"\r{self._color}{self._text}{Style.RESET_ALL} {self._color_frame}{frame}{Style.RESET_ALL}")
|
63
|
-
sys.stdout.flush()
|
64
|
-
time.sleep(0.1)
|