fix: encode query params for GQL request

This commit is contained in:
ducklet 2024-05-18 23:38:33 +02:00
parent 0747ca5658
commit 1789b2ce45
3 changed files with 22 additions and 13 deletions

View file

@ -12,6 +12,7 @@ import bs4
from . import db from . import db
from .models import Movie, Rating, User from .models import Movie, Rating, User
from .request import adownload, asession, asoup_from_url, cache_path from .request import adownload, asession, asoup_from_url, cache_path
from .utils import json_dump
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -355,9 +356,12 @@ async def _load_ratings_page_legacy(url: str, soup: bs4.BeautifulSoup) -> _Ratin
return page return page
async def load_and_store_ratings( async def load_and_store_ratings(user_id: UserId) -> AsyncIterable[tuple[Rating, bool]]:
user_id: UserId, """Load user ratings from imdb.com and store them in our database.
) -> AsyncIterable[tuple[Rating, bool]]:
All loaded ratings are yielded together with the information whether each rating
was already present in our database.
"""
async with db.new_connection() as conn: async with db.new_connection() as conn:
user = await db.get(conn, User, imdb_id=user_id) or User( user = await db.get(conn, User, imdb_id=user_id) or User(
imdb_id=user_id, name="", secret="" imdb_id=user_id, name="", secret=""
@ -385,6 +389,7 @@ async def load_and_store_ratings(
async def load_ratings(user_id: UserId) -> AsyncIterable[Rating]: async def load_ratings(user_id: UserId) -> AsyncIterable[Rating]:
"""Return all ratings for the given user from imdb.com."""
next_url = user_ratings_url(user_id) next_url = user_ratings_url(user_id)
while next_url: while next_url:
@ -443,13 +448,15 @@ async def load_top_250() -> list[MovieId]:
qgl_api_url = "https://caching.graphql.imdb.com/" qgl_api_url = "https://caching.graphql.imdb.com/"
query = { query = {
"operationName": "Top250MoviesPagination", "operationName": "Top250MoviesPagination",
"variables": {"first": 250, "locale": "en-US"}, "variables": json_dump({"first": 250, "locale": "en-US"}),
"extensions": { "extensions": json_dump(
"persistedQuery": { {
"sha256Hash": "26114ee01d97e04f65d6c8c7212ae8b7888fa57ceed105450d1fce09df749b2d", "persistedQuery": {
"version": 1, "sha256Hash": "26114ee01d97e04f65d6c8c7212ae8b7888fa57ceed105450d1fce09df749b2d",
"version": 1,
}
} }
}, ),
} }
headers = { headers = {
"accept": "application/graphql+json, application/json", "accept": "application/graphql+json, application/json",

View file

@ -2,7 +2,6 @@ import json
from dataclasses import dataclass, field from dataclasses import dataclass, field
from dataclasses import fields as _fields from dataclasses import fields as _fields
from datetime import datetime, timezone from datetime import datetime, timezone
from functools import partial
from types import UnionType from types import UnionType
from typing import ( from typing import (
Annotated, Annotated,
@ -26,6 +25,7 @@ from sqlalchemy import Column, ForeignKey, Index, Integer, String, Table
from sqlalchemy.orm import registry from sqlalchemy.orm import registry
from .types import ULID from .types import ULID
from .utils import json_dump
JSONScalar: TypeAlias = int | float | str | None JSONScalar: TypeAlias = int | float | str | None
type JSON = JSONScalar | list["JSON"] | dict[str, "JSON"] type JSON = JSONScalar | list["JSON"] | dict[str, "JSON"]
@ -110,10 +110,8 @@ def optional_fields(o):
yield f yield f
json_dump = partial(json.dumps, separators=(",", ":"))
def _id(x: T) -> T: def _id(x: T) -> T:
"""Return the given argument, aka. the identity function."""
return x return x

View file

@ -1,8 +1,12 @@
import base64 import base64
import hashlib import hashlib
import json
import secrets import secrets
from functools import partial
from typing import Any, TypedDict from typing import Any, TypedDict
json_dump = partial(json.dumps, separators=(",", ":"))
def b64encode(b: bytes) -> str: def b64encode(b: bytes) -> str:
return base64.b64encode(b).decode().rstrip("=") return base64.b64encode(b).decode().rstrip("=")