diff --git a/README.md b/README.md index 1ee1152..26fdb45 100644 --- a/README.md +++ b/README.md @@ -90,12 +90,35 @@ El `CLI` proporciona los siguientes comandos: ### Login -Inicia sesión en Código Facilito abriendo una ventana del navegador. +Puedes iniciar sesión de dos formas: + +#### Email | Facebook | Google ```console facilito login ``` +#### Cookies + +Este método solo se recomienda si tienes problemas de autenticación mediante el método anterior. + +```console +facilito set-cookies path/to/cookies.json +``` + +
+ +Tips & Tricks + +## Exportar las cookies + +1. Instala la extensión de Chrome [***`GetCookies`***][cookies-extension]. +2. Inicia sesión en Código Facilito utilizando el navegador Chrome. +3. Recarga la página. +4. Exporta las cookies en formato `json` desde la extensión de Chrome. + +
+ ### Logout Elimina la sesión almacenada localmente de Código Facilito. @@ -172,3 +195,4 @@ Aquí tienes una lista de algunos de mis otros repositorios. ¡Échales un vista [chocolatey]: https://community.chocolatey.org [ffmpeg-youtube]: https://youtu.be/JR36oH35Fgg?si=Gerco7SP8WlZVaKM [previous-version]: /~https://github.com/ivansaul/codigo_facilito_downloader/tree/e39524cf4a925fb036c903b5d82306f9e2088ca6 +[cookies-extension]: https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc diff --git a/src/facilito/async_api.py b/src/facilito/async_api.py index 0721fb3..1040c4b 100644 --- a/src/facilito/async_api.py +++ b/src/facilito/async_api.py @@ -1,13 +1,17 @@ +from pathlib import Path + from playwright.async_api import BrowserContext, Page, async_playwright from playwright_stealth import Stealth from . import collectors from .constants import BASE_URL, LOGIN_URL, SESSION_FILE from .errors import LoginError +from .helpers import read_json from .logger import logger from .utils import ( load_state, login_required, + normalize_cookies, save_state, try_except_request, ) @@ -121,6 +125,13 @@ async def download(self, url: str, **kwargs): "Please provide a valid URL, either a video, lecture or course." ) + @try_except_request + async def set_cookies(self, path: Path): + cookies = normalize_cookies(read_json(path)) # type: ignore + await self.context.add_cookies(cookies) # type: ignore + await self._set_profile() + await save_state(self.context, SESSION_FILE) + @try_except_request async def _set_profile(self): SELECTOR = "h1.h1.f-text-34" diff --git a/src/facilito/cli.py b/src/facilito/cli.py index c76adea..2509416 100644 --- a/src/facilito/cli.py +++ b/src/facilito/cli.py @@ -1,4 +1,5 @@ import asyncio +from pathlib import Path import typer from typing_extensions import Annotated @@ -19,6 +20,28 @@ def login(): asyncio.run(_login()) +@app.command() +def set_cookies( + path: Annotated[ + Path, + typer.Argument( + exists=True, + file_okay=True, + dir_okay=False, + help="Path to cookies.json", + show_default=False, + ), + ], +): + """ + Login to Codigo Facilito using your cookies. + + Usage: + facilito set-cookies cookies.json + """ + asyncio.run(_set_cookies(path)) + + @app.command() def logout(): """ @@ -108,3 +131,8 @@ async def _logout(): async def _download(url: str, **kwargs): async with AsyncFacilito() as client: await client.download(url, **kwargs) + + +async def _set_cookies(path: Path): + async with AsyncFacilito() as client: + await client.set_cookies(path) diff --git a/src/facilito/utils.py b/src/facilito/utils.py index d113662..6824ae1 100644 --- a/src/facilito/utils.py +++ b/src/facilito/utils.py @@ -182,3 +182,25 @@ def get_unit_type(url: str) -> TypeUnit: return TypeUnit.QUIZ raise UnitError() + + +def normalize_cookies(cookies: list[dict]) -> list[dict]: + """ + Normalize cookies to a common format. + + :param list[dict] cookies: List of cookies to normalize. + :return list[dict]: Normalized list of cookies. + """ + import copy + + same_site_valid_values = {"Lax", "Strict", "None"} + same_site_key = "sameSite" + + cookies = copy.deepcopy(cookies) + for cookie in cookies: + same_site = cookie.get(same_site_key, "None") + same_site = same_site.replace("unspecified", "Lax").capitalize() + same_site = same_site if same_site in same_site_valid_values else "None" + cookie[same_site_key] = same_site + + return cookies