udemy-userAPI 0.3.10__py3-none-any.whl → 0.3.11__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- __version__ = '0.3.10'
1
+ __version__ = '0.3.11'
2
2
  __lib_name__ = 'udemy_userAPI' # local name
3
3
  __repo_name__ = 'udemy-userAPI'
4
4
  __autor__ = 'PauloCesar-dev404'
@@ -208,7 +208,7 @@ class UdemyAuth:
208
208
  with open(self.__file_path, 'wb') as f:
209
209
  f.write(b'')
210
210
 
211
- def login_passwordless(self, email: str, locale: str = 'pt-BR'):
211
+ def login_passwordless(self, email: str, locale: str = 'pt-BR', otp_callback=None):
212
212
  """
213
213
  Realiza login na Udemy usando autenticação de dois fatores (2FA).
214
214
 
@@ -219,6 +219,7 @@ class UdemyAuth:
219
219
  Args:
220
220
  email (str): Email do usuário.
221
221
  locale (str): Localização do usuário (recomendado para receber mensagens no idioma local).
222
+ otp_callback (callable, opcional): Função para obter o código OTP (se None, usa input padrão).
222
223
 
223
224
  Raises:
224
225
  LoginException: Em caso de falha no processo de login.
@@ -227,23 +228,16 @@ class UdemyAuth:
227
228
  try:
228
229
  if self.verif_login():
229
230
  raise UserWarning("Atenção, você já possui uma Sessão válida!")
230
- # Inicializa uma sessão com proteção contra Cloudflare
231
- session = cloudscraper.create_scraper()
232
231
 
233
- # Requisita a página de inscrição para obter o token CSRF
232
+ session = cloudscraper.create_scraper()
234
233
  signup_url = "https://www.udemy.com/join/signup-popup/"
235
234
  headers = {"User-Agent": "okhttp/4.9.2 UdemyAndroid 8.9.2(499) (phone)"}
236
235
  response = session.get(signup_url, headers=headers)
237
-
238
- # Obtém o token CSRF dos cookies retornados
239
236
  csrf_token = response.cookies.get("csrftoken")
240
237
  if not csrf_token:
241
238
  raise LoginException("Não foi possível obter o token CSRF.")
242
239
 
243
- # Prepara os dados do login
244
240
  data = {"email": email, "fullname": ""}
245
-
246
- # Atualiza os cookies e cabeçalhos da sessão
247
241
  session.cookies.update(response.cookies)
248
242
  session.headers.update({
249
243
  "User-Agent": "okhttp/4.9.2 UdemyAndroid 8.9.2(499) (phone)",
@@ -261,17 +255,20 @@ class UdemyAuth:
261
255
  "Cache-Control": "no-cache",
262
256
  })
263
257
 
264
- # Faz a requisição para iniciar o login
265
258
  login_url = "https://www.udemy.com/api-2.0/auth/code-generation/login/4.0/"
266
259
  response = session.post(login_url, data=data, allow_redirects=False)
260
+
267
261
  if 'error_message' in response.text:
268
262
  erro_data: dict = response.json()
269
263
  error_message = erro_data.get('error_message', {})
270
264
  raise LoginException(error_message)
265
+
271
266
  for attempt in range(3):
272
- # Solicita o código OTP ao usuário
273
- otp = input("Digite o código de 6 dígitos enviado ao seu e-mail: ")
274
- # Realiza o login com o código OTP
267
+ # Obtém o código OTP via callback ou terminal
268
+ if otp_callback and callable(otp_callback):
269
+ otp = otp_callback()
270
+ else:
271
+ otp = input("Digite o código de 6 dígitos enviado ao seu e-mail: ")
275
272
  otp_login_url = "https://www.udemy.com/api-2.0/auth/udemy-passwordless/login/4.0/"
276
273
  otp_data = {
277
274
  "email": email,
@@ -280,33 +277,36 @@ class UdemyAuth:
280
277
  "subscribeToEmails": "false",
281
278
  "upow": J(email, 'login')
282
279
  }
280
+
283
281
  session.headers.update({
284
282
  "Referer": f"https://www.udemy.com/join/passwordless-auth/?locale={locale}&next="
285
283
  f"https%3A%2F%2Fwww.udemy.com%2Fmobile%2Fipad%2F&response_type=html"
286
284
  })
285
+
287
286
  response = session.post(otp_login_url, otp_data, allow_redirects=False)
288
- # Verifica se o login foi bem-sucedido
287
+
289
288
  if response.status_code == 200:
290
289
  self._save_cookies(session.cookies)
290
+ break # Sai do loop se o login for bem-sucedido
291
291
  else:
292
292
  if 'error_message' in response.text:
293
293
  erro_data: dict = response.json()
294
294
  error_message = erro_data.get('error_message', {})
295
295
  error_code = erro_data.get('error_code', {})
296
+
296
297
  if error_code == '1538':
297
298
  raise LoginException(error_message)
298
299
  elif error_code == '2550':
299
- print(error_message)
300
- continue
300
+ ### codigo errado....
301
+ raise LoginException(error_message)
301
302
  elif error_code == '1330':
302
303
  raise LoginException(error_message)
303
304
  elif error_code == '1149':
304
- raise LoginException(f"Erro interno ao enviar os dados veja os detalhes: '{error_message}'")
305
+ raise LoginException(
306
+ f"Erro interno ao enviar os dados, veja os detalhes: '{error_message}'")
307
+
305
308
  raise LoginException(response.text)
306
- break
309
+
307
310
  except Exception as e:
308
- if DEBUG:
309
- error_details = traceback.format_exc()
310
- else:
311
- error_details = str(e)
311
+ error_details = traceback.format_exc() if DEBUG else str(e)
312
312
  raise LoginException(error_details)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: udemy_userAPI
3
- Version: 0.3.10
3
+ Version: 0.3.11
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
@@ -29,7 +29,7 @@ Dynamic: summary
29
29
  # udemy-userAPI
30
30
 
31
31
 
32
- ![Versão](https://img.shields.io/badge/version-0.3.8-orange)
32
+ ![Versão](https://img.shields.io/badge/version-0.3.11-orange)
33
33
  ![Licença](https://img.shields.io/badge/license-MIT-orange)
34
34
  [![Sponsor](https://img.shields.io/badge/💲Donate-yellow)](https://paulocesar-dev404.github.io/me-apoiando-online/)
35
35
  [![Sponsor](https://img.shields.io/badge/Documentation-green)](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=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
5
+ udemy_userAPI/bultins.py,sha256=LZlyOjSGte6B6gNn7cjl6L2Q2T_CyXIqqfkOUzt4CV4,21996
6
+ udemy_userAPI/exeptions.py,sha256=kfnPdZpqYY8nd0gnl6_Vh-MIz-XupmmbRPIuFnyXupk,692
7
+ udemy_userAPI/sections.py,sha256=Q1PlVt2Bu5MSEP8g11-F_gilJDdhZq50TV1Bo400jcA,6389
8
+ udemy_userAPI/udemy.py,sha256=SpK0LI4hjO45nZDz5waw-Py-d0uulBb28TVjltyWBxM,2920
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.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,,
@@ -1 +0,0 @@
1
- from .animation import AnimationConsole
@@ -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)
@@ -1,118 +0,0 @@
1
- import sys
2
- import os
3
- import requests
4
- import zipfile
5
- import shutil
6
- import stat
7
- from .exeptions import *
8
- from .__utils import URL_PLATAFOMR, system
9
-
10
- lib_name = os.path.dirname(__file__)
11
- URL_BASE_REPO = "https://raw.githubusercontent.com/PauloCesar-dev404/binarios/main/"
12
-
13
-
14
- class Configurate:
15
- """Configura variáveis de ambiente no ambiente virtual ou globalmente."""
16
-
17
- def __init__(self):
18
- self.VERSION = self.__read_version
19
- self.FFMPEG_URL = os.getenv('FFMPEG_URL')
20
- self.FFMPEG_BINARY = os.getenv('FFMPEG_BINARY')
21
- PATH = os.path.join(lib_name, 'ffmpeg-bin')
22
- os.makedirs(PATH, exist_ok=True)
23
- dirpath = PATH
24
- self.INSTALL_DIR = os.getenv('INSTALL_DIR', dirpath)
25
- self.configure()
26
-
27
- def configure(self):
28
- """Configura as variáveis de ambiente com base no sistema operacional."""
29
- if not self.FFMPEG_URL or not self.FFMPEG_BINARY:
30
- platform_name = system
31
- if platform_name == 'Windows':
32
- self.FFMPEG_URL = URL_PLATAFOMR
33
- self.FFMPEG_BINARY = 'ffmpeg.exe'
34
- elif platform_name == 'Linux':
35
- self.FFMPEG_URL = URL_PLATAFOMR
36
- self.FFMPEG_BINARY = 'ffmpeg'
37
- else:
38
- raise DeprecationWarning(f"Arquitetura '{platform_name}' ainda não suportada...\n\n"
39
- f"Versão atual da lib: {self.VERSION}")
40
- os.environ['FFMPEG_URL'] = self.FFMPEG_URL
41
- os.environ['FFMPEG_BINARY'] = self.FFMPEG_BINARY
42
-
43
- if not os.getenv('INSTALL_DIR'):
44
- os.environ['INSTALL_DIR'] = self.INSTALL_DIR
45
-
46
- @property
47
- def __read_version(self):
48
- """Lê a versão do arquivo __version__.py."""
49
- version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)).split('.')[0], '__version__.py')
50
- if os.path.isfile(version_file):
51
- with open(version_file, 'r') as file:
52
- version_line = file.readline().strip()
53
- if version_line.startswith('__version__'):
54
- return version_line.split('=')[1].strip().strip("'")
55
- return 'Unknown Version'
56
-
57
- def __download_file(self, url: str, local_filename: str):
58
- """Baixa um arquivo do URL para o caminho local especificado."""
59
- try:
60
- response = requests.get(url, stream=True)
61
- response.raise_for_status()
62
- total_length = int(response.headers.get('content-length', 0))
63
-
64
- with open(local_filename, 'wb') as f:
65
- start_time = time.time()
66
- downloaded = 0
67
-
68
- for data in response.iter_content(chunk_size=4096):
69
- downloaded += len(data)
70
- f.write(data)
71
-
72
- elapsed_time = time.time() - start_time
73
- elapsed_time = max(elapsed_time, 0.001)
74
- speed_kbps = (downloaded / 1024) / elapsed_time
75
- percent_done = (downloaded / total_length) * 100
76
-
77
-
78
- except requests.RequestException as e:
79
- raise Exception(f"Erro durante o download: {e}")
80
-
81
- def __extract_zip(self, zip_path: str, extract_to: str):
82
- """Descompacta o arquivo ZIP no diretório especificado."""
83
- try:
84
- with zipfile.ZipFile(zip_path, 'r') as zip_ref:
85
- zip_ref.extractall(extract_to)
86
- except zipfile.BadZipFile as e:
87
- sys.stderr.write(f"Erro ao descompactar o arquivo: {e}\n")
88
- raise
89
- finally:
90
- os.remove(zip_path)
91
-
92
- def remove_file(self, file_path: str):
93
- """Remove o arquivo ou diretório especificado."""
94
- if os.path.exists(file_path):
95
- try:
96
- shutil.rmtree(file_path, onerror=self.handle_remove_readonly)
97
- except Exception as e:
98
- print(f"Erro ao remover {file_path}: {e}")
99
- raise
100
-
101
- def install_bins(self):
102
- """Instala o ffmpeg baixando e descompactando o binário apropriado."""
103
- zip_path = os.path.join(self.INSTALL_DIR, "ffmpeg.zip")
104
- os.makedirs(self.INSTALL_DIR, exist_ok=True)
105
- self.__download_file(self.FFMPEG_URL, zip_path)
106
- self.__extract_zip(zip_path, self.INSTALL_DIR)
107
- self.remove_file(zip_path)
108
- os.environ["PATH"] += os.pathsep + self.INSTALL_DIR
109
- return
110
-
111
- def handle_remove_readonly(self, func, path, exc_info):
112
- """Callback para lidar com arquivos somente leitura."""
113
- os.chmod(path, stat.S_IWRITE)
114
- func(path)
115
-
116
-
117
- if __name__ == "__main__":
118
- FFmpegExceptions("erro de runtime...")
@@ -1,8 +0,0 @@
1
- # ffmpeg-and-python/__init__.py
2
-
3
- from .ffmpeg import FFmpeg
4
- from .exeptions import FFmpegExceptions
5
-
6
- __all__ = ['FFmpeg', 'FFmpegExceptions']
7
- if __name__ == '__main__':
8
- raise RuntimeError("no escope!")
@@ -1,78 +0,0 @@
1
- import platform
2
- import os
3
-
4
- URL_PLATAFOMR = ''
5
-
6
-
7
- def get_processor_info():
8
- system = platform.system()
9
- architecture = platform.architecture()[0]
10
- processor = ''
11
- if system == "Windows":
12
- processor = platform.processor()
13
- elif system in ["Linux", "Darwin"]: # Darwin é o nome do sistema para macOS
14
- try:
15
- if system == "Linux":
16
- # Obtém informações detalhadas do processador no Linux
17
- with open("/proc/cpuinfo") as f:
18
- cpuinfo = f.read()
19
- if "model name" in cpuinfo:
20
- processor = cpuinfo.split("model name")[1].split(":")[1].split("\n")[0].strip()
21
- else:
22
- processor = "Unknown"
23
- elif system == "Darwin":
24
- # Obtém informações detalhadas do processador no macOS
25
- processor = os.popen("sysctl -n machdep.cpu.brand_string").read().strip()
26
- except FileNotFoundError:
27
- processor = "Unknown"
28
- d = (f"System: {system} "
29
- f"Architecture: {architecture} "
30
- f"Processor: {processor} ")
31
- return d
32
-
33
-
34
- # Processa a informação do processador e limpa a string
35
- data = (get_processor_info().replace('Architecture:', '').replace('System:', '').
36
- replace('Processor:', '').strip().split())
37
-
38
- # Remove entradas vazias e limpa espaços em branco
39
- cleaned_data = [item.strip() for item in data if item.strip()]
40
-
41
- # Garantindo que há pelo menos três elementos
42
- if len(cleaned_data) >= 2:
43
- system = cleaned_data[0]
44
- architecture = cleaned_data[1]
45
- processor = ' '.join(cleaned_data[2:]) # Junta o restante como o processador
46
-
47
- URL_BASE_REPO = "https://raw.githubusercontent.com/PauloCesar-dev404/binarios/main/"
48
- # Mapeamento para Linux
49
- linux_mapping = {
50
- "x86_64": "amd64",
51
- "i686": "i686",
52
- "arm64": "arm64",
53
- "armhf": "armhf",
54
- "armel": "armel"
55
- }
56
- # Formata a URL com base no sistema e arquitetura
57
- if system == "Linux" and ('intel' in processor.lower() or 'amd' in processor.lower()):
58
- url = f"{URL_BASE_REPO}linux/ffmpeg-7.0.2-{linux_mapping.get('x86_64')}.zip"
59
- elif system == "Linux" and 'i686' in architecture.lower():
60
- url = f"{URL_BASE_REPO}linux/ffmpeg-7.0.2-{linux_mapping.get('i686')}.zip"
61
- elif system == "Linux" and 'arm64' in architecture.lower():
62
- url = f"{URL_BASE_REPO}linux/ffmpeg-7.0.2-{linux_mapping.get('arm64')}.zip"
63
- elif system == "Linux" and 'armhf' in architecture.lower():
64
- url = f"{URL_BASE_REPO}linux/ffmpeg-7.0.2-{linux_mapping.get('armhf')}.zip"
65
- elif system == "Linux" and 'armel' in architecture.lower():
66
- url = f"{URL_BASE_REPO}linux/ffmpeg-7.0.2-{linux_mapping.get('armel')}.zip"
67
- elif system == "Windows" and architecture == '64bit':
68
- url = f"{URL_BASE_REPO}windows/win-ffmpeg-7.0.2-full-amd64-intel64.zip"
69
- else:
70
- url = f"Unsupported system or architecture"
71
-
72
- URL_PLATAFOMR = url
73
-
74
- else:
75
- raise DeprecationWarning("Não foi possível obter seu sistema ....consulte o desenvolvedor!")
76
-
77
- if __name__ == '__main__':
78
- raise RuntimeError("este é uma função interna!")
@@ -1,6 +0,0 @@
1
- __version__ = '0.3.5'
2
- __lib_name__ = 'ffmpeg_for_python'
3
- __autor__ = 'PauloCesar-dev404'
4
- __repo__ = 'https://github.com/PauloCesar-dev404/ffmpeg-for-python'
5
- __lib__ = f'https://raw.githubusercontent.com/PauloCesar-dev404/ffmpeg-for-python/main/{__lib_name__}-{__version__}-py3-none-any.whl'
6
- __source__ = f'https://raw.githubusercontent.com/PauloCesar-dev404/ffmpeg-for-python/main/{__lib_name__}-{__version__}.tar.gz'
@@ -1,91 +0,0 @@
1
- import time
2
-
3
- INPUT_ERROR = [
4
- 'Error opening input: No such file or directory',
5
- 'Error opening input: Permission denied',
6
- 'Error opening input: Invalid argument',
7
- 'Error opening input: Protocol not found',
8
- 'Error opening input: Unsupported protocol',
9
- 'Error opening input: File format not recognized',
10
- 'Error opening input: Could not open file',
11
- 'Error opening input: Invalid data found when processing input',
12
- 'Error opening input: Input stream is empty',
13
- 'Error opening input: Cannot open file for reading',
14
- 'Error opening input: File is too short',
15
- 'Error opening input: End of file while parsing input',
16
- 'Error opening input: Codec not found',
17
- 'Error opening input: No decoder for codec',
18
- 'Error opening input: Stream not found',
19
- 'Error opening input: Stream codec not found',
20
- 'Error opening input: Stream index out of range',
21
- 'Error opening input: Invalid timestamp',
22
- 'Error opening input: Corrupt file',
23
- 'Error opening input: Unsupported codec',
24
- 'Error opening input: Failed to initialize filter',
25
- 'Error opening input: Error while opening codec',
26
- 'Error opening input: Device not found',
27
- 'Error opening input: Device or resource busy',
28
- 'Error opening input: Invalid option',
29
- 'Error opening input: Unable to seek',
30
- 'Error opening input: Input format not found'
31
- ]
32
- OUTPUT_ERROR = [
33
- 'Error opening output file: No such file or directory',
34
- 'Error opening output file: Permission denied',
35
- 'Error opening output file: Invalid argument',
36
- 'Error opening output file: Unsupported protocol',
37
- 'Error opening output file: Protocol not found',
38
- 'Error opening output file: File format not recognized',
39
- 'Error opening output file: Could not open file for writing',
40
- 'Error opening output file: Disk full or quota exceeded',
41
- 'Error opening output file: Cannot create file',
42
- 'Error opening output file: Invalid data found when processing output',
43
- 'Error opening output file: Output stream not found',
44
- 'Error opening output file: Cannot write to file',
45
- 'Error opening output file: File already exists',
46
- 'Error opening output file: Unsupported codec',
47
- 'Error opening output file: Codec not found',
48
- 'Error opening output file: Cannot open codec for writing',
49
- 'Error opening output file: Failed to initialize filter',
50
- 'Error opening output file: Invalid option',
51
- 'Error opening output file: Invalid timestamp',
52
- 'Error opening output file: Corrupt file',
53
- 'Error opening output file: Device or resource busy',
54
- 'Error opening output file: Cannot seek',
55
- 'Error opening output file: Stream index out of range',
56
- 'Error opening output file: Stream codec not found'
57
- ]
58
- ERROS = []
59
- for er in INPUT_ERROR:
60
- ERROS.append(er)
61
- for er in OUTPUT_ERROR:
62
- ERROS.append(er)
63
-
64
-
65
- class FFmpegExceptions(Exception):
66
- def __init__(self, message: str):
67
- super().__init__(message)
68
-
69
- def __str__(self):
70
- """
71
- Retorna a representação em string da exceção.
72
-
73
- Returns:
74
- str: Mensagem de erro formatada com detalhes adicionais, se presentes.
75
- """
76
-
77
- return super().__str__()
78
-
79
-
80
- def wraper_erros(line: str):
81
- """Verifica se a linha de saida do ffmpeg está no dict de erros e retorna sua categoria"""
82
-
83
- if "Error" in line:
84
- erro = line.split('Error')[1]
85
- return erro.strip()
86
- elif 'already exists. Overwrite? [y/N]' in line:
87
- erro = line.split('File')[1]
88
- return erro.strip()
89
-
90
-
91
-