Skip to content

Commit

Permalink
Merge pull request #6 from gunyu1019/develop
Browse files Browse the repository at this point in the history
[Deploy] Deploy v0.0.4
  • Loading branch information
gunyu1019 authored Mar 5, 2024
2 parents 0c9a797 + a81dec6 commit 5819ea4
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 128 deletions.
4 changes: 2 additions & 2 deletions chzzkpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
__author__ = "gunyu1019"
__license__ = "MIT"
__copyright__ = "Copyright 2024-present gunyu1019"
__version__ = "0.0.3-alpha1" # version_info.to_string()
__version__ = "0.0.4-alpha1" # version_info.to_string()


class VersionInfo(NamedTuple):
Expand All @@ -57,5 +57,5 @@ def to_string(self) -> str:


version_info: VersionInfo = VersionInfo(
major=0, minor=0, micro=3, release_level="alpha", serial=1
major=0, minor=0, micro=4, release_level="alpha", serial=1
)
22 changes: 7 additions & 15 deletions chzzkpy/chat/http.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
from async_client_decorator import get, Query
from ahttp_client import get, Query
from ahttp_client.extension import get_pydantic_response_model
from typing import Annotated

from .access_token import AccessToken
from ..base_model import Content
from ..http import (
ChzzkSession,
NaverGameAPISession,
_response_pydantic_model_validation_able,
_custom_query_name,
_response_pydantic_model_validation,
)
from ..http import ChzzkSession, NaverGameAPISession


class ChzzkChatSession(NaverGameAPISession):
@_response_pydantic_model_validation_able
@ChzzkSession.logging
@_custom_query_name("channel_id", "channelId") # Will moved. (Temporary Decorator)
@ChzzkSession.login_able
@get("/nng_main/v1/chats/access-token")
@get_pydantic_response_model()
@get("/nng_main/v1/chats/access-token", directly_response=True)
@ChzzkSession.configuration(login_able=True)
@Query.default_query("chatType", "STREAMING")
@_response_pydantic_model_validation
async def chat_access_token(
self, channel_id: Annotated[str, Query]
self, channel_id: Annotated[str, Query.to_camel()]
) -> Content[AccessToken]:
pass
4 changes: 2 additions & 2 deletions chzzkpy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ def login(self, authorization_key: str, session_key: str):
self._api_session.login(authorization_key, session_key)
self._game_session.login(authorization_key, session_key)

async def live_status(self, channel_id: str) -> LiveStatus:
async def live_status(self, channel_id: str) -> Optional[LiveStatus]:
res = await self._api_session.live_status(channel_id=channel_id)
return res.content

async def live_detail(self, channel_id: str) -> LiveDetail:
async def live_detail(self, channel_id: str) -> Optional[LiveDetail]:
res = await self._api_session.live_detail(channel_id=channel_id)
return res.content

Expand Down
115 changes: 28 additions & 87 deletions chzzkpy/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@

import asyncio
import functools
import inspect
import logging
from typing import Annotated, Optional

import aiohttp
from async_client_decorator import Session, get, Path
from ahttp_client import Session, get, Path
from ahttp_client.extension import get_pydantic_response_model
from ahttp_client.request import RequestCore

from .base_model import ChzzkModel, Content
from .error import LoginRequired
Expand All @@ -38,50 +38,6 @@
_log = logging.getLogger(__name__)


# This decorator will remove at https://github.com/gunyu1019/async-client-decorator/issues/8
def _response_pydantic_model_validation(func):
signature = inspect.signature(func)
if not issubclass(signature.return_annotation, ChzzkModel):
return func

signature = inspect.signature(func)

@functools.wraps(func)
async def wrapper(self: Session, response: aiohttp.ClientResponse, *_1, **_2):
data = await response.json()
validated_data = signature.return_annotation.model_validate(data)
return validated_data

return wrapper


# This decorator will remove at https://github.com/gunyu1019/async-client-decorator/issues/8
def _response_pydantic_model_validation_able(func):
signature = inspect.signature(func)
if not issubclass(signature.return_annotation, ChzzkModel):
return func

func.__component_parameter__.response.append("response")
return func


# This decorator will remove at https://github.com/gunyu1019/async-client-decorator/issues/9
def _custom_query_name(oldest_name, replace_name):
def decorator(func):
func.__component_parameter__.query[replace_name] = (
func.__component_parameter__.query.pop(oldest_name)
)

@functools.wraps(func)
def wrapper(self, *args, **kwargs):
kwargs[replace_name] = kwargs.pop(oldest_name)
return func(self, *args, **kwargs)

return wrapper

return decorator


class ChzzkSession(Session):
def __init__(self, base_url: str, loop: Optional[asyncio.AbstractEventLoop] = None):
super().__init__(base_url=base_url, loop=loop)
Expand All @@ -98,36 +54,28 @@ def has_login(self) -> bool:
return self._authorization_key is not None and self._session_key is not None

@staticmethod
def login_required(func):
@functools.wraps(func)
async def wrapper(self: "ChzzkSession", *args, **kwargs):
if not self.has_login:
raise LoginRequired()
def configuration(login_able: bool = False, login_required: bool = False):
def decorator(func):
func.__login_able__ = login_able
func.__login_required__ = login_required
return func

return await func(self, *args, **kwargs)
return decorator

return wrapper
async def before_request(
self, request: RequestCore, path: str
) -> tuple[RequestCore, str]:
_log.debug(f"Path({path}) was called.")

