Skip to content

Commit

Permalink
Merge pull request #13 from issamansur/dev
Browse files Browse the repository at this point in the history
UPDATE TO 3.3.0
  • Loading branch information
issamansur authored Jan 21, 2024
2 parents adf489d + 55dc03a commit cebbb8e
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 42 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![Лицензия](https://img.shields.io/badge/Лицензия-MIT-blue)
![Совместимость с Python](https://img.shields.io/badge/Python-3.7--3.9-blue)
![Версия библиотеки](https://img.shields.io/badge/pip-3.2.2-blue)
![Версия библиотеки](https://img.shields.io/badge/pip-3.3.0-blue)

# VKpyMusic
### is a Python library that provides a simple interface for interacting with the VKontakte (VK) music service API. The library allows developers to easily perform operations related to music and other functionalities available through the VK API.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "vkpymusic"
version = "3.2.2"
version = "3.3.0"
homepage = "https://github.com/issamansur/vkpymusic"
repository = "https://github.com/issamansur/vkpymusic"
description = "Python library for VK Audio (API)"
Expand Down
3 changes: 3 additions & 0 deletions vkpymusic/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
Classes:
Song: A class that represents a song.
Playlist: A class that represents a playlist.
UserInfo: A class that represents a main user's info.
"""

from .song import Song
from .playlist import Playlist
from .userinfo import UserInfo

__all__ = [
"Song",
"Playlist",
"UserInfo",
]
2 changes: 1 addition & 1 deletion vkpymusic/models/song.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(
track_id: str,
owner_id: str,
url: str = "",
):
) -> None:
"""
Initializes a Song object.
Expand Down
69 changes: 69 additions & 0 deletions vkpymusic/models/userinfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""
This module contains the UserInfo class.
"""


class UserInfo:
"""
A class that represents a user.
Attributes:
userid (int): The ID of the user.
first_name (str): The first name of the user.
last_name (str): The last name of the user.
photo (str): The URL of the user's photo.
phone (str): The phone number of the user.
"""

userid: int
first_name: str
last_name: str
photo: str
phone: str

def __init__(
self,
userid: int,
first_name: str,
last_name: str,
photo: str = "",
phone: str = "",
) -> None:
"""
Initializes a UserInfo object.
Args:
userid (int): The ID of the user.
first_name (str): The first name of the user.
last_name (str): The last name of the user.
photo (str): The URL of the user's photo.
phone (str): The phone number of the user.
"""
self.userid = userid
self.first_name = first_name
self.last_name = last_name
self.photo = photo
self.phone = phone

def __str__(self):
return f"{self.userid} {self.first_name} {self.last_name}"

def to_dict(self) -> dict:
"""
Converts the user to a dictionary.
"""
return self.__dict__

@classmethod
def from_json(cls, item) -> "UserInfo":
"""
Converts a JSON object to a UserInfo object.
"""
userid = int(item["id"])
first_name = str(item["first_name"])
last_name = str(item["last_name"])
if "photo_200" in item:
photo = str(item["photo_200"])
if "phone" in item:
phone = str(item["phone"])
return cls(userid, first_name, last_name, photo, phone)
22 changes: 11 additions & 11 deletions vkpymusic/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import requests
from requests import Response, Session

from .models import Song, Playlist
from .models import Song, Playlist, UserInfo
from .utils import Converter, get_logger


Expand Down Expand Up @@ -97,7 +97,7 @@ def __get_profile_info(token: str) -> Response:
("v", "5.131"),
]
with Session() as session:
response = session.post(url=url, data=parameters)
response: Response = session.post(url=url, data=parameters)
return response

@staticmethod
Expand All @@ -118,6 +118,9 @@ def check_token(token: str) -> bool:
if "error" in data:
logger.error("Token is invalid!")
return False
if "id" in data["response"]:
logger.info("Token is valid!")
return True
except Exception as e:
logger.error(e)
return False
Expand All @@ -133,25 +136,22 @@ def is_token_valid(self) -> bool:
"""
return Service.check_token(self.__token)

def get_user_info(self) -> (int, str):
def get_user_info(self) -> UserInfo:
"""
Get user info by token.
Returns:
(int, str): Tuple of user id and first + last name.
UserInfo: Instance of 'UserInfo'.
"""
logger.info("Getting user info...")
try:
response = Service.__get_profile_info(self.__token)
data = json.loads(response.content.decode("utf-8"))
user_id = int(data["response"]["id"])
first_name = data["response"]["first_name"]
last_name = data["response"]["last_name"]
response: Response = Service.__get_profile_info(self.__token)
userInfo: UserInfo = Converter.response_to_userinfo(response)
except Exception as e:
logger.error(e)
return
logger.info(f"User info: {user_id}, {first_name}, {last_name}")
return user_id, first_name + " " + last_name
logger.info(f"User info: {userInfo}")
return userInfo

#######################################
# PRIVATE METHODS FOR CREATING REQUESTS
Expand Down
25 changes: 12 additions & 13 deletions vkpymusic/service_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import aiofiles
from httpx import AsyncClient, Response

from .models import Song, Playlist
from .models import Song, Playlist, UserInfo
from .utils import Converter, get_logger


Expand Down Expand Up @@ -110,9 +110,12 @@ async def check_token(token: str) -> bool:
try:
response = await ServiceAsync.__get_profile_info(token)
data = json.loads(response.content.decode("utf-8"))
if "error" in data:
if "error" in data or "id" not in data:
logger.error("Token is invalid!")
return False
if "id" in data["response"]:
logger.info("Token is valid!")
return True
except Exception as e:
logger.error(e)
return False
Expand All @@ -129,26 +132,22 @@ async def is_token_valid(self) -> bool:
logger.info("Checking token...")
return await ServiceAsync.check_token(self.__token)

async def get_user_info(self) -> (int, str):
async def get_user_info(self) -> UserInfo:
"""
Get user id and username.
Get user info by token.
Returns:
tuple[int, str]: Tuple of user id and username.
UserInfo: Instance of 'UserInfo'.
"""
logger.info("Getting user info...")
try:
response = await ServiceAsync.__get_profile_info(self.__token)
data = json.loads(response.content.decode("utf-8"))
user_id = int(data["response"]["id"])
first_name = data["response"]["first_name"]
last_name = data["response"]["last_name"]
response: Response = await ServiceAsync.__get_profile_info(self.__token)
userInfo = Converter.response_to_userinfo(response)
except Exception as e:
logger.error(e)
return
logger.info(f"User info: {user_id}, {first_name}, {last_name}")
return user_id, first_name + " " + last_name

logger.info(f"User info: {userInfo}")
return userInfo

#######################################
# PRIVATE METHODS FOR CREATING REQUESTS
Expand Down
33 changes: 26 additions & 7 deletions vkpymusic/token_receiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,19 @@ def __init__(self, login: str, password: str, client: str = "Kate") -> None:
self.client = clients["Kate"]
self.__token = None

def __request_auth(
def request_auth(
self, code: Optional[str] = None, captcha: Optional[Tuple[int, str]] = None
) -> Response:
"""
Request auth from VK.
Args:
code (Optional[str]): Code from VK/SMS (default value = None).
captcha (Optional[Tuple[int, str]]): Captcha (default value = None).
Returns:
Response: Response from VK.
"""
query_params = [
("grant_type", "password"),
("client_id", self.client.client_id),
Expand All @@ -130,7 +140,16 @@ def __request_auth(
response = session.post("https://oauth.vk.com/token", data=query_params)
return response

def __request_code(self, sid: Union[str, int]):
def request_code(self, sid: Union[str, int]):
"""
Request code from VK.
Args:
sid (Union[str, int]): Sid from VK.
Returns:
Response: Response from VK.
"""
query_params = [("sid", str(sid)), ("v", "5.131")]
with Session() as session:
session.headers.update({"User-Agent": self.client.user_agent})
Expand Down Expand Up @@ -172,7 +191,7 @@ def auth(
Returns:
bool: Boolean value indicating whether authorization was successful or not.
"""
response_auth: requests.Response = self.__request_auth()
response_auth: requests.Response = self.request_auth()
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
while "error" in response_auth_json:
error = response_auth_json["error"]
Expand All @@ -181,20 +200,20 @@ def auth(
captcha_sid: str = response_auth_json["captcha_sid"]
captcha_img: str = response_auth_json["captcha_img"]
captcha_key: str = on_captcha(captcha_img)
response_auth = self.__request_auth(captcha=(captcha_sid, captcha_key))
response_auth = self.request_auth(captcha=(captcha_sid, captcha_key))
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
elif error == "need_validation":
sid = response_auth_json["validation_sid"]
# response2: requests.Response =
self.__request_code(sid)
self.request_code(sid)
# response2_json = json.loads(response2.content.decode('utf-8'))
code: str = on_2fa()
response_auth = self.__request_auth(code=code)
response_auth = self.request_auth(code=code)
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
elif error == "invalid_request":
logger.warn("Invalid code. Try again!")
code: str = on_2fa()
response_auth = self.__request_auth(code=code)
response_auth = self.request_auth(code=code)
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
elif error == "invalid_client":
del self.__login
Expand Down
33 changes: 26 additions & 7 deletions vkpymusic/token_receiver_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,19 @@ def __init__(self, login, password, client="Kate"):
self.client = clients["Kate"]
self.__token = None

async def __request_auth(
async def request_auth(
self, code: str = None, captcha: Tuple[int, str] = None
) -> Response:
"""
Request auth from VK.
Args:
code (Optional[str]): Code from VK/SMS (default value = None).
captcha (Optional[Tuple[int, str]]): Captcha (default value = None).
Returns:
Response: Response from VK.
"""
query_params = [
("grant_type", "password"),
("client_id", self.client.client_id),
Expand All @@ -76,7 +86,16 @@ async def __request_auth(
)
return response

async def __request_code(self, sid: Union[str, int]):
async def request_code(self, sid: Union[str, int]):
"""
Request code from VK.
Args:
sid (Union[str, int]): Sid from VK.
Returns:
Response: Response from VK.
"""
query_params = [("sid", str(sid)), ("v", "5.131")]
async with AsyncClient() as session:
session.headers.update({"User-Agent": self.client.user_agent})
Expand Down Expand Up @@ -118,30 +137,30 @@ async def auth(
Returns:
bool: Boolean value indicating whether authorization was successful or not.
"""
response_auth = await self.__request_auth()
response_auth = await self.request_auth()
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
while "error" in response_auth_json:
error = response_auth_json["error"]
if error == "need_captcha":
captcha_sid: str = response_auth_json["captcha_sid"]
captcha_img: str = response_auth_json["captcha_img"]
captcha_key: str = await on_captcha(captcha_img)
response_auth = await self.__request_auth(
response_auth = await self.request_auth(
captcha=(captcha_sid, captcha_key)
)
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
elif error == "need_validation":
sid = response_auth_json["validation_sid"]
# response2: requests.Response =
await self.__request_code(sid)
await self.request_code(sid)
# response2_json = json.loads(response2.content.decode('utf-8'))
code: str = await on_2fa()
response_auth = await self.__request_auth(code=code)
response_auth = await self.request_auth(code=code)
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
elif error == "invalid_request":
logger.warn("Invalid code. Try again!")
code: str = await on_2fa()
response_auth = await self.__request_auth(code=code)
response_auth = await self.request_auth(code=code)
response_auth_json = json.loads(response_auth.content.decode("utf-8"))
elif error == "invalid_client":
del self.__login
Expand Down
Loading

0 comments on commit cebbb8e

Please sign in to comment.