Skip to content

Commit

Permalink
feat: add cookie-based login
Browse files Browse the repository at this point in the history
- Implement a new `set-cookies` command for CLI login using cookies
- Provide instructions for exporting cookies
- Add a helper function to normalize cookie format
  • Loading branch information
ivansaul committed Nov 24, 2024
1 parent 258e8ea commit 41228fe
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 1 deletion.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

<details>

<summary>Tips & Tricks</summary>

## 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.

</details>

### Logout

Elimina la sesión almacenada localmente de Código Facilito.
Expand Down Expand Up @@ -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
11 changes: 11 additions & 0 deletions src/facilito/async_api.py
Original file line number Diff line number Diff line change
@@ -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,
)
Expand Down Expand Up @@ -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"
Expand Down
28 changes: 28 additions & 0 deletions src/facilito/cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
from pathlib import Path

import typer
from typing_extensions import Annotated
Expand All @@ -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():
"""
Expand Down Expand Up @@ -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)
22 changes: 22 additions & 0 deletions src/facilito/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 41228fe

Please sign in to comment.