@staticmethod
def login_able(func):
@functools.wraps(func)
async def wrapper(self: "ChzzkSession", *args, **kwargs):
# Authorization
if getattr(request.func, "__login_able__", False):
if self.has_login:
if "Cookie" not in func.__component_parameter__.header.keys():
func.__component_parameter__.header["Cookie"] = ""
func.__component_parameter__.header["Cookie"] += self._token
return await func(self, *args, **kwargs)

return wrapper

@staticmethod
def logging(func):
@functools.wraps(func)
def wrapper(self: "ChzzkSession", *args, **kwargs):
_log.debug(f"Path({func.__request_path__}) was called.")
return func(self, *args, **kwargs)

return wrapper
if "Cookie" not in request.headers.keys():
request.headers["Cookie"] = ""
request.headers["Cookie"] += self._token
elif getattr(request.func, "__login_required__", False):
raise LoginRequired()
return request, path

@property
def _token(self) -> str:
Expand All @@ -138,19 +86,15 @@ class ChzzkAPISession(ChzzkSession):
def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None):
super().__init__(base_url="https://api.chzzk.naver.com", loop=loop)

@_response_pydantic_model_validation_able
@ChzzkSession.logging
@get("/polling/v2/channels/{channel_id}/live-status")
@_response_pydantic_model_validation
@get_pydantic_response_model()
@get("/polling/v2/channels/{channel_id}/live-status", directly_response=True)
async def live_status(
self, channel_id: Annotated[str, Path]
) -> Content[LiveStatus]:
pass

@_response_pydantic_model_validation_able
@ChzzkSession.logging
@get("/service/v2/channels/{channel_id}/live-detail")
@_response_pydantic_model_validation
@get_pydantic_response_model()
@get("/service/v2/channels/{channel_id}/live-detail", directly_response=True)
async def live_detail(
self, channel_id: Annotated[str, Path]
) -> Content[LiveDetail]:
Expand All @@ -161,11 +105,8 @@ class NaverGameAPISession(ChzzkSession):
def __init__(self, loop: Optional[asyncio.AbstractEventLoop] = None):
super().__init__(base_url="https://comm-api.game.naver.com", loop=loop)

@_response_pydantic_model_validation_able
@ChzzkSession.logging
@ChzzkSession.login_required
@ChzzkSession.login_able
@get("/nng_main/v1/user/getUserStatus")
@_response_pydantic_model_validation
@get_pydantic_response_model()
@get("/nng_main/v1/user/getUserStatus", directly_response=True)
@ChzzkSession.configuration(login_able=True, login_required=True)
async def user(self) -> Content[User]:
pass
2 changes: 1 addition & 1 deletion chzzkpy/live.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class LiveStatus(ChzzkModel):
adult: bool
chat_channel_id: str
category_type: Optional[str]
live_category: str
live_category: Optional[str]
live_category_value: str
live_polling_status: Json[LivePollingStatus] = Field(alias="livePollingStatusJson")
fault_status: Any # typing: ???
Expand Down
10 changes: 5 additions & 5 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
aiohttp==3.9.1
aiohttp==3.9.3
aiosignal==1.3.1
annotated-types==0.6.0
async-timeout==4.0.3
async_client_decorator==0.2.0
ahttp_client==1.0.0
attrs==23.2.0
charset-normalizer==3.3.2
frozenlist==1.4.1
idna==3.6
multidict==6.0.4
pydantic==2.6.1
pydantic_core==2.16.2
multidict==6.0.5
pydantic==2.6.2
pydantic_core==2.16.3
typing_extensions==4.9.0
yarl==1.9.4
32 changes: 16 additions & 16 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,64 @@
#
# pip-compile --output-file=requirements.txt requirements.in
#
aiohttp==3.9.1
ahttp-client==1.0.1
# via -r requirements.in
aiohttp==3.9.3
# via
# -r requirements.in
# async-client-decorator
# ahttp-client
aiosignal==1.3.1
# via
# -r requirements.in
# ahttp-client
# aiohttp
# async-client-decorator
annotated-types==0.6.0
# via
# -r requirements.in
# pydantic
async-client-decorator==0.2.0
# via -r requirements.in
async-timeout==4.0.3
# via
# -r requirements.in
# async-client-decorator
# ahttp-client
attrs==23.2.0
# via
# -r requirements.in
# ahttp-client
# aiohttp
# async-client-decorator
charset-normalizer==3.3.2
# via
# -r requirements.in
# async-client-decorator
# ahttp-client
frozenlist==1.4.1
# via
# -r requirements.in
# ahttp-client
# aiohttp
# aiosignal
# async-client-decorator
idna==3.6
# via
# -r requirements.in
# async-client-decorator
# ahttp-client
# yarl
multidict==6.0.4
multidict==6.0.5
# via
# -r requirements.in
# ahttp-client
# aiohttp
# async-client-decorator
# yarl
pydantic==2.6.1
pydantic==2.6.3
# via -r requirements.in
pydantic-core==2.16.2
pydantic-core==2.16.3
# via
# -r requirements.in
# pydantic
typing-extensions==4.9.0
typing-extensions==4.10.0
# via
# -r requirements.in
# pydantic
# pydantic-core
yarl==1.9.4
# via
# -r requirements.in
# ahttp-client
# aiohttp
# async-client-decorator

0 comments on commit 5819ea4

Please sign in to comment